基于Android 2.3.7 源码分析
在分析android的事件分发之前,还需要了解一些内容,那就是Ams与Wms的关联,这里目前指的是client端的关联
目前的分析流程根据ActivityThread的过程即可
上篇中已经提到了大体的流程,现在这几个流程细化一些: 同一个应用中,Actiivty activityA正常模式启动一个activityB的流程
Ams通知pauseActivityAActivityThread在收到pause后(ActivityThread.handlePauseActivity()),做对应的操作后,通知Ams,已经pauseAms在收到通知后,记录下这些信息,然后通知ActivityThread启动下一个Activity,activityB,并且自己发送Handler的10ms的delay通知,到了之后,检查是否要通知stop activity端上在收到Ams的启动通知后(ActivityThread.handleLauncheActivity())后,便通知Activity进行启动相关详细文章,可参照老罗的android 之旅
上面罗列的几个细节点,在启动Activity时,会调用ActivityThread.handleLauncheActiivty,在要停止运行时,会逐步通知,先ActvityThread的handlePauseActivity,然后会ActivityThread.handleStopActivity(),在端上主动调用finish时,经过Ams的处理,最终会通知ActivityThread进行handleDestroyActivity的操作,在操作完成后,会通知Ams,Activity已经销毁.
根据这几个过程,我们会找到我们想要的事件分发的相关类 汇总流程
ActivityThread.handleLaunchActivityActivityThread.handlePauseActivityActivityThread.handleStopActivityActivity.handleDestroyActivityandroid.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); } ...... } 组装了Client的package的信息调用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) { } } }查看代码,得知,做了两件事情
调用performLaunchActivity()如果返回的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; } 根据反射,构造Activity获取到Application构造ContextImpl,并且初始化将ContextImpl等信息,attach到Activity通过Instrument 通知Activity进行onCreate()(相关实现可以查看instrumentation中的callActiivtyOnCreate)通知Activity进行start如果有state信息,通知Activity进行OnRestoreInstanceState通知Activity进行onPostCreate记录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) { } } } 执行performResumeActivityViewManager中添加decorViewupdateViewLayout假如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; }我们启动时,clearHide是false,并且是首次启动,因而不会做deliverResults以及deliverResults的操作,只会做activity的performResume操作,并且设置paused,stopped,state为null
将Activity进行attach()
将Activity进行onCreate()将Activity进行onStart()将Activity进行postOnCreate()将Activity进行onResume通知Activity进行start跟我们相关的其实只有三个过程
Activity的attach过程Activity的onCreate()过程ActivityThread调用的handleResumeActivity中的windowManager.addView()和updateLayout的过程那么接下来就看这几个过程
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; } attach了baseActivity,这是在ActivityThread中创建的ContextImpl,然后Activity attachBase后,这个便是ContextWrapper中的mBase构建了Window,并且设置callback为当前的activity将ActivityThread传递的参数,给当前activity进行赋值给mWindow设置windowmanager设置当前的windowManager为mWindow中get的windowManager这里面看似简单,其实信息量很多,我们逐个分析
在上篇中的图中,已经提到了Context的类结构,从这里的attach,也可以context的结构
Activity虽然继承Context,但是只是作为一个包装的继承类,方便了我们与真正的Context: ContextImpl进行交互,再次截图如下:
可以以activity的getSystemService为例,查看相关的源码,在activity中直接引用的,则直接返回对应的service,否则,便通过attach的baseContext()进行获取
Activity.getSystemService()
@Override public 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,然后给window设置了callback为当前的activity,然后设置了一个输入法模式
一步一步来看
PolicyManager.makeNewWindow()
// The static methods to spawn new policy-specific objects public 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是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; }小总结一下:
经过上面两个步骤:做到了以下几点:
构建了一个PhoneWindow将PhoneWindow的callback设置为当前的Activity
PhoneWindow是什么,接下来我们继续看,PhoneWindow和WindowManager是否有关系,答案是肯定的,但是WindowManagerService是否管理的就是我们说的PhoneWindow,有关系,但是无直接关系。
我们继续看
记录了thread,instrumenttation,token,application,intent,activityInfo和title,parentActivity等信息,知道即可
我们的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); } 保存了appToken,appName如果wm为null,获取默认的WindowManager根据wm,构建一个local的WindowManager由于我们传过来的wm是null,因而是直接获取的WindowManagerImpl,根据这个wm,构建的LocalWindowManager.
在这里停一下,查看下对应的实现
WindowManager的结构
我们先大体的看一下,类是用来做什么的,以及LocalWindowManager和WindowManagerImpl之间的关系
LocalWindoManager
翻看其源码,看到,其实没有做太多的事情
实现了WindowManager的接口在构造时,传过来了一个WindowManager方法的调用也不多,看到是用来和构造时传递来的WindowManager交互的代理从这里就发现了,其实LocalWindowManager可以认为是WindowManager的代理类,但是其中也包含了一些自己的逻辑,比如说addView时的逻辑
WindowManagerImpl
翻看其源码,发现做的事情如下:
实现了WindowManager的接口这里具体的实现了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相关类图如下:
设置Activity中使用的windowManager为我们创建的LocalWindowManager
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中的实现,是很有帮助的.
在Activity的onCreate中,我们是可以调用finish()方法的,假如说调用了finish()方法,那么Activity的生命周期中的其他方法是不会调用的,这个我们自己可以看下Activity的finish()方法做了什么,以及在ActivityThread.performLaunchActivity()时,在通知Activity onCreate后,会做什么判断在这里通常是我们做事情的开始,setContentView(),findViewById(),以及数据的初始化savedInstanceState,假如说activity因而内存不够用,而被finish(),我们可以获取一些信息假如在我们继承的Activity中,没有调用这个Activity.onCreate()即基类的方法,那么会直接抛出异常的,异常的处理是在Activity的performLaunchActivity中
其实看了这些,发现是不能和Window关联起来的,因而在此处我们会setContentView(),这个方法我们还是要看看具体的实现的.
Activity.setContentView()
/**
Set the activity content from a layout resource. The resource will beinflated, 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()
@Override public void setContentView(int layoutResID) { if (mContentParent == null) { installDecor(); } else { mContentParent.removeAllViews(); } mLayoutInflater.inflate(layoutResID, mContentParent); final Callback cb = getCallback(); if (cb != null) { cb.onContentChanged(); } } 判断contentParent是否为null,是null,安装decor如果不是null,删除所有的view采用构造时初始化的mLayoutInflater填充layoutResId获得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); } } } } 判断mDecor是否为null,为null,创建Decor,并且设置相关属性判断mContentParent是否为null,为null,则构建mContentParent,并且根据是否是no_title,设置title的值那么还是老规矩,一步一步来:
PhoneWindow.generateDecor()
protected DecorView generateDecor() { return new DecorView(getContext(), -1); }也就是构建了一个DecorView,千呼万唤始出来的一个类,这个是个核心的类,目前我们也先瞅瞅他,到底有何特殊之处,导致她如此核心
大体瞅上几眼,发现如下的内容
继承了FrameLayout复写了常用的事件分发的方法,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; }上述操作中,总共做了几件事情:
设置了window的attrs,layoutParams的一些属性填充窗口的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); } } 根据在generateLayout时,我们设置的属性,backGround,forceground,设置了DecorView的padding值requestLayout()invalidate()设置了窗口的mDefaultOpacity在这里我们关心的是,此时已经有了requestLayout和invalidate的操作
到此处,installDecor的部分已经结束
小总结一下
创建了DecorView设置了Window的相关属性给DecorView添加了一个全屏的孩子节点,并且其ID为ID_ANDROID_CONTENT的作为mContentParent根据设置的window的属性,给DecorView设置对应的padding数值DecorView requestLayout和invalidate了假如DecorView中,需要设置title,会在此时将title也给设置向Activity通知onContentChanged()此时已经可以发现:
Activity的setContentView其实是交给PhoneWindow来处理的,PhoneWindow负责生成了DecorView,并且给DecorView进行各种处理这样看来PhoneWindow相关的类是作为DecorView和Activity的桥梁了,先这样的猜测一下.
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) { } } } 执行resume的操作假如window还没有添加到WindowManager上,并且这个activity没有finish自己或者启动其他的Actiivty,那么添加到windowManager中 其他操作 通知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); } ...... 先将Decor设置为了invisible给Activity设置DecorView为window中构造的DecorView如果是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); } 窗口如果是subWindow中,title进行获取和设置,token使用的是DecorView的token窗口不是subWindow,则使用appToken如果wp.packageName为null,获取到context的packageName进行赋值调用代理的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); } 解决奇葩的场景,多次添加view的场景,暂时不考虑如果是panelWindow,找到panelWindow的parentView创建viewRoot,设置mAddNesting的数量为1将viewRoot和view相关信息保存到WindowManagerImpl中给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; }有两个比较关键的信息
初始化WindowSession,但是在系统启动时Zygote进程已经启动,但是我们还是需要知道联系的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; } } 在没有初始化时,根据mainLooper,得到InputMethodManager的实例imm通过imm的相关变量和IWindowManager的binder方式,获取到WindowSession,并且设置为mWindowSession设置为已经初始化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; } } } mAdded设置为truerequsetLayout创建了inputChannel通过mWindowSession,将窗口添加到了Wms的管理中,其中callback为我们上面看到的ViewRoot.类如果InputQueueCallback不为null,那么就创建对应的InputQuue,并且主动调用callback,onInputQueueCreated;如果为null,那么直接给InputQueue注册InputChannel,并且设置了mInputHandler.但是我们的ViewRoot的的返回的InputQueueCallback为null,因而是直接注册的设置view的parent为this,即ViewRoot在系统有了按键消息时,系统会通过Wms做自己的处理,如果Wms没有处理掉,便会通过ViewRoot.InputHandler来通知我们的ViewRoot来处理,即交给我们具体的app来处理这些消息
在系统有了触摸消息时,会通过InputQueue直接通知我们的app来做处理的,app知道这些事件也是通过ViewRoot.InputHandler感知的
小总结一下
到这里,大体的View相关的结构已经有了一个结果
Activity通过attach,构建了Wms的client的相关类. 一个Acvitiy会构建一个PhoneWindow,对应的管理器类是LocalWindowManager,而LocalWindowManager作为一个WindowManagerImpl的代理类存在的.
Activity通过setContentView构建了对应的DecorView
ActivityThread通过在handleResumeActivity时,判断view是否和Activity有直接关联,发现没有,便直接通过WindowManager的addView,通过几个过程,最终创建了ViewRoot,将decorView交给了Wms来管理通过查看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进行显示
todo
todo
todo:
有兴趣的可以看看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 = 真正的个数
从目前已知的结构上来看,View相关的结构如下:
ViewRoot(并不是一个view,但是是ViewParent)(作为控制分发类)
DecorView(作为View具体的控制分发的起始点,包括Activity,PhoneWindow,以及View的结构体系)
ContentView(根据theme不同,contentview可能不同)
our Layout view(3和4之间,根据theme不同,可能会有差异)
Activity A 按照普通模式启动ActivityB,并且ActiivtyB也是为标准的Activity模式时,生命周期的流程
在最开始我们也提到了,正常来讲应该是这样的
ActivityA onPause()ActivityB onCreate()ActivityB onStart()ActivityB onResume()ActiivtyA onStop()其实问这个问题的目的是在于,我们有可能会存在跨Activity时,我们假如需要存到内存或者其他地方时,数据可能会存在状态的问题,因为ActivityA的onStop()是在ActivityB已经resume之后,才会调用的(注意这是正常情况,假如ActivityB中发生了一些耗时操作,那么可能是不一定的,因为ActivityA的onStop()是在Ams的handler中10sdelay后做的检查操作)