Activity.onWindowFocusChanged首次执行过程源码分析

触发onWindowFocusChanged的情况有多种,比如应用前后台来回切换、软键盘弹出或者隐藏、首次进入一个Activity后会在onResume方法之后调用等,我们以最后一种场景,分析它的执行过程。

我们以ActivityThread.handleResumeActivity()方法作为切入点开始分析。

public final class ActivityThread extends ClientTransactionHandler

    //省略其他方法
       ...
    @Override
    public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
            String reason) {
       
        //省略部分代码
           ...
        final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
        final Activity a = r.activity;
        //省略部分代码
        ...
        r.window = r.activity.getWindow();
        View decor = r.window.getDecorView();
        decor.setVisibility(View.INVISIBLE);
        ViewManager wm = a.getWindowManager();
        WindowManager.LayoutParams l = r.window.getAttributes();
        a.mDecor = decor;
        l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
        l.softInputMode |= forwardBit;
           
        wm.addView(decor, l);
               
        //省略部分代码
          ...
    }
}

我们知道这个方法是控制Acitvity.onResume执行的,也就是说在onResume之后,才会将DecorView的对象decor(activity显示内容的最外层容器)对象添加到ViewManager的对象wm中。那么wm对象是在什么时候初始化的呢?他是在Activity中初始化的,我们看一下是哪个方法里初始化的。

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback,
        AutofillManager.AutofillClient {
    //省略其他方法
    ...

    final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback) {
        //省略部分代码
        ...

        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        //省略部分代码
        ...
       
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }

        mWindowManager = mWindow.getWindowManager();
        //省略部分代码
        ...
        
    }

    /** Retrieve the window manager for showing custom windows. */
    public WindowManager getWindowManager() {
        return mWindowManager;
    }
    //省略其他方法
    ...
}

我们看到Activity.attach方法中创建了Window唯一实现类PhoneWindow类型的mWindow对象,mWindowManager对象也是从PhoneWindow获取的。那么他是在哪里初始化的呢?

public abstract class Window {
    //省略其他方法
    ...

    /**
     * Set the window manager for use by this Window to, for example,
     * display panels.  This is <em>not</em> used for displaying the
     * Window itself -- that must be done by the client.
     *
     * @param wm The window manager for adding new windows.
     */
    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated
                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }
    //省略其他方法
    ...
}

Window是PhoneWindow的基类,在setWindowManager方法中初始化了mWindowManager对象。(WindowManagerImpl类是WindowManager的实现类,WindowManager接口继承了ViewManager接口)。

我们回到最初wm.addView(decor,l)方法,实际上是调用了WindowManagerImpl.addView方法,我们看一下该方法的实现。

public final class WindowManagerImpl implements WindowManager {
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    //省略部分代码
        ...

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }
}

我们看到addView方法调用了WindowManagerGlobal.addView方法,我们看一下该方法的实现。

public final class WindowManagerGlobal {
    //省略部分方法
        ...

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        //省略部分代码
            ...

        ViewRootImpl root;
        View panelParentView = null;

        //省略部分代码
            ...

        root = new ViewRootImpl(view.getContext(), display);

        view.setLayoutParams(wparams);

        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);

        // do this last because it fires off messages to start doing things
        try {
           root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
            // BadTokenException or InvalidDisplayException, clean up.
            if (index >= 0) {
                removeViewLocked(index, true);
             }
             throw e;
            }
        }
    }

在addView中方法调用了ViewRootImpl.setView方法,我们看一下该方法的实现。

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {

    final IWindowSession mWindowSession;
    final W mWindow;

    public ViewRootImpl(Context context, Display display) {
        mWindowSession = WindowManagerGlobal.getWindowSession();
        mWindow = new W(this);
        //省略部分代码
            ...
    }

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        //省略部分代码
            ...
        res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
        //省略部分代码
            ...

    }

    static class W extends IWindow.Stub {
        private final WeakReference<ViewRootImpl> mViewAncestor;
        private final IWindowSession mWindowSession;

        W(ViewRootImpl viewAncestor) {
            mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
            mWindowSession = viewAncestor.mWindowSession;
        }

        @Override
        public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
            final ViewRootImpl viewAncestor = mViewAncestor.get();
            if (viewAncestor != null) {
                viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
            }
        }

        //省略其他代码
            ...
    }

}

