Activity启动及窗口创建过程详解
2015-01-27 19:08
387 查看
有这么一个网站,能通过web方式查看Android源码.在你需要的时候,本地又没有源码的时候,通过这个网站可以很方便的查看到源码
网站地址:http://grepcode.com/project/repository.grepcode.com/java/ext/com.google.android/android
以前一直都说Activity的人口是onCreate方法。其实android上一个应用的入口,应该是ActivityThread。和普通的java类一样,入口是一个main方法。
任何的apk有且仅有一个ActivityThread类,该类为应用程序的主线程类。
ActivityThread其实就是我们经常说的UI thread,也就是主线程。我们都知道主线程可以使用Handler进行异步通信,因为主线程中已经创建了Looper,而这个Looper就是在这里创建的。如果其他线程需要使用Handler通信,就要自己去创建Looper。
创建一个Handler。
ActivityThread thread = new ActivityThread();
创建ActivityThread 对象。
ActivityThread 有几个比较重要的成员变量,会在创建ActivityThread对象时初始化。
(1)final ApplicationThread mAppThread = new ApplicationThread();
ApplicationThread继承自ApplicationThreadNative, 而ApplicationThreadNative又继承自Binder并实现了IApplicationThread接口。IApplicationThread继承自IInterface。这是一个很明显的binder结构,用于于Ams通信。IApplicationThread接口定义了对一个程序(linux的进程)操作的接口。ApplicationThread通过binder与Ams通信,并将Ams的调用,通过下面的H类(也就是Hnalder)将消息发送到消息队列,然后进行相应的操作,入activity的start,
stop。
(2)final H mH = new H();
private final class H extends Handler
mH负责处理ApplicationThread发送到消息队列的消息,例如:
从名字中就可以看出,这里就将进行启动activity的工作了。
方法中主要调用了这一句:
Activity a = performLaunchActivity(r, customIntent);
(1)进行了一些初始化和赋值操作后,创建activity。
以上代码中使用ClassLoader从程序中加载指定的activity对应的class文件
(2)然后调用:
attach的作用就是为刚构造好的Activity设置内部变量,还有一个主要的工作就是创建Window对象
(3)创建好Window对象后,给Window对象的mWindowManager对象赋值
接下来看setWindowManager在 Window.java里面
搞清楚了wm参数之后再看LocalWindowManager在Window.java中
实现WindowManager这个interface的有两个类,一个是LocalWindowManager,一个是WindowManagerImpl,
而LocalWindowManager只是一个壳而已,真正实现功能的是实现WindowManager这个interface的WindowManagerImpl类。
还是在ActivityThread.java中performLaunchActivity方法里面
这一句就会调用到acitivity的onCreate方法了,就进入了大多数应用开发的入口了。
在Activity.java中可以看到
getWindow()返回的是一个PhoneWindow类,接下来看PhoneWindow.java
关键是在下面
generateLayout这个方法内容比多,截取其中最重要的几行
该方法会做如下事情:
根据窗口的风格修饰类型为该窗口选择不同的窗口布局文件(根视图),具体体现为代码中的代码中的layoutResource。这些窗口修饰布局文件指定一个用来存放Activity自定义布局文件的ViewGroup视图,一般为FrameLayout 其id 为: android:id="@android:id/content"。
例如窗口修饰类型包括FullScreen(全屏)、NoTitleBar(不含标题栏)等。选定窗口修饰类型有两种:
①、指定requestFeature()指定窗口修饰符,PhoneWindow对象调用getLocalFeature()方法获取值;
②、为我们的Activity配置相应属性,即android:theme=“”,PhoneWindow对象调用getWindowStyle()方法
获取值。
举例如下,隐藏标题栏有如下方法:requestWindowFeature(Window.FEATURE_NO_TITLE);
或者 为Activity配置xml属性:android:theme=”@android:style/Theme.NoTitleBar”。
PS:因此,在Activity中必须在setContentView之前调用requestFeature()方法。
确定好窗口风格之后,选定该风格对应的布局文件,这些布局文件位于 frameworks/base/core/res/layout/ ,
典型的窗口布局文件有:
R.layout.dialog_titile_icons
R.layout.screen_title_icons
R.layout.screen_progress
R.layout.dialog_custom_title
R.layout.dialog_title
R.layout.screen_title // 最常用的Activity窗口修饰布局文件
R.layout.screen_simple //全屏的Activity窗口布局文件
这样layoutResource的值确定了,contentParent即为@android:id/content对应的View,接下来就可以把应用中的layout.xml添加到mDecor中。具体是通过setContentView方法中 mLayoutInflater.inflate(layoutResID, mContentParent)这一句来实现的。
最后调用cb.onContentChanged()通知窗口内容发生改变。cb即为Activity本身,Activity实现了Window.CallBack接口,因为在之前Activity的attach()方法中mWindow.setCallback(this)
首先Activity准备好了会通知Ams,Ams经过一系列判断最终调用Activity的makeVisible方法
在上面的方法中,首先获得一个WindowManager对象,wm实际上就是Window.LocalWindowManager对象,该对象的addView方法第一个参数是DecroView对象即为一个Activity全部看的到的视图内容,第二个参数为Window初始化时默认构造的WindowManager.LayoutParams对象,具体代码在Window.java中如下
而WindowManager中的构造方法
综上可见创建的窗口类型为TYPE_APPLICATION,为应用窗口类型。而在LocalWindowManager的addView方法中会先检查第二个参数(WindowManager.LayoutParams类型,以下用params替代,即为代码中的wp)的值并给其内部变量token赋值,以便于添加
以上表示添加的为子窗口,如果token为空则把activity对应的窗口token赋值给params。
如果添加的不是子窗口则把mAppToken值赋值给params,若被父activity包含则把父activity的mAppToken赋值给params。
由此可以看出前面创建Window时,为什么mWindowManager对象是一个Window.LocalWindowManager对象而不是一个WindowManagerImpl对象。
前者比后者多了检查params.token的关卡。
网站地址:http://grepcode.com/project/repository.grepcode.com/java/ext/com.google.android/android
1. 应用的入口。
以前一直都说Activity的人口是onCreate方法。其实android上一个应用的入口,应该是ActivityThread。和普通的java类一样,入口是一个main方法。任何的apk有且仅有一个ActivityThread类,该类为应用程序的主线程类。
public static final void main(String[] args) { SamplingProfilerIntegration.start(); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); if (sMainThreadHandler == null) { sMainThreadHandler = new Handler(); } ActivityThread thread = new ActivityThread(); thread.attach(false); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); if (Process.supportsProcesses()) { throw new RuntimeException("Main thread loop unexpectedly exited"); } thread.detach(); String name = (thread.mInitialApplication != null) ? thread.mInitialApplication.getPackageName() : "<unknown>"; Slog.i(TAG, "Main thread of " + name + " is now exiting"); }下面仔细分析一下这个main方法。
1.1.Looper.prepareMainLooper();
ActivityThread其实就是我们经常说的UI thread,也就是主线程。我们都知道主线程可以使用Handler进行异步通信,因为主线程中已经创建了Looper,而这个Looper就是在这里创建的。如果其他线程需要使用Handler通信,就要自己去创建Looper。
1.2. sMainThreadHandler = new Handler();
创建一个Handler。ActivityThread thread = new ActivityThread();
创建ActivityThread 对象。
ActivityThread 有几个比较重要的成员变量,会在创建ActivityThread对象时初始化。
(1)final ApplicationThread mAppThread = new ApplicationThread();
ApplicationThread继承自ApplicationThreadNative, 而ApplicationThreadNative又继承自Binder并实现了IApplicationThread接口。IApplicationThread继承自IInterface。这是一个很明显的binder结构,用于于Ams通信。IApplicationThread接口定义了对一个程序(linux的进程)操作的接口。ApplicationThread通过binder与Ams通信,并将Ams的调用,通过下面的H类(也就是Hnalder)将消息发送到消息队列,然后进行相应的操作,入activity的start,
stop。
(2)final H mH = new H();
private final class H extends Handler
mH负责处理ApplicationThread发送到消息队列的消息,例如:
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; 。。。
1.3. handleLaunchActivity(r, null);
从名字中就可以看出,这里就将进行启动activity的工作了。方法中主要调用了这一句:
Activity a = performLaunchActivity(r, customIntent);
1.4. performLaunchActivity()
(1)进行了一些初始化和赋值操作后,创建activity。Activity activity = null; 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); } }
以上代码中使用ClassLoader从程序中加载指定的activity对应的class文件
(2)然后调用:
activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstance, r.lastNonConfigurationChildInstances, config);
attach的作用就是为刚构造好的Activity设置内部变量,还有一个主要的工作就是创建Window对象
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); 。。。
(3)创建好Window对象后,给Window对象的mWindowManager对象赋值
接下来看setWindowManager在 Window.java里面
public void setWindowManager(WindowManager wm, IBinder appToken, String appName) { mAppToken = appToken; mAppName = appName; if (wm == null) { wm = WindowManagerImpl.getDefault(); } mWindowManager = new LocalWindowManager(wm); }再进一步看 WindowManagerImpl.java
public static WindowManagerImpl getDefault() { return mWindowManager; }
private static WindowManagerImpl mWindowManager = new WindowManagerImpl();
搞清楚了wm参数之后再看LocalWindowManager在Window.java中
private class LocalWindowManager implements WindowManager { LocalWindowManager(WindowManager wm) { mWindowManager = wm; mDefaultDisplay = mContext.getResources().getDefaultDisplay( mWindowManager.getDefaultDisplay()); } 。。。
实现WindowManager这个interface的有两个类,一个是LocalWindowManager,一个是WindowManagerImpl,
而LocalWindowManager只是一个壳而已,真正实现功能的是实现WindowManager这个interface的WindowManagerImpl类。
2、配置好Activity和Window之后,接下来给窗口添加显示视图View或ViewGroup,
还是在ActivityThread.java中performLaunchActivity方法里面mInstrumentation.callActivityOnCreate(activity, r.state);
这一句就会调用到acitivity的onCreate方法了,就进入了大多数应用开发的入口了。
3、在activity的onCreate方法里面实际上又调用了其Window的方法
在Activity.java中可以看到public void setContentView(int layoutResID) { getWindow().setContentView(layoutResID); }
getWindow()返回的是一个PhoneWindow类,接下来看PhoneWindow.java
@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(); } }
关键是在下面
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); } } } }
protected DecorView generateDecor() { return new DecorView(getContext(), -1); }
generateLayout这个方法内容比多,截取其中最重要的几行
mDecor.startChanging(); 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"); }
该方法会做如下事情:
根据窗口的风格修饰类型为该窗口选择不同的窗口布局文件(根视图),具体体现为代码中的代码中的layoutResource。这些窗口修饰布局文件指定一个用来存放Activity自定义布局文件的ViewGroup视图,一般为FrameLayout 其id 为: android:id="@android:id/content"。
例如窗口修饰类型包括FullScreen(全屏)、NoTitleBar(不含标题栏)等。选定窗口修饰类型有两种:
①、指定requestFeature()指定窗口修饰符,PhoneWindow对象调用getLocalFeature()方法获取值;
②、为我们的Activity配置相应属性,即android:theme=“”,PhoneWindow对象调用getWindowStyle()方法
获取值。
举例如下,隐藏标题栏有如下方法:requestWindowFeature(Window.FEATURE_NO_TITLE);
或者 为Activity配置xml属性:android:theme=”@android:style/Theme.NoTitleBar”。
PS:因此,在Activity中必须在setContentView之前调用requestFeature()方法。
确定好窗口风格之后,选定该风格对应的布局文件,这些布局文件位于 frameworks/base/core/res/layout/ ,
典型的窗口布局文件有:
R.layout.dialog_titile_icons
R.layout.screen_title_icons
R.layout.screen_progress
R.layout.dialog_custom_title
R.layout.dialog_title
R.layout.screen_title // 最常用的Activity窗口修饰布局文件
R.layout.screen_simple //全屏的Activity窗口布局文件
这样layoutResource的值确定了,contentParent即为@android:id/content对应的View,接下来就可以把应用中的layout.xml添加到mDecor中。具体是通过setContentView方法中 mLayoutInflater.inflate(layoutResID, mContentParent)这一句来实现的。
最后调用cb.onContentChanged()通知窗口内容发生改变。cb即为Activity本身,Activity实现了Window.CallBack接口,因为在之前Activity的attach()方法中mWindow.setCallback(this)
4、Window类设置完视图之后,告诉Wms,Wms就把窗口显示在屏幕上了
首先Activity准备好了会通知Ams,Ams经过一系列判断最终调用Activity的makeVisible方法void makeVisible() { if (!mWindowAdded) { ViewManager wm = getWindowManager(); wm.addView(mDecor, getWindow().getAttributes()); mWindowAdded = true; } mDecor.setVisibility(View.VISIBLE); }
在上面的方法中,首先获得一个WindowManager对象,wm实际上就是Window.LocalWindowManager对象,该对象的addView方法第一个参数是DecroView对象即为一个Activity全部看的到的视图内容,第二个参数为Window初始化时默认构造的WindowManager.LayoutParams对象,具体代码在Window.java中如下
public final WindowManager.LayoutParams getAttributes() { return mWindowAttributes; }
// The current window attributes. private final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
而WindowManager中的构造方法
public LayoutParams() { super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); type = TYPE_APPLICATION; format = PixelFormat.OPAQUE; }
综上可见创建的窗口类型为TYPE_APPLICATION,为应用窗口类型。而在LocalWindowManager的addView方法中会先检查第二个参数(WindowManager.LayoutParams类型,以下用params替代,即为代码中的wp)的值并给其内部变量token赋值,以便于添加
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(); } }
以上表示添加的为子窗口,如果token为空则把activity对应的窗口token赋值给params。
如果添加的不是子窗口则把mAppToken值赋值给params,若被父activity包含则把父activity的mAppToken赋值给params。
if (wp.token == null) { wp.token = mContainer == null ? mAppToken : mContainer.mAppToken; }检查完params参数后,接下来就调用WindowManagerImpl的addView方法。
由此可以看出前面创建Window时,为什么mWindowManager对象是一个Window.LocalWindowManager对象而不是一个WindowManagerImpl对象。
前者比后者多了检查params.token的关卡。
相关文章推荐
- Activity启动及窗口创建过程详解
- Activity启动过程详解
- Android应用程序窗口(Activity)的窗口对象(Window)的创建过程分析
- Android应用程序窗口(Activity)的运行上下文环境(Context)的创建过程分析 .
- Android应用程序窗口(Activity)的绘图表面(Surface)的创建过程分析
- Android应用程序窗口(Activity)的绘图表面(Surface)的创建过程分析
- Android应用程序窗口(Activity)的运行上下文环境(Context)的创建过程分析
- Android应用程序窗口(Activity)的运行上下文环境(Context)的创建过程分析
- Android窗口管理服务WindowManagerService显示Activity组件的启动窗口(Starting Window)的过程分析
- Android应用程序窗口(Activity)的运行上下文环境(Context)的创建过程分析
- Android FrameWork——Activity启动过程详解
- Android应用程序窗口(Activity)的绘图表面(Surface)的创建过程分析
- Android应用程序窗口(Activity)的窗口对象(Window)的创建过程分析
- Android应用程序窗口(Activity)的运行上下文环境(Context)的创建过程分析
- Android应用程序窗口(Activity)的运行上下文环境(Context)的创建过程分析
- Android应用程序窗口(Activity)的视图对象(View)的创建过程分析
- Android应用程序窗口(Activity)的绘图表面(Surface)的创建过程分析
- Android应用程序窗口(Activity)的窗口对象(Window)的创建过程分析
- Android FrameWork——Activity启动过程详解
- Android窗口管理服务WindowManagerService显示Activity组件的启动窗口(Starting Window)的过程分析