Hello everyone, from today, will bring several issues about Android source code analysis of the article, thank you for reading, you can also pay attention to the public number, welcome to add groups together and big guy exchange learning.

In this section we’ll start with requestFocus:
In the development process, we need a control View to focus, usually will actively call the control’s requestFocus method. (This article is analyzed based on API 27 source code)
< view.java > public final Boolean requestFocus() {return requestFocus(view.focus_down); }Copy the code
RequestFocus then goes to the requestFocusNoSearch method, which specifies the focus of a View, so there is no need to use the focus mechanism:
<View.java> private boolean requestFocusNoSearch(int direction, // need to be focusable // If focusable = false, Return if ((mViewFlags & FOCUSABLE)! = FOCUSABLE || (mViewFlags & VISIBILITY_MASK) ! = VISIBLE) { return false; } // need to be focusable in touch mode if in touch mode // If (isInTouchMode() && (FOCUSABLE_IN_TOUCH_MODE! = (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { return false; // If the view sets focusableInTouchMode = false, Direct return} / / need to not have any parents blocking us if (hasAncestorThatBlocksDescendantFocus () {return false. FOCUS_BLOCK_DESCENDANTS = handleFocusGainInternal(direction, previouslyFocusedRect); return true; // Focus succeeded}Copy the code

1 requestFocusNoSearch

The requestFocusNoSearch method does the following:
  • The first step is to determine the current View’s focusable state. If false, the View does not get focus, so there is no need to proceed further.
  • In touch mode, if focusableInTouchMode is false, the View can’t get focus by touch and there is no need to move down.
  • Continue to look down a judgment hasAncestorThatBlocksDescendantFocus () method:
<View.java> private boolean hasAncestorThatBlocksDescendantFocus() { final boolean focusableInTouchMode = isFocusableInTouchMode(); ViewParent ancestor = mParent; while (ancestor instanceof ViewGroup) { final ViewGroup vgAncestor = (ViewGroup) ancestor; if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS || (! focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { return true; } else { ancestor = vgAncestor.getParent(); } } return false; }Copy the code

2 hasAncestorThatBlocksDescendantFocus

Again to see the hasAncestorThatBlocksDescendantFocus, this method also is to traverse the parent the parent View to find whether there is a set FOCUS_BLOCK_DESCENDANTS, if set, This method returns true because the parent View passed the focus to the interceptor and did not expect it to get the focus. When you return to requestFocusNoSearch, you simply return instead of going down.
After a series of criteria, if focusable and the parent View does not intercept the focus, it ends up in the core method handleFocusGainInternal:
<View.java> void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { if (DBG) { System.out.println(this + " requestFocus()"); } if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { mPrivateFlags |= PFLAG_FOCUSED; View oldFocus = (mAttachInfo!) = null) ? getRootView().findFocus() : null; if (mParent ! = null) { mParent.requestChildFocus(this, this); View updateFocusedInCluster(oldFocus, direction); } if (mAttachInfo! = null) {/ / notify mAttachInfo ViewTreeObserver focus change. MTreeObserver. DispatchOnGlobalFocusChange (oldFocus, this); } onFocusChanged(true, direction, previouslyFocusedRect); // Call the focus change callback refreshDrawableState(); Drawable state}}Copy the code

3 handleFocusGainInternal

For the handleFocusGainInternal method, it first updates the current View’s flag bit mPrivateFlags to record its isFocused state, then finds the current focus through rootView and assigns the value to oldFocus. Then call the parent’s requestChildFocus method to tell the parent that it is in focus.
<ViewGroup.java> @Override public void requestChildFocus(View child, View focused) { if (DBG) { System.out.println(this + " requestChildFocus()"); } / / installed FOCUS_BLOCK_DESCENDANTS again to determine whether the if (getDescendantFocusability () = = FOCUS_BLOCK_DESCENDANTS) {return; } // Unfocus us, if necessary super.unFocus(focused); // We had a previous notion of who had focus. Clear it. if (mFocused ! = child) { if (mFocused ! = null) { mFocused.unFocus(focused); } mFocused = child; } if (mParent ! = null) { mParent.requestChildFocus(this, focused); }}Copy the code

4 requestChildFocus

In requestChildFocus this method, focused this parameter is useless to (unFocus as a parameter to, in fact it is useless to the parameter), the first call on the incoming is this, the focus of the focused is actually directly, Directly is also focused on the child on the first call, the child = = focused, but through the mParent. RequestChildFocus (this, focused); After that, the child argument becomes the parent View of the direct focus, called layer by layer and so on. The next two arguments should be distinguished. Here is the official comment on this parameter:
<ViewParent.java> /** * Called when a child of this parent wants focus * * @param child The child of this ViewParent that wants focus. This view * will contain the focused view. It is not necessarily the view that * actually has focus. *  @param focused The view that is a descendant of child that actually has * focus */ public void requestChildFocus(View child, View focused);Copy the code

In each ViewGroup, there is a mFocus variable that holds the focus of the current ViewGroup, not the direct focus. (Official note on the meaning of this variable: The view contained within this ViewGroup that has or contains focus.) then return to The requestChildFocus(View child, View focused (‘ focused ‘) methods
  • Check again if FOCUS_BLOCK_DESCENDANTS is set, and stop going down if intercepted.
  • UnFocus (focused) mFocused. UnFocus (focused)
<View.java> void unFocus(View focused) { if (DBG) { System.out.println(this + " unFocus()"); } clearFocusInternal(focused, false, false); Void clearFocusInternal(View focused, Boolean propagate, If ((mPrivateFlags & PFLAG_FOCUSED)! = 0) { mPrivateFlags &= ~PFLAG_FOCUSED; if (propagate && mParent ! = null) { mParent.clearChildFocus(this); OnFocusChanged (false, 0, null);} onFocusChanged(false, 0, null); // Call back notification of focus state changes // Refresh the drawable state if (propagate && (! refocus || ! rootViewRequestFocus())) { notifyGlobalFocusCleared(this); }}}Copy the code

5 clearFocusInternal

Finally, let’s talk about clearFocusInternal. This method is called by mFocus, which clears the focus state of the View where the current focus is. It mainly does the following:
  • Tell parent to call clearChildFocus to set the mFocus variable to null because the focus is no longer under the View tree node.
  • The callback notifies itself of a change in focus state, which is where our usual setOnFocusChangeListener listener is set to trigger the callback.
  • Since we cleared our focus state in Step 1, we naturally need to refresh the view state after we lose focus, and we call refreshDrawableState to refresh the drawableState, which is the selector state property we normally set in XML.
** Note that ** :
The ‘focus’ parameter is not used at all, but the’ focus’ is the most direct focus.
After clearing the current focus, go back to the parent’s requestChildFocus and assign the desired child to mFocused. RequestFocus successfully shifts focus from oldFocus to newFocus by calling View.requestFocus.
<ViewGroup.java> ViewGroup.requestChildFocus ... // We had a previous notion of who had focus. Clear it. if (mFocused ! = child) { if (mFocused ! = null) { mFocused.unFocus(focused); } mFocused = child; } if (mParent ! = null) { mParent.requestChildFocus(this, focused); }...Copy the code

The parent then tells the parent View, layer by layer, that the current focus is on me. That is, if a child View is focused, it assigns itself to parent’s mFocus variable, so that the next time you look for a focus, you can find the immediate focus at the lowest level by using the mFocus variable on the top level of parent. To make this clear, expand the findFocus method:
<ViewGroup.java> @Override public View findFocus() { if (DBG) { System.out.println("Find focus in " + this + ": flags=" + isFocused() + ", child=" + mFocused); } return this if (isFocused()) {return this if (isFocused()); } // mFocus is not null, if (mFocus! = null) { return mFocused.findFocus(); } return null; } < view.java > public View findFocus() {return (mPrivateFlags & PFLAG_FOCUSED)! = 0? this : null; }Copy the code

For example: A contains B, B contains C, A and B are both viewgroups, C is A direct View, A’s mFocus is B, and B’s mFocus is C. = null (‘ A ‘, ‘B’, ‘hasFocus’,’ ISfocus’); You’ll end up in requestChildFocus of ViewRootImpl for UI redrawing.
<ViewGroup.java> public boolean hasFocus() { return (mPrivateFlags & PFLAG_FOCUSED) ! = 0 || mFocused ! = null; } <ViewRootImpl.java> @Overridepublic void requestChildFocus(View child, View focused) { if (DEBUG_INPUT_RESIZE) { Log.v(mTag, "Request child focus: focus now " + focused); } checkThread(); scheduleTraversals(); // UI redraw}Copy the code

Return to the above, the mPrivateFlags handleFocusGainInternal | = PFLAG_FOCUSED; There is a change to the tag bit by which isFocused is actually judged.
<View.java> @ViewDebug.ExportedProperty(category = "focus") public boolean isFocused() { return (mPrivateFlags & PFLAG_FOCUSED) ! = 0; }Copy the code

At this point, the view.requestfocus invocation process is finished, and the focus has moved from the oldFocus to the new newFocus. Let’s look at the viewgroup.requestFocus method:
<ViewGroup.java> @Override public boolean requestFocus(int direction, Rect previouslyFocusedRect) { if (DBG) { System.out.println(this + " ViewGroup.requestFocus direction=" + direction); } int descendantFocusability = getDescendantFocusability(); Switch (descendantFocusability) {case FOCUS_BLOCK_DESCENDANTS:// Descendants capture the focus with descendantFocusability. RequestFocus return super.requestFocus(direction, previouslyFocusedRect); case FOCUS_BEFORE_DESCENDANTS: {// First call the super logic in requestFocus itself, RequestFocus final Boolean took = super.requestFocus(direction, previouslyFocusedRect); return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect); } case FOCUS_AFTER_DESCENDANTS: {// Instead of FOCUS_BEFORE_DESCENDANTS, first traverse the sub-view for requestFocus, If the child View all request focus after a failed again call super logic in their requestFocus final Boolean took = onRequestFocusInDescendants (direction, previouslyFocusedRect); return took ? took : super.requestFocus(direction, previouslyFocusedRect); } default: throw new IllegalStateException("descendant focusability must be " + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS " + "but is " + descendantFocusability); }}Copy the code

DescendantFocusability: descendantFocusability is descendantFocusability:
  • FOCUS_BLOCK_DESCENDANTS: intercepts the focus itself and makes a requestFocus call to request the focus directly.
  • FOCUS_BEFORE_DESCENDANTS: FOCUS_BEFORE_DESCENDANTS: when its priority subview gets the focus, make a requestFocus call on itself first to get the focus, and then traverse the subview to get the focus if it fails.
  • FOCUS_AFTER_DESCENDANTS: first traverse the sub-views to get them focused, and then make a requestFocus call to oneself if none of the sub-views are focused.
Below we see onRequestFocusInDescendants done:
<ViewGroup.java> protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { int index; int increment; int end; int count = mChildrenCount; if ((direction & FOCUS_FORWARD) ! = 0) {// index = 0; increment = 1; end = count; } else {// index = count - 1; increment = -1; end = -1; } final View[] children = mChildren; // the mChildren array holds all childViews for (int I = index; i ! = end; i += increment) { View child = children[i]; If ((child.mviewFlags & VISIBILITY_MASK) == VISIBLE) {// Traverses the child View, If (child-requestFocus (direction, previouslyFocusedRect)) {return true; }}} return false; }Copy the code
OnRequestFocusInDescendants main function is to traverse all child under this ViewGroup View, then the son of the visible View call requestFocus, focus if the request is successful, the direct returns true, at this point, ViewGroup. RequestFocus is also handled.

Welcome to the Android community

The group invites some Android cattle around from time to time

Communicate and share, and answer the problems encountered in the work

Share work experience, interview tips and more! Add: yzlkf09

You are also welcome to contribute, the content can be database, development, operation and maintenance, products, operations and so on!

Yue column LIKECOLUMN

Here, learn programming well

Be a better IT person!