setView方法调用了IWindowSession.addToDisplay方法(注意:mWindow对象是W类型的,后面会用到这个对象)。我们看一下该方法的实现。

public final class WindowManagerGlobal {
    
    //省略部分方法
        ...
   
    public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    InputMethodManager imm = InputMethodManager.getInstance();
                    IWindowManager windowManager = getWindowManagerService();
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            },
                            imm.getClient(), imm.getInputContext());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowSession;
        }
    }

}

通过以上代码,我们看到IWindowSession对象,是通过WindowMangerService创建的,WindowManagerService实现了IWindowManager。我们看一下WindowMangerService.openSession方法

public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    //省略其他代码
        ...

    // -------------------------------------------------------------
    // IWindowManager API
    // -------------------------------------------------------------

    @Override
    public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
            IInputContext inputContext) {
        if (client == null) throw new IllegalArgumentException("null client");
        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
        Session session = new Session(this, callback, client, inputContext);
        return session;
    }


}

我们看到openSession方法中创建了Session对象返回,也就是说ViewRootImpl.setView方法中调用的是Session.addToDisplay方法,我们看一下该方法的实现。

class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {

    final WindowManagerService mService;
    
    public Session(WindowManagerService service, IWindowSessionCallback callback,
            IInputMethodClient client, IInputContext inputContext) {
        mService = service;
    }
        
    //省略部分代码
        ...

    @Override
    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
            Rect outStableInsets, Rect outOutsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
                outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel);
    }
}

addToDisplay方法中调用了WindowManagerService.addWindow方法。我们看一下addWindow方法的实现。

 

public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    //省略其他代码
        ...

    public int addWindow(Session session, IWindow client, int seq,
            LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
           
          final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], seq, attrs, viewVisibility, session.mUid,
                    session.mCanAddInternalSystemWindow);
          //省略部分代码
            ...
          focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
                        false /*updateInputWindows*/);
    
        //省略部分代码
            ...
    }

    // TODO: Move to DisplayContent
    boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {

         mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
    }

    
    final class H extends android.os.Handler {
        public static final int REPORT_FOCUS_CHANGE = 2;
         //省略部分代码
            ...
         @Override
        public void handleMessage(Message msg) {
            if (DEBUG_WINDOW_TRACE) {
                Slog.v(TAG_WM, "handleMessage: entry what=" + msg.what);
            }
            switch (msg.what) {
                case REPORT_FOCUS_CHANGE: {
                    WindowState newFocus;

                    newFocus.reportFocusChangedSerialized(true, mInTouchMode);
                    
                } break;
                 //省略部分代码
                    ...
            }

    }


}

在WindowManagerService.addWindow方法中调用了updateFocusedWindowLocked方法,然后通过Handler调用了WindowState.reportFocusChangedSerialized方法。我们看一下该方法的实现

class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState {
    final IWindow mClient;
    //省略其他代码
        ...
    WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
            WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
            int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow,
            PowerManagerWrapper powerManagerWrapper) {
        super(service);
        
        mClient = c;
    }    

    /**
     * Report a focus change.  Must be called with no locks held, and consistently
     * from the same serialized thread (such as dispatched from a handler).
     */
    void reportFocusChangedSerialized(boolean focused, boolean inTouchMode) {
        try {
            mClient.windowFocusChanged(focused, inTouchMode);
        } catch (RemoteException e) {
        }
        if (mFocusCallbacks != null) {
            final int N = mFocusCallbacks.beginBroadcast();
            for (int i=0; i<N; i++) {
                IWindowFocusObserver obs = mFocusCallbacks.getBroadcastItem(i);
                try {
                    if (focused) {
                        obs.focusGained(mWindowId.asBinder());
                    } else {
                        obs.focusLost(mWindowId.asBinder());
                    }
                } catch (RemoteException e) {
                }
            }
            mFocusCallbacks.finishBroadcast();
        }
    }

}

