Android随笔随想-GUI-事件分发先导篇2

来源:互联网 发布:现金流水账记账软件 编辑:程序博客网 时间:2024/05/08 02:40

Android随笔随想-GUI-事件分发先导篇2 - 找到事件分发的相关类

基于Android 2.3.7 源码分析

随笔

在分析android的事件分发之前,还需要了解一些内容,那就是Ams与Wms的关联,这里目前指的是client端的关联

目前的分析流程根据ActivityThread的过程即可

上篇中已经提到了大体的流程,现在这几个流程细化一些:
同一个应用中,Actiivty activityA正常模式启动一个activityB的流程

  1. Ams通知pauseActivityA
  2. ActivityThread在收到pause后(ActivityThread.handlePauseActivity()),做对应的操作后,通知Ams,已经pause
  3. Ams在收到通知后,记录下这些信息,然后通知ActivityThread启动下一个Activity,activityB,并且自己发送Handler的10ms的delay通知,到了之后,检查是否要通知stop activity
  4. 端上在收到Ams的启动通知后(ActivityThread.handleLauncheActivity())后,便通知Activity进行启动

相关详细文章,可参照老罗的android 之旅

上面罗列的几个细节点,在启动Activity时,会调用ActivityThread.handleLauncheActiivty,在要停止运行时,会逐步通知,先ActvityThread的handlePauseActivity,然后会ActivityThread.handleStopActivity(),在端上主动调用finish时,经过Ams的处理,最终会通知ActivityThread进行handleDestroyActivity的操作,在操作完成后,会通知Ams,Activity已经销毁.

根据这几个过程,我们会找到我们想要的事件分发的相关类
汇总流程

  1. ActivityThread.handleLaunchActivity
  2. ActivityThread.handlePauseActivity
  3. ActivityThread.handleStopActivity
  4. Activity.handleDestroyActivity

ActivityThread的launch Activity的过程

android.app.ActivityThread. scheduleLaunchActivity()

    // we use token to identify this activity without having to send the    // activity itself back to the activity manager. (matters more with ipc)    public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,            ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,            List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) {        ActivityClientRecord r = new ActivityClientRecord();        r.token = token;        r.ident = ident;        r.intent = intent;        r.activityInfo = info;        r.state = state;        r.pendingResults = pendingResults;        r.pendingIntents = pendingNewIntents;        r.startsNotResumed = notResumed;        r.isForward = isForward;        queueOrSendMessage(H.LAUNCH_ACTIVITY, r);    }

将IPC的通知结果,组装成ActivityCLientRecord,发给handler

android.app.ActivityThread.H.handleMessage()

private final class H extends Handler {         ......       public void handleMessage(Message msg) {        if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + msg.what);        switch (msg.what) {            case LAUNCH_ACTIVITY: {                ActivityClientRecord r = (ActivityClientRecord)msg.obj;                r.packageInfo = getPackageInfoNoCheck(                        r.activityInfo.applicationInfo);                handleLaunchActivity(r, null);            } break;            ......         }        if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what);    }    ......}
  1. 组装了Client的package的信息
  2. 调用handleLaunchActivity()

android.app.ActivityThread.handleLaunchActiivty()

private final void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {    ...    Activity a = performLaunchActivity(r, customIntent);    if (a != null) {        r.createdConfig = new Configuration(mConfiguration);        Bundle oldState = r.state;        handleResumeActivity(r.token, false, r.isForward);          ......    } else {        // If there was an error, for any reason, tell the activity        // manager to stop us.        try {            ActivityManagerNative.getDefault()                .finishActivity(r.token, Activity.RESULT_CANCELED, null);        } catch (RemoteException ex) {        }    }}

查看代码,得知,做了两件事情

  1. 调用performLaunchActivity()
  2. 如果返回的activity不是null,调用handleResumeActivity()

从这里也可以看出,是先运行activitiy,然后resumeActivity

一个一个看

android.app.ActivityThread.performLaunchActivity()

private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {             ......    Activity activity = null;    //step 1: 根据反射,构造Activity    try {        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();        activity = mInstrumentation.newActivity(                cl, component.getClassName(), r.intent);        r.intent.setExtrasClassLoader(cl);        if (r.state != null) {            r.state.setClassLoader(cl);        }    } catch (Exception e) {        if (!mInstrumentation.onException(activity, e)) {            throw new RuntimeException(                "Unable to instantiate activity " + component                + ": " + e.toString(), e);        }    }     //step 2: 获取到Application    try {        Application app = r.packageInfo.makeApplication(false, mInstrumentation);         ......        if (activity != null) {           //step3: 构造ContextImpl,并且初始化            ContextImpl appContext = new ContextImpl();            appContext.init(r.packageInfo, r.token, this);            appContext.setOuterContext(activity);            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());            Configuration config = new Configuration(mConfiguration);            ......            //step4: 将ContextImpl等信息,attach到Activity            activity.attach(appContext, this, getInstrumentation(), r.token,                    r.ident, app, r.intent, r.activityInfo, title, r.parent,                    r.embeddedID, r.lastNonConfigurationInstance,                    r.lastNonConfigurationChildInstances, config);            if (customIntent != null) {                activity.mIntent = customIntent;            }            r.lastNonConfigurationInstance = null;            r.lastNonConfigurationChildInstances = null;            activity.mStartedActivity = false;            int theme = r.activityInfo.getThemeResource();            if (theme != 0) {                activity.setTheme(theme);            }                //step5: 通过Instrument 通知Activity进行onCreate()            activity.mCalled = false;            mInstrumentation.callActivityOnCreate(activity, r.state);            if (!activity.mCalled) {                throw new SuperNotCalledException(                    "Activity " + r.intent.getComponent().toShortString() +                    " did not call through to super.onCreate()");            }            r.activity = activity;            r.stopped = true;                //step6: 通知Activity进行start            if (!r.activity.mFinished) {                activity.performStart();                r.stopped = false;            }            //step7: 如果有state信息,通知Activity进行OnRestoreInstanceState            if (!r.activity.mFinished) {                if (r.state != null) {                    mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);                }            }            //step8: 通知Activity进行onPostCreate            if (!r.activity.mFinished) {                activity.mCalled = false;                mInstrumentation.callActivityOnPostCreate(activity, r.state);                if (!activity.mCalled) {                    throw new SuperNotCalledException(                        "Activity " + r.intent.getComponent().toShortString() +                        " did not call through to super.onPostCreate()");                }            }        }        //step9: 记录ActivityRecord的状态,然后放置到mActivities中,保存起来        r.paused = true;        mActivities.put(r.token, r);    } catch (SuperNotCalledException e) {        throw e;    } catch (Exception e) {        if (!mInstrumentation.onException(activity, e)) {            throw new RuntimeException(                "Unable to start activity " + component                + ": " + e.toString(), e);        }    }    return activity;}
  1. 根据反射,构造Activity
  2. 获取到Application
  3. 构造ContextImpl,并且初始化
  4. 将ContextImpl等信息,attach到Activity
  5. 通过Instrument 通知Activity进行onCreate()(相关实现可以查看instrumentation中的callActiivtyOnCreate)
  6. 通知Activity进行start
  7. 如果有state信息,通知Activity进行OnRestoreInstanceState
  8. 通知Activity进行onPostCreate
  9. 记录ActivityRecord的状态,然后放置到mActivities中,保存起来

android.app.ActivityThread.handleResumeActivity

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {    ......    //1. 执行performResumeActivity    ActivityClientRecord r = performResumeActivity(token, clearHide);    if (r != null) {        final Activity a = r.activity;        final int forwardBit = isForward ?                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;        ......                //2. ViewManager中添加decorView        // If the window hasn't yet been added to the window manager,        // and this guy didn't finish itself or start another activity,        // then go ahead and add the window.        boolean willBeVisible = !a.mStartedActivity;        if (!willBeVisible) {            try {                willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(                        a.getActivityToken());            } catch (RemoteException e) {            }        }        if (r.window == null && !a.mFinished && willBeVisible) {            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;            if (a.mVisibleFromClient) {                a.mWindowAdded = true;                wm.addView(decor, l);            }        // If the window has already been added, but during resume        // we started another activity, then don't yet make the        // window visible.        } else if (!willBeVisible) {            if (localLOGV) Slog.v(                TAG, "Launch " + r + " mStartedActivity set");            r.hideForNow = true;        }        // The window is now visible if it has been added, we are not        // simply finishing, and we are not starting another activity.        if (!r.activity.mFinished && willBeVisible                && r.activity.mDecor != null && !r.hideForNow) {               if (r.newConfig != null) {                performConfigurationChanged(r.activity, r.newConfig);                r.newConfig = null;            }            ......            //3. updateViewLayout            WindowManager.LayoutParams l = r.window.getAttributes();            if ((l.softInputMode                    & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)                    != forwardBit) {                l.softInputMode = (l.softInputMode                        & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))                        | forwardBit;                if (r.activity.mVisibleFromClient) {                    ViewManager wm = a.getWindowManager();                    View decor = r.window.getDecorView();                    wm.updateViewLayout(decor, l);                }            }            r.activity.mVisibleFromServer = true;            mNumVisibleActivities++;            //4. 假如activity没有做显示,显示出来            if (r.activity.mVisibleFromClient) {                r.activity.makeVisible();            }        }        r.nextIdle = mNewActivities;        mNewActivities = r;        if (localLOGV) Slog.v(            TAG, "Scheduling idle handler for " + r);        Looper.myQueue().addIdleHandler(new Idler());    } else {        // If an exception was thrown when trying to resume, then        // just end this activity.        try {            ActivityManagerNative.getDefault()                .finishActivity(token, Activity.RESULT_CANCELED, null);        } catch (RemoteException ex) {        }    }}
  1. 执行performResumeActivity
  2. ViewManager中添加decorView
  3. updateViewLayout
  4. 假如activity没有做显示,显示出来

performResumeActivity()

    public final ActivityClientRecord performResumeActivity(IBinder token,            boolean clearHide) {        ActivityClientRecord r = mActivities.get(token);        ......        if (r != null && !r.activity.mFinished) {            if (clearHide) {                r.hideForNow = false;                r.activity.mStartedActivity = false;            }            try {                if (r.pendingIntents != null) {                    deliverNewIntents(r, r.pendingIntents);                    r.pendingIntents = null;                }                if (r.pendingResults != null) {                    deliverResults(r, r.pendingResults);                    r.pendingResults = null;                }                r.activity.performResume();                EventLog.writeEvent(LOG_ON_RESUME_CALLED,                        r.activity.getComponentName().getClassName());                r.paused = false;                r.stopped = false;                r.state = null;            } catch (Exception e) {                if (!mInstrumentation.onException(r.activity, e)) {                    throw new RuntimeException(                        "Unable to resume activity "                        + r.intent.getComponent().toShortString()                        + ": " + e.toString(), e);                }            }        }        return r;    }
  1. 我们启动时,clearHide是false,并且是首次启动,因而不会做deliverResults以及deliverResults的操作,只会做activity的performResume操作,并且设置paused,stopped,state为null

  2. 将Activity进行attach()

  3. 将Activity进行onCreate()
  4. 将Activity进行onStart()
  5. 将Activity进行postOnCreate()
  6. 将Activity进行onResume
  7. 通知Activity进行start

跟我们相关的其实只有三个过程

  1. Activity的attach过程
  2. Activity的onCreate()过程
  3. ActivityThread调用的handleResumeActivity中的windowManager.addView()和updateLayout的过程

那么接下来就看这几个过程

Activity的attach过程

android.app.Activity.attach()

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,        Object lastNonConfigurationInstance,        HashMap<String,Object> lastNonConfigurationChildInstances,        Configuration config) {    attachBaseContext(context);    mWindow = PolicyManager.makeNewWindow(this);    mWindow.setCallback(this);    if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {        mWindow.setSoftInputMode(info.softInputMode);    }    mUiThread = Thread.currentThread();    mMainThread = aThread;    mInstrumentation = instr;    mToken = token;    mIdent = ident;    mApplication = application;    mIntent = intent;    mComponent = intent.getComponent();    mActivityInfo = info;    mTitle = title;    mParent = parent;    mEmbeddedID = id;    mLastNonConfigurationInstance = lastNonConfigurationInstance;    mLastNonConfigurationChildInstances = lastNonConfigurationChildInstances;    mWindow.setWindowManager(null, mToken, mComponent.flattenToString());    if (mParent != null) {        mWindow.setContainer(mParent.getWindow());    }    mWindowManager = mWindow.getWindowManager();    mCurrentConfig = config;}
  1. attach了baseActivity,这是在ActivityThread中创建的ContextImpl,然后Activity attachBase后,这个便是ContextWrapper中的mBase
  2. 构建了Window,并且设置callback为当前的activity
  3. 将ActivityThread传递的参数,给当前activity进行赋值
  4. 给mWindow设置windowmanager
  5. 设置当前的windowManager为mWindow中get的windowManager

这里面看似简单,其实信息量很多,我们逐个分析

Activity的attachBaseContext()

在上篇中的图中,已经提到了Context的类结构,从这里的attach,也可以context的结构

Activity虽然继承Context,但是只是作为一个包装的继承类,方便了我们与真正的Context: ContextImpl进行交互,再次截图如下:

context相关类图

可以以activity的getSystemService为例,查看相关的源码,在activity中直接引用的,则直接返回对应的service,否则,便通过attach的baseContext()进行获取

Activity.getSystemService()

 @Overridepublic Object getSystemService(String name) {    if (getBaseContext() == null) {        throw new IllegalStateException(                "System services not available to Activities before onCreate()");    }    if (WINDOW_SERVICE.equals(name)) {        return mWindowManager;    } else if (SEARCH_SERVICE.equals(name)) {        ensureSearchManager();        return mSearchManager;    }    return super.getSystemService(name);}

ContextThemeWrapper.getSystemService()

@Override public Object getSystemService(String name) {    if (LAYOUT_INFLATER_SERVICE.equals(name)) {        if (mInflater == null) {            mInflater = LayoutInflater.from(mBase).cloneInContext(this);        }        return mInflater;    }    return mBase.getSystemService(name);}
构建Window,并且设置callback为当前的activity
    mWindow = PolicyManager.makeNewWindow(this);    mWindow.setCallback(this);    if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {        mWindow.setSoftInputMode(info.softInputMode);    }

代码只看三行,信息量却是巨大的

单纯来看,创建了一个Window,然后给window设置了callback为当前的activity,然后设置了一个输入法模式

一步一步来看

PolicyManager.makeNewWindow()过程

PolicyManager.makeNewWindow()

// The static methods to spawn new policy-specific objectspublic static Window makeNewWindow(Context context) {    return sPolicy.makeNewWindow(context);}

这里只是调用了方法而已,我们查看sPolicy的makeNewWindow()方法

PolicyManager的完整类

public final class PolicyManager {    private static final String POLICY_IMPL_CLASS_NAME =        "com.android.internal.policy.impl.Policy";    private static final IPolicy sPolicy;    static {        // Pull in the actual implementation of the policy at run-time        try {            Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);            sPolicy = (IPolicy)policyClass.newInstance();        } catch (ClassNotFoundException ex) {            throw new RuntimeException(                    POLICY_IMPL_CLASS_NAME + " could not be loaded", ex);        } catch (InstantiationException ex) {            throw new RuntimeException(                    POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);        } catch (IllegalAccessException ex) {            throw new RuntimeException(                    POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);        }    }    // Cannot instantiate this class    private PolicyManager() {}    // The static methods to spawn new policy-specific objects    public static Window makeNewWindow(Context context) {        return sPolicy.makeNewWindow(context);    }    public static LayoutInflater makeNewLayoutInflater(Context context) {        return sPolicy.makeNewLayoutInflater(context);    }    public static WindowManagerPolicy makeNewWindowManager() {        return sPolicy.makeNewWindowManager();    }}

从上面也可以看出,是反射构建了Policy的对象,那么直接查找对应的Policy类,并且查找其makeNewWindow(Context context)的方法

Policy.makeNewWindow()

public PhoneWindow makeNewWindow(Context context) {    return new PhoneWindow(context);}

查看上述方法,也是很简单的,构造了一个PhoneWindow

小总结一下:

在PolicyManager.makeNewWindow()时,通过反射构造的Policy,返回了实现Window的PhoneWindow对象

接下来还是要看看PhoneWindow在构造时,做了什么

PhoneWindow构造

public PhoneWindow(Context context) {    super(context);    mLayoutInflater = LayoutInflater.from(context);}public Window(Context context) {    mContext = context;}

没有什么,只是保存了context,并且创建了一个layoutInflater,保存了起来

PhoneWindow是一个很关键的类,接下来分析会和他紧密联系

Window.setCallback()过程

刚才已经提到 , Window是phoneWindow,那么直接查看PhoneWindow.setCallback(),看到是基类的操作

Window.setCallback()

   /**     * Set the Callback interface for this window, used to intercept key     * events and other dynamic operations in the window.     *     * @param callback The desired Callback interface.     */    public void setCallback(Callback callback) {        mCallback = callback;    }

小总结一下:

经过上面两个步骤:做到了以下几点:

  1. 构建了一个PhoneWindow
  2. 将PhoneWindow的callback设置为当前的Activity

    PhoneWindow是什么,接下来我们继续看,PhoneWindow和WindowManager是否有关系,答案是肯定的,但是WindowManagerService是否管理的就是我们说的PhoneWindow,有关系,但是无直接关系。

    我们继续看

将ActivityThread传递的参数,给当前activity进行赋值
     mUiThread = Thread.currentThread();    mMainThread = aThread;    mInstrumentation = instr;    mToken = token;    mIdent = ident;    mApplication = application;    mIntent = intent;    mComponent = intent.getComponent();    mActivityInfo = info;    mTitle = title;    mParent = parent;    mEmbeddedID = id;

记录了thread,instrumenttation,token,application,intent,activityInfo和title,parentActivity等信息,知道即可

给mWindow设置windowmanager
mWindow.setWindowManager(null, mToken, mComponent.flattenToString());if (mParent != null) {    mWindow.setContainer(mParent.getWindow());}

我们的parent是null,因而只需要查看PhoneWindow的setWindowManager即可

Window.setWindowManager()

    /**     * 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 ViewManager for adding new windows.     */    public void setWindowManager(WindowManager wm,            IBinder appToken, String appName) {        mAppToken = appToken;        mAppName = appName;        if (wm == null) {            wm = WindowManagerImpl.getDefault();        }        mWindowManager = new LocalWindowManager(wm);    }       
  1. 保存了appToken,appName
  2. 如果wm为null,获取默认的WindowManager
  3. 根据wm,构建一个local的WindowManager

由于我们传过来的wm是null,因而是直接获取的WindowManagerImpl,根据这个wm,构建的LocalWindowManager.

在这里停一下,查看下对应的实现

WindowManager的结构

我们先大体的看一下,类是用来做什么的,以及LocalWindowManager和WindowManagerImpl之间的关系

LocalWindoManager

翻看其源码,看到,其实没有做太多的事情

  1. 实现了WindowManager的接口
  2. 在构造时,传过来了一个WindowManager
  3. 方法的调用也不多,看到是用来和构造时传递来的WindowManager交互的代理

从这里就发现了,其实LocalWindowManager可以认为是WindowManager的代理类,但是其中也包含了一些自己的逻辑,比如说addView时的逻辑

WindowManagerImpl

翻看其源码,发现做的事情如下:

  1. 实现了WindowManager的接口
  2. 这里具体的实现了WindowMangager中的接口内容,比如说addView,removeView,findView等操作这些事用来做什么的?我们稍后再看,目前知道是用来做Window的一个管理使用的

小总结一下

看到这里,以及看到了很多的类,
Window, PhoneWindow, LocalWindowManager, WindowManager, WindowManagerImpl,总结下相互之间的关系

一个Activity会对应一个PhoneWindow,而在Activity,attach时,也会构造对应的LocalWindowManager,这个LocalWindowManager相当于一个代理类,作为WindowManagerImpl的代理,WindowManagerImpl作为具体操作类,会真正的实现WindowManager的功能.
具体是什么功能?
通过具体查看,得知是添加view,删除view等操作,而根据WindowManager的说明,得知WindowManager管理的是Activity的根View,具体根View是什么,我们继续看.
先整理Window相关类图如下:

Window的client类的基本类图

设置当前的windowManager为mWindow中get的windowManager

设置Activity中使用的windowManager为我们创建的LocalWindowManager

Activity的onCreate()过程

Activity.onCreate()

/** * Called when the activity is starting.  This is where most initialization * should go: calling {@link #setContentView(int)} to inflate the * activity's UI, using {@link #findViewById} to programmatically interact * with widgets in the UI, calling * {@link #managedQuery(android.net.Uri , String[], String, String[], String)} to retrieve * cursors for data being displayed, etc. *  * <p>You can call {@link #finish} from within this function, in * which case onDestroy() will be immediately called without any of the rest * of the activity lifecycle ({@link #onStart}, {@link #onResume}, * {@link #onPause}, etc) executing. *  * <p><em>Derived classes must call through to the super class's * implementation of this method.  If they do not, an exception will be * thrown.</em></p> *  * @param savedInstanceState If the activity is being re-initialized after *     previously being shut down then this Bundle contains the data it most *     recently supplied in {@link #onSaveInstanceState}.  <b><i>Note: Otherwise it is null.</i></b> *  * @see #onStart * @see #onSaveInstanceState * @see #onRestoreInstanceState * @see #onPostCreate */protected void onCreate(Bundle savedInstanceState) {    mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(            com.android.internal.R.styleable.Window_windowNoDisplay, false);    mCalled = true;}

这个方法的实现,没有操作太多内容,设置了mCalled为true,以及设置了mVisibleFromClient,但是这个方法的说明,以及我们看到的ActivityThread中的实现,是很有帮助的.

  1. 在Activity的onCreate中,我们是可以调用finish()方法的,假如说调用了finish()方法,那么Activity的生命周期中的其他方法是不会调用的,这个我们自己可以看下Activity的finish()方法做了什么,以及在ActivityThread.performLaunchActivity()时,在通知Activity onCreate后,会做什么判断
  2. 在这里通常是我们做事情的开始,setContentView(),findViewById(),以及数据的初始化
  3. savedInstanceState,假如说activity因而内存不够用,而被finish(),我们可以获取一些信息
  4. 假如在我们继承的Activity中,没有调用这个Activity.onCreate()即基类的方法,那么会直接抛出异常的,异常的处理是在Activity的performLaunchActivity中

    其实看了这些,发现是不能和Window关联起来的,因而在此处我们会setContentView(),这个方法我们还是要看看具体的实现的.

    Activity.setContentView()

    /**

    • Set the activity content from a layout resource. The resource will be
    • inflated, adding all top-level views to the activity.

      • @param layoutResID Resource ID to be inflated.
        */
        public void setContentView(int layoutResID) {
        getWindow().setContentView(layoutResID);
        }

没有实际内容,直接看window的setContentView即可,window我们已经知道,是PhoneWindow(),那么继续看

PhoneWindow.setContentView()

@Overridepublic void setContentView(int layoutResID) {    if (mContentParent == null) {        installDecor();    } else {        mContentParent.removeAllViews();    }    mLayoutInflater.inflate(layoutResID, mContentParent);    final Callback cb = getCallback();    if (cb != null) {        cb.onContentChanged();    }}
  1. 判断contentParent是否为null,是null,安装decor
  2. 如果不是null,删除所有的view
  3. 采用构造时初始化的mLayoutInflater填充layoutResId
  4. 获得callback,通知callback,内容发生了改变,这里的callback就是我们的Activity

由于没有做其他操作,所以mContentParent是null的,因而我们要查看的路径就是安装decor.

PhoneWindow.installDecor()

private void installDecor() {    if (mDecor == null) {        mDecor = generateDecor();        mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);        mDecor.setIsRootNamespace(true);    }    if (mContentParent == null) {        mContentParent = generateLayout(mDecor);        mTitleView = (TextView)findViewById(com.android.internal.R.id.title);        if (mTitleView != null) {            if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {                View titleContainer = findViewById(com.android.internal.R.id.title_container);                if (titleContainer != null) {                    titleContainer.setVisibility(View.GONE);                } else {                    mTitleView.setVisibility(View.GONE);                }                if (mContentParent instanceof FrameLayout) {                    ((FrameLayout)mContentParent).setForeground(null);                }            } else {                mTitleView.setText(mTitle);            }        }    }}
  1. 判断mDecor是否为null,为null,创建Decor,并且设置相关属性
  2. 判断mContentParent是否为null,为null,则构建mContentParent,并且根据是否是no_title,设置title的值

那么还是老规矩,一步一步来:

PhoneWindow.generateDecor()

    protected DecorView generateDecor() {        return new DecorView(getContext(), -1);    }

也就是构建了一个DecorView,千呼万唤始出来的一个类,这个是个核心的类,目前我们也先瞅瞅他,到底有何特殊之处,导致她如此核心

大体瞅上几眼,发现如下的内容

  1. 继承了FrameLayout
  2. 复写了常用的事件分发的方法,dispatchKeyEvent,dispatchTouchEvent,onInterceptTouchEvent,这个已经和我们的事件分发联系上了,但是还不知道是怎么联系上的,我们继续看.

PhoneWindow.generateLayout()

protected ViewGroup generateLayout(DecorView decor) {    // Apply data from current theme.     //1. 设置了window的attrs,layoutParams的一些属性    TypedArray a = getWindowStyle();     ......    mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false);    int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)            & (~getForcedWindowFlags());    if (mIsFloating) {        setLayout(WRAP_CONTENT, WRAP_CONTENT);        setFlags(0, flagsToUpdate);    } else {        setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);    }    if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) {        requestFeature(FEATURE_NO_TITLE);    }    if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {        setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags()));    }    if (a.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {        setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));    }    WindowManager.LayoutParams params = getAttributes();    if (!hasSoftInputMode()) {        params.softInputMode = a.getInt(                com.android.internal.R.styleable.Window_windowSoftInputMode,                params.softInputMode);    }    if (a.getBoolean(com.android.internal.R.styleable.Window_backgroundDimEnabled,            mIsFloating)) {        /* All dialogs should have the window dimmed */        if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) {            params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;        }        params.dimAmount = a.getFloat(                android.R.styleable.Window_backgroundDimAmount, 0.5f);    }    if (params.windowAnimations == 0) {        params.windowAnimations = a.getResourceId(                com.android.internal.R.styleable.Window_windowAnimationStyle, 0);    }    // The rest are only done if this window is not embedded; otherwise,    // the values are inherited from our container.    if (getContainer() == null) {        if (mBackgroundDrawable == null) {            if (mBackgroundResource == 0) {                mBackgroundResource = a.getResourceId(                        com.android.internal.R.styleable.Window_windowBackground, 0);            }            if (mFrameResource == 0) {                mFrameResource = a.getResourceId(com.android.internal.R.styleable.Window_windowFrame, 0);            }            if (false) {                System.out.println("Background: "                        + Integer.toHexString(mBackgroundResource) + " Frame: "                        + Integer.toHexString(mFrameResource));            }        }        mTextColor = a.getColor(com.android.internal.R.styleable.Window_textColor, 0xFF000000);    }     //2. 填充窗口的decorView    // Inflate the window decor.     //2.1 根据窗口的属性,找到需要layout的resourceId    int layoutResource;    int features = getLocalFeatures();    // System.out.println("Features: 0x" + Integer.toHexString(features));    if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {        if (mIsFloating) {            layoutResource = com.android.internal.R.layout.dialog_title_icons;        } else {            layoutResource = com.android.internal.R.layout.screen_title_icons;        }        // System.out.println("Title Icons!");    } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0) {        // Special case for a window with only a progress bar (and title).        // XXX Need to have a no-title version of embedded windows.        layoutResource = com.android.internal.R.layout.screen_progress;        // System.out.println("Progress!");    } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {        // Special case for a window with a custom title.        // If the window is floating, we need a dialog layout        if (mIsFloating) {            layoutResource = com.android.internal.R.layout.dialog_custom_title;        } else {            layoutResource = com.android.internal.R.layout.screen_custom_title;        }    } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {        // If no other features and not embedded, only need a title.        // If the window is floating, we need a dialog layout        if (mIsFloating) {            layoutResource = com.android.internal.R.layout.dialog_title;        } else {            layoutResource = com.android.internal.R.layout.screen_title;        }        // System.out.println("Title!");    } else {        // Embedded, so no decoration is needed.        layoutResource = com.android.internal.R.layout.screen_simple;        // System.out.println("Simple!");    }     //2.2 通知Decor正在更改    mDecor.startChanging();     //2.3 给decorView添加全屏的子view    View in = mLayoutInflater.inflate(layoutResource, null);    decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);    if (contentParent == null) {        throw new RuntimeException("Window couldn't find content container view");    }    if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {        ProgressBar progress = getCircularProgressBar(false);        if (progress != null) {            progress.setIndeterminate(true);        }    }      //2.4 填充DecorView的backgroud和title,在DecorView作为顶级窗口时    // Remaining setup -- of background and title -- that only applies    // to top-level windows.    if (getContainer() == null) {        Drawable drawable = mBackgroundDrawable;        if (mBackgroundResource != 0) {            drawable = getContext().getResources().getDrawable(mBackgroundResource);        }        mDecor.setWindowBackground(drawable);        drawable = null;        if (mFrameResource != 0) {            drawable = getContext().getResources().getDrawable(mFrameResource);        }        mDecor.setWindowFrame(drawable);        ......        if (mTitleColor == 0) {            mTitleColor = mTextColor;        }        if (mTitle != null) {            setTitle(mTitle);        }        setTitleColor(mTitleColor);    }     //2.5 通知DecorView,更改完毕    mDecor.finishChanging();    return contentParent;}

上述操作中,总共做了几件事情:

  1. 设置了window的attrs,layoutParams的一些属性
  2. 填充窗口的decorView
    2.1 根据窗口的属性,找到需要layout的resourceId
    2.2 通知Decor正在更改
    2.3 给decorView添加全屏的子view,,并且ID为ID_ANDROID_CONTENT的作为contentParent
    2.4 填充DecorView的backgroud和title,在DecorView作为顶级窗口时
    2.5 通知DecorView,更改完毕

在这里时,DecorView已经有了自己的第一个孩子节点,孩子节点采用的那种布局,是根据我们窗口的类型来决定的
在标记decorView的开始更改时,只是做了一个标记
在设置结束更改时,即DecorView.finishChanging()时,做了很多操作,我们需要继续查看一下

DecorView.finishChanging()

 public void finishChanging() {        mChanging = false;        drawableChanged();    }

DecorView.drawableChanged()

    private void drawableChanged() {        if (mChanging) {            return;        }        setPadding(mFramePadding.left + mBackgroundPadding.left, mFramePadding.top                + mBackgroundPadding.top, mFramePadding.right + mBackgroundPadding.right,                mFramePadding.bottom + mBackgroundPadding.bottom);        requestLayout();        invalidate();        int opacity = PixelFormat.OPAQUE;        // Note: if there is no background, we will assume opaque. The        // common case seems to be that an application sets there to be        // no background so it can draw everything itself. For that,        // we would like to assume OPAQUE and let the app force it to        // the slower TRANSLUCENT mode if that is really what it wants.        Drawable bg = getBackground();        Drawable fg = getForeground();        if (bg != null) {            if (fg == null) {                opacity = bg.getOpacity();            } else if (mFramePadding.left <= 0 && mFramePadding.top <= 0                    && mFramePadding.right <= 0 && mFramePadding.bottom <= 0) {                // If the frame padding is zero, then we can be opaque                // if either the frame -or- the background is opaque.                int fop = fg.getOpacity();                int bop = bg.getOpacity();                if (Config.LOGV)                    Log.v(TAG, "Background opacity: " + bop + ", Frame opacity: " + fop);                if (fop == PixelFormat.OPAQUE || bop == PixelFormat.OPAQUE) {                    opacity = PixelFormat.OPAQUE;                } else if (fop == PixelFormat.UNKNOWN) {                    opacity = bop;                } else if (bop == PixelFormat.UNKNOWN) {                    opacity = fop;                } else {                    opacity = Drawable.resolveOpacity(fop, bop);                }            } else {                // For now we have to assume translucent if there is a                // frame with padding... there is no way to tell if the                // frame and background together will draw all pixels.                if (Config.LOGV)                    Log.v(TAG, "Padding: " + mFramePadding);                opacity = PixelFormat.TRANSLUCENT;            }        }        if (Config.LOGV)            Log.v(TAG, "Background: " + bg + ", Frame: " + fg);        if (Config.LOGV)            Log.v(TAG, "Selected default opacity: " + opacity);        mDefaultOpacity = opacity;        if (mFeatureId < 0) {            setDefaultWindowFormat(opacity);        }    }
  1. 根据在generateLayout时,我们设置的属性,backGround,forceground,设置了DecorView的padding值
  2. requestLayout()
  3. invalidate()
  4. 设置了窗口的mDefaultOpacity

在这里我们关心的是,此时已经有了requestLayout和invalidate的操作

到此处,installDecor的部分已经结束

小总结一下

  1. 创建了DecorView
  2. 设置了Window的相关属性
  3. 给DecorView添加了一个全屏的孩子节点,并且其ID为ID_ANDROID_CONTENT的作为mContentParent
  4. 根据设置的window的属性,给DecorView设置对应的padding数值
  5. DecorView requestLayout和invalidate了
  6. 假如DecorView中,需要设置title,会在此时将title也给设置
  7. 向Activity通知onContentChanged()

此时已经可以发现:

  1. Activity的setContentView其实是交给PhoneWindow来处理的,PhoneWindow负责生成了DecorView,并且给DecorView进行各种处理

这样看来PhoneWindow相关的类是作为DecorView和Activity的桥梁了,先这样的猜测一下.

ActivityThread调用的handleResumeActivity

ActivityThread.handleResumeActivity()

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {      //1. 执行resume的操作    ActivityClientRecord r = performResumeActivity(token, clearHide);    if (r != null) {        final Activity a = r.activity;        //......        final int forwardBit = isForward ?                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;        //2. 假如window还没有添加到WindowManager上,并且这个activity没有finish自己或者启动其他的Actiivty,那么添加到windowManager中        // If the window hasn't yet been added to the window manager,        // and this guy didn't finish itself or start another activity,        // then go ahead and add the window.        boolean willBeVisible = !a.mStartedActivity;        if (!willBeVisible) {            try {                willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(                        a.getActivityToken());            } catch (RemoteException e) {            }        }        if (r.window == null && !a.mFinished && willBeVisible) {            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;            if (a.mVisibleFromClient) {                a.mWindowAdded = true;                wm.addView(decor, l);            }        // If the window has already been added, but during resume        // we started another activity, then don't yet make the        // window visible.        } else if (!willBeVisible) {            if (localLOGV) Slog.v(                TAG, "Launch " + r + " mStartedActivity set");            r.hideForNow = true;        }          //3. window现在是可见的,并且已经添加了, 现在启动其他的activity(???)        // The window is now visible if it has been added, we are not        // simply finishing, and we are not starting another activity.        if (!r.activity.mFinished && willBeVisible                && r.activity.mDecor != null && !r.hideForNow) {            if (r.newConfig != null) {                ......                performConfigurationChanged(r.activity, r.newConfig);                r.newConfig = null;            }            ......            WindowManager.LayoutParams l = r.window.getAttributes();            if ((l.softInputMode                    & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)                    != forwardBit) {                l.softInputMode = (l.softInputMode                        & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))                        | forwardBit;                if (r.activity.mVisibleFromClient) {                    ViewManager wm = a.getWindowManager();                    View decor = r.window.getDecorView();                    wm.updateViewLayout(decor, l);                }            }            r.activity.mVisibleFromServer = true;            mNumVisibleActivities++;            if (r.activity.mVisibleFromClient) {                r.activity.makeVisible();            }        }        r.nextIdle = mNewActivities;        mNewActivities = r;        if (localLOGV) Slog.v(            TAG, "Scheduling idle handler for " + r);        Looper.myQueue().addIdleHandler(new Idler());    } else {        // If an exception was thrown when trying to resume, then        // just end this activity.        try {            ActivityManagerNative.getDefault()                .finishActivity(token, Activity.RESULT_CANCELED, null);        } catch (RemoteException ex) {        }    }}
  1. 执行resume的操作
  2. 假如window还没有添加到WindowManager上,并且这个activity没有finish自己或者启动其他的Actiivty,那么添加到windowManager中
  3. 其他操作
  4. 通知activity makeVisible()

我们关注的点,现在在第二步上,因为会涉及到WindowManager上,添加这个view,另外也会涉及到第四步,makeVisible的部分

WindowManager的addView的相关操作

 ......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;if (a.mVisibleFromClient) {    a.mWindowAdded = true;    wm.addView(decor, l);} ......
  1. 先将Decor设置为了invisible
  2. 给Activity设置DecorView为window中构造的DecorView
  3. 如果是client可见的,那么给我们构建的LocalWindowManager中添加这个decorView,layoutParams使用的是window的attributes

那么现在的有效部分便是最后的wm.addView(decor,l)的过程

Window.LocalWindowManager.addView()

    public final void addView(View view, ViewGroup.LayoutParams params) {        // Let this throw an exception on a bad params.        WindowManager.LayoutParams wp = (WindowManager.LayoutParams)params;        CharSequence curTitle = wp.getTitle();        if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&            wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {            if (wp.token == null) {                View decor = peekDecorView();                if (decor != null) {                    wp.token = decor.getWindowToken();                }            }            if (curTitle == null || curTitle.length() == 0) {                String title;                if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA) {                    title="Media";                } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY) {                    title="MediaOvr";                } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {                    title="Panel";                } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL) {                    title="SubPanel";                } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG) {                    title="AtchDlg";                } else {                    title=Integer.toString(wp.type);                }                if (mAppName != null) {                    title += ":" + mAppName;                }                wp.setTitle(title);            }        } else {            if (wp.token == null) {                wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;            }            if ((curTitle == null || curTitle.length() == 0)                    && mAppName != null) {                wp.setTitle(mAppName);            }       }        if (wp.packageName == null) {            wp.packageName = mContext.getPackageName();        }        mWindowManager.addView(view, params);    }
  1. 窗口如果是subWindow中,title进行获取和设置,token使用的是DecorView的token
  2. 窗口不是subWindow,则使用appToken
  3. 如果wp.packageName为null,获取到context的packageName进行赋值
  4. 调用代理的windowManager,即WindowManagerImpl进行addView的操作

    WindowManager.addView()

    public void addView(View view, ViewGroup.LayoutParams params)
    {
    addView(view, params, false);
    }

WindowManager.addView() 实现的方法

private void addView(View view, ViewGroup.LayoutParams params, boolean nest){      ......    final WindowManager.LayoutParams wparams            = (WindowManager.LayoutParams)params;    ViewRoot root;    View panelParentView = null;    synchronized (this) {        //1. 解决奇葩的场景,多次添加view的场景,暂时不考虑        // Here's an odd/questionable case: if someone tries to add a        // view multiple times, then we simply bump up a nesting count        // and they need to remove the view the corresponding number of        // times to have it actually removed from the window manager.        // This is useful specifically for the notification manager,        // which can continually add/remove the same view as a        // notification gets updated.        int index = findViewLocked(view, false);        if (index >= 0) {            if (!nest) {                throw new IllegalStateException("View " + view                        + " has already been added to the window manager.");            }            root = mRoots[index];            root.mAddNesting++;            // Update layout parameters.            view.setLayoutParams(wparams);            root.setLayoutParams(wparams, true);            return;        }        //2. 如果是panelWindow,找到panelWindow的parentView        // If this is a panel window, then find the window it is being        // attached to for future reference.        if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&                wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {            final int count = mViews != null ? mViews.length : 0;            for (int i=0; i<count; i++) {                if (mRoots[i].mWindow.asBinder() == wparams.token) {                    panelParentView = mViews[i];                }            }        }        //3. 创建viewRoot        root = new ViewRoot(view.getContext());        root.mAddNesting = 1;        view.setLayoutParams(wparams);        //4. 将viewRoot和view相关信息保存到WindowManagerImpl中        if (mViews == null) {            index = 1;            mViews = new View[1];            mRoots = new ViewRoot[1];            mParams = new WindowManager.LayoutParams[1];        } else {            index = mViews.length + 1;            Object[] old = mViews;            mViews = new View[index];            System.arraycopy(old, 0, mViews, 0, index-1);            old = mRoots;            mRoots = new ViewRoot[index];            System.arraycopy(old, 0, mRoots, 0, index-1);            old = mParams;            mParams = new WindowManager.LayoutParams[index];            System.arraycopy(old, 0, mParams, 0, index-1);        }        index--;        mViews[index] = view;        mRoots[index] = root;        mParams[index] = wparams;    }    //5. 给viewRoot设置view和相关参数    // do this last because it fires off messages to start doing things    root.setView(view, wparams, panelParentView);}
  1. 解决奇葩的场景,多次添加view的场景,暂时不考虑
  2. 如果是panelWindow,找到panelWindow的parentView
  3. 创建viewRoot,设置mAddNesting的数量为1
  4. 将viewRoot和view相关信息保存到WindowManagerImpl中
  5. 给viewRoot设置view和相关参数

目前对于我们寻找view系统的结构有关的信息,位于3.viewRoot的创建和5.给viewRoot设置view和相关参数

ViewRoot相关结构

先可以大体的看下ViewRoot的结构
发现是一些dispatch和Surface相关的内容,其实看到这里,我们就看到了View体系的中央枢纽了

ViewRoot的继承结构

public final class ViewRoot extends Handler implements ViewParent,    View.AttachInfo.Callbacks {    ......    }

handler的继承类,同样也实现了ViewParent,还有View.AttachInfo.Callbacks的接口

ViewRoot的构建

public ViewRoot(Context context) {    super();    if (MEASURE_LATENCY && lt == null) {        lt = new LatencyTimer(100, 1000);    }    // For debug only    //++sInstanceCount;     //1. 初始化windowSession,但是在系统启动时Zygote进程已经启动了    // Initialize the statics when this class is first instantiated. This is    // done here instead of in the static block because Zygote does not    // allow the spawning of threads.    getWindowSession(context.getMainLooper());    mThread = Thread.currentThread();    mLocation = new WindowLeaked(null);    mLocation.fillInStackTrace();    mWidth = -1;    mHeight = -1;    mDirty = new Rect();    mTempRect = new Rect();    mVisRect = new Rect();    mWinFrame = new Rect();    //2. mWindow的创建    mWindow = new W(this, context);    mInputMethodCallback = new InputMethodCallback(this);    mViewVisibility = View.GONE;    mTransparentRegion = new Region();    mPreviousTransparentRegion = new Region();    mFirst = true; // true for the first time the view is added    mAdded = false;    mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);    mViewConfiguration = ViewConfiguration.get(context);    mDensity = context.getResources().getDisplayMetrics().densityDpi;}

有两个比较关键的信息

  1. 初始化WindowSession,但是在系统启动时Zygote进程已经启动,但是我们还是需要知道联系的
  2. mWindow的创建

ViewRoot.getWindowSession()

 public static IWindowSession getWindowSession(Looper mainLooper) {    synchronized (mStaticInit) {        if (!mInitialized) {            try {                InputMethodManager imm = InputMethodManager.getInstance(mainLooper);                sWindowSession = IWindowManager.Stub.asInterface(                        ServiceManager.getService("window"))                        .openSession(imm.getClient(), imm.getInputContext());                mInitialized = true;            } catch (RemoteException e) {            }        }        return sWindowSession;    }}
  1. 在没有初始化时,根据mainLooper,得到InputMethodManager的实例imm
  2. 通过imm的相关变量和IWindowManager的binder方式,获取到WindowSession,并且设置为mWindowSession
  3. 设置为已经初始化

mWindowSession是一个重要的对象,接下来我们会看到,WindowSession作为ViewRoot主动请求Wms的Binder代理类

ViewRoot.W类的介绍

static class W extends IWindow.Stub {    private final WeakReference<ViewRoot> mViewRoot;    public W(ViewRoot viewRoot, Context context) {        mViewRoot = new WeakReference<ViewRoot>(viewRoot);    }    ......}

W类作为IWindow.Stub的子类,一般看到这里,大概可以猜测到,是作为Window的callback方式来存在的.

ViewRoot.setView()

 /** * We have one child */public void setView(View view, WindowManager.LayoutParams attrs,        View panelParentView) {    synchronized (this) {        if (mView == null) {            mView = view;            mWindowAttributes.copyFrom(attrs);            attrs = mWindowAttributes;            if (view instanceof RootViewSurfaceTaker) {                mSurfaceHolderCallback =                        ((RootViewSurfaceTaker)view).willYouTakeTheSurface();                if (mSurfaceHolderCallback != null) {                    mSurfaceHolder = new TakenSurfaceHolder();                    mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);                }            }            Resources resources = mView.getContext().getResources();            CompatibilityInfo compatibilityInfo = resources.getCompatibilityInfo();            mTranslator = compatibilityInfo.getTranslator();            if (mTranslator != null || !compatibilityInfo.supportsScreen()) {                mSurface.setCompatibleDisplayMetrics(resources.getDisplayMetrics(),                        mTranslator);            }            boolean restore = false;            if (mTranslator != null) {                restore = true;                attrs.backup();                mTranslator.translateWindowLayout(attrs);            }            ......            if (!compatibilityInfo.supportsScreen()) {                attrs.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;            }            mSoftInputMode = attrs.softInputMode;            mWindowAttributesChanged = true;            mAttachInfo.mRootView = view;            mAttachInfo.mScalingRequired = mTranslator != null;            mAttachInfo.mApplicationScale =                    mTranslator == null ? 1.0f : mTranslator.applicationScale;            if (panelParentView != null) {                mAttachInfo.mPanelParentWindowToken                        = panelParentView.getApplicationWindowToken();            }            mAdded = true;            int res; /* = WindowManagerImpl.ADD_OKAY; */            // Schedule the first layout -before- adding to the window            // manager, to make sure we do the relayout before receiving            // any other events from the system.            requestLayout();            mInputChannel = new InputChannel();            try {                res = sWindowSession.add(mWindow, mWindowAttributes,                        getHostVisibility(), mAttachInfo.mContentInsets,                        mInputChannel);            } catch (RemoteException e) {                mAdded = false;                mView = null;                mAttachInfo.mRootView = null;                mInputChannel = null;                unscheduleTraversals();                throw new RuntimeException("Adding window failed", e);            } finally {                if (restore) {                    attrs.restore();                }            }            if (mTranslator != null) {                mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);            }            mPendingContentInsets.set(mAttachInfo.mContentInsets);            mPendingVisibleInsets.set(0, 0, 0, 0);            if (Config.LOGV) Log.v(TAG, "Added window " + mWindow);            if (res < WindowManagerImpl.ADD_OKAY) {//handle exception               ......            }            if (view instanceof RootViewSurfaceTaker) {                mInputQueueCallback =                    ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();            }            if (mInputQueueCallback != null) {                mInputQueue = new InputQueue(mInputChannel);                mInputQueueCallback.onInputQueueCreated(mInputQueue);            } else {                InputQueue.registerInputChannel(mInputChannel, mInputHandler,                        Looper.myQueue());            }            view.assignParent(this);            mAddedTouchMode = (res&WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE) != 0;            mAppVisible = (res&WindowManagerImpl.ADD_FLAG_APP_VISIBLE) != 0;        }    }}
  1. mAdded设置为true
  2. requsetLayout
  3. 创建了inputChannel
  4. 通过mWindowSession,将窗口添加到了Wms的管理中,其中callback为我们上面看到的ViewRoot.类
  5. 如果InputQueueCallback不为null,那么就创建对应的InputQuue,并且主动调用callback,onInputQueueCreated;如果为null,那么直接给InputQueue注册InputChannel,并且设置了mInputHandler.但是我们的ViewRoot的的返回的InputQueueCallback为null,因而是直接注册的
  6. 设置view的parent为this,即ViewRoot

在系统有了按键消息时,系统会通过Wms做自己的处理,如果Wms没有处理掉,便会通过ViewRoot.InputHandler来通知我们的ViewRoot来处理,即交给我们具体的app来处理这些消息

在系统有了触摸消息时,会通过InputQueue直接通知我们的app来做处理的,app知道这些事件也是通过ViewRoot.InputHandler感知的

小总结一下

到这里,大体的View相关的结构已经有了一个结果

Ams和Wms client的关系类图

  1. Activity通过attach,构建了Wms的client的相关类.
    一个Acvitiy会构建一个PhoneWindow,对应的管理器类是LocalWindowManager,而LocalWindowManager作为一个WindowManagerImpl的代理类存在的.

  2. Activity通过setContentView构建了对应的DecorView

  3. ActivityThread通过在handleResumeActivity时,判断view是否和Activity有直接关联,发现没有,便直接通过WindowManager的addView,通过几个过程,最终创建了ViewRoot,将decorView交给了Wms来管理
  4. 通过查看ViewRoot的相关代码,也发现ViewRoot是作为SurfaceFlinger,Wms,android事件分发的client的类,可以认作MVC中的controller类.

Activity.makeVisible()

 void makeVisible() {    if (!mWindowAdded) {        ViewManager wm = getWindowManager();        wm.addView(mDecor, getWindow().getAttributes());        mWindowAdded = true;    }    mDecor.setVisibility(View.VISIBLE);}

此时会将DecorView进行显示

ActivityThread的pause Activity的过程

todo

ActivityThread的stop Activity的过程

todo

ActivityThread的destroy Activity的过程

todo:

随想

1. Context的结构, 包装类的实现,与java中的BufferStream的实现原理没有什么区别的

2. Context的结构,带来Context数量计算的问题

有兴趣的可以看看ContextImpl的源码,真正干活的类,很多面试会问,一个应用中的Context如何计算,这个话题是应该有争论的,Activity算是Context,ContextImpl也是Context,Application也是Context,因为在不同状态下,系统的Context数量是不同的。

Application是Context,而且是包装类,因而是两个Context
Activity是Context,也是包装类,因而是两个Context
Service是Context的包装类,因而是两个。

假如应用只有单进程,那么现在活动的 (Activity+Service ) * 2 + 2(application的) = 真正的个数
而如果是多进程,那么同样是所有相关进程的(Activity+Service+Application个数)* 2 = 真正的个数

3. View的层级结构

从目前已知的结构上来看,View相关的结构如下:

  1. ViewRoot(并不是一个view,但是是ViewParent)(作为控制分发类)

  2. DecorView(作为View具体的控制分发的起始点,包括Activity,PhoneWindow,以及View的结构体系)

  3. ContentView(根据theme不同,contentview可能不同)

  4. our Layout view(3和4之间,根据theme不同,可能会有差异)

4. 两个Activity之间的生命周期的关系

Activity A 按照普通模式启动ActivityB,并且ActiivtyB也是为标准的Activity模式时,生命周期的流程

在最开始我们也提到了,正常来讲应该是这样的

  1. ActivityA onPause()
  2. ActivityB onCreate()
  3. ActivityB onStart()
  4. ActivityB onResume()
  5. ActiivtyA onStop()

其实问这个问题的目的是在于,我们有可能会存在跨Activity时,我们假如需要存到内存或者其他地方时,数据可能会存在状态的问题,因为ActivityA的onStop()是在ActivityB已经resume之后,才会调用的(注意这是正常情况,假如ActivityB中发生了一些耗时操作,那么可能是不一定的,因为ActivityA的onStop()是在Ams的handler中10sdelay后做的检查操作)

0 0
原创粉丝点击