WindowState.reportFocusChangedSerialized方法中调用了mClient.windowFocusChanged方法,mClient是IWindow的对象,也就是我们构建的调用WindowMangerService.addWindow方法时传入的W类的对象,因此会调用W.windowFocusChanged方法。

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {

    final IWindowSession mWindowSession;
    final W mWindow;

    public ViewRootImpl(Context context, Display display) {
        mWindowSession = WindowManagerGlobal.getWindowSession();
        mWindow = new W(this);
        //省略部分代码
            ...
    }

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        //省略部分代码
            ...
        res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
        //省略部分代码
            ...

    }

    static class W extends IWindow.Stub {
        private final WeakReference<ViewRootImpl> mViewAncestor;
        private final IWindowSession mWindowSession;

        W(ViewRootImpl viewAncestor) {
            mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
            mWindowSession = viewAncestor.mWindowSession;
        }

        @Override
        public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
            final ViewRootImpl viewAncestor = mViewAncestor.get();
            if (viewAncestor != null) {
                viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
            }
        }

        //省略其他代码
            ...
    }

    public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
        synchronized (this) {
            mWindowFocusChanged = true;
            mUpcomingWindowFocus = hasFocus;
            mUpcomingInTouchMode = inTouchMode;
        }
        Message msg = Message.obtain();
        msg.what = MSG_WINDOW_FOCUS_CHANGED;
        mHandler.sendMessage(msg);
    }
    
    private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
    final class ViewRootHandler extends Handler {
    
         @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                 case MSG_WINDOW_FOCUS_CHANGED: {
                    handleWindowFocusChanged();
                } break;
            }
    }
    
    private void handleWindowFocusChanged() {
      
         mView.dispatchWindowFocusChanged(hasWindowFocus);
    }

}

W.windowFocusChanged方法会调用ViewRootImpl.windowFocusChange方法,该方法通过Handler执行handleWindowFocusChanged方法,该方法调用View.dispatchWindowFocusChanged方法,我们知道,mView是DecorView的实例,所以最终调用DecorView.onWindowChangeFocused方法。

public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
    //省略其他代码
        ...
    
     @Override
    public void onWindowFocusChanged(boolean hasWindowFocus) {
        super.onWindowFocusChanged(hasWindowFocus);

        // If the user is chording a menu shortcut, release the chord since
        // this window lost focus
        if (mWindow.hasFeature(Window.FEATURE_OPTIONS_PANEL) && !hasWindowFocus
                && mWindow.mPanelChordingKey != 0) {
            mWindow.closePanel(Window.FEATURE_OPTIONS_PANEL);
        }

        final Window.Callback cb = mWindow.getCallback();
        if (cb != null && !mWindow.isDestroyed() && mFeatureId < 0) {
            cb.onWindowFocusChanged(hasWindowFocus);
        }

        if (mPrimaryActionMode != null) {
            mPrimaryActionMode.onWindowFocusChanged(hasWindowFocus);
        }
        if (mFloatingActionMode != null) {
            mFloatingActionMode.onWindowFocusChanged(hasWindowFocus);
        }

        updateElevation();
    }

}

DecorView.onWindowFocusChanged方法中调用了cb.onWindowFocusChanged方法,我们发现Activity实现了Window.CallBack并在创建PhoneWindow时,实例传给了PhoneWindow,因此这个方法调用的就是Acitivity中的onWindowFocusChanged。这就是onWindowFocusChanged首次执行过程。

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值