您的位置:首页 > 移动开发 > Android开发

Android 4.2 SetContentView 流程分析(一)

2013-01-02 16:39 543 查看
当呼叫startActivity去启动一个新的Activity, System Server就会经由Socket发送一个请求给Zygote,这个请求带有"android.app.ActivityThread"参数.Zygote就会因为这个请求而fork一个子进程 (假设所启动的activity所属的process还没有被启动过), 这个子进程就是App对应的进程. 此入口函数就是ActivityThread的main function.

在ActivityThread class中有一个function handleLaunchActivity, handleLaunchActivity的功用就是新增Activity的地方, main function 如何呼叫到 handleLaunchActivity function的流程分析并不在这次的分析当中,所以就直接来看 handleLaunchActivity 这函数.

[ActivityThread.java]
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//...
//传回一个新的Activity物件. 并建立一些UI对象(比如View,
//Window.)
Activity a = performLaunchActivity(r, customIntent);  (1)

if (a != null) {
//...
//建立ViewRootImpl跟WindowManagerService, Surface的关系
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed);  (2)
if (!r.activity.mFinished && r.startsNotResumed) {
//当目前的Activity处在背景但还是visible的状态时, Activity
//Manager Service就将目前的Activity状态转到Pause state.

}
} else {
//通知Activity Manager Service终止目前的Activity.

}
}


(1)

[ActivityThread.java]
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//1. 检查ActivityClientRecord中有没有相关的package information,
//若没有的话就下载Apk建立新的package information.
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
//2. 检查ActivityClientRecord中有没有相关的component,没有的话
//先在ActivityClientRecord中的intent设定component的属性.
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
//3. 根据新的Package information建立一个新的ComponentName物
//件.
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}

Activity activity = null;
try {
//4. 从ActivityClientRecord中的package information取得Class
//Loader.
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
//5. 利用Class loader和ComponentName对象搭配
//mInstrumentation.newActivity函数产生一个新的activity对象.
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
//...
} catch (Exception e) {
//...
}

try {
//6. 根据ActivityClientRecord中的package information建立一个
//新的Application.
Application app = r.packageInfo.makeApplication(false,
mInstrumentation);

if (activity != null) {
//7. 为新的Activity建立新的context跟一些属性设定.
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title =
r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new
Configuration(mCompatConfiguration);
//8. 将新的Activity嵌入由上面产生的新Application.
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances,
config);
//9. 开始设定activity的参数intent设定跟背景主题设定
if (customIntent != null) {
activity.mIntent = customIntent;
}
//...
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
//...
//10. 开始进入新的Activity的 Create state.
activity.mCalled = false;
mInstrumentation.callActivityOnCreate(activity, r.state);
}

//...

} catch (SuperNotCalledException e) {
throw e;

} catch (Exception e) {
//...
}

return activity;
}
到目前为止,我们可以看到一个新的Activity被启动时, 第一个会被呼叫的就是onCreate function, 在这function中都会利用setContentView 来设置UI接口.

[Activity.java]
public void setContentView(View view) {
//由函数字面大概可以推出要利用 Window对象来设置UI组件.
getWindow().setContentView(view);
//这是android 4.x之后新的UI组件, 为何要把这个UI组件独立出来
//设置.这有太多原因了, 但不是这里的分析重点.
initActionBar();
}


getWindow().setContentView(view); 这一行程序代码带出了两个角色, Window
View. 根据SDK的描述 Window 和 View 的定义如下:

Window

Abstract base class for a top-level window look andbehavior policy. An instance of this class should be used as the top-level viewadded to the window manager. It provides standard UI policies such as abackground, title area, default key processing,
etc.


大概意思是说Window是一个抽象类,主要是用来控制top window的外观跟行为,即绘制UI组件跟默认的输入处理.

View

This class represents the basic building block foruser interface components. A View occupies a rectangular area on the screen andis responsible for drawing and event handling

大概意思是说View是一个基本占据屏幕一块矩形的UI单元,可用于绘画跟处理事件.

getWindow 回传的 window 物件是甚么? setContentView里的View 对象又是代表甚么?分析如下:

1. getWindow 回传的 window 物件.

[Activity.java]
public Window getWindow() {
return mWindow;
}
mWindow 是何物, 这需要从新增activity的 performLaunchActivity function 开始说起, 我们在前面分析 performLaunchActivity function 时,发现 performLaunchActivity 中的第八个步骤将新的activity嵌入新产生的application, mWindow对象就是在这时候产生的.直接来看第八个步骤所呼叫的activity.attach
函数实作.

[Activity.java]
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config) {
//...
mWindow = PolicyManager.makeNewWindow(this);

//...
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken,
mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) !=
0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
这里的关键动作做了两件事, 首先由 PolicyManager.makeNewWindow 建立一个新的 Window 对象, 再来就是让新的 Window 对象设为 WindowManager 角色.

新的 Window
物件为何物?

[PolicyManager.java]
public static Window makeNewWindow(Context context) {
//sPolicy 是由 IPolicy宣告的, 因此需要去找谁去实作 IPolicy的类别.
return sPolicy.makeNewWindow(context);
}

[Policy.java]
public Window makeNewWindow(Context context) {
//新的 Window对象就是一个 PhoneWindow 对象.
return new PhoneWindow(context);
}
由以上的分析可以得到以下的推论:

1. mWindow = PolicyManager.makeNewWindow(this);

==> mWindow = new PhoneWindow(this);

2. mWindow.setWindowManager

==> new PhoneWindow(this). setWindowManager

WindowManager 为何物?

本来想说既然找到 mWindow 就是 PhoneWindow 对象, 所以就去 PhoneWindow 类别找 setWindowManager function 的实作, 结果找不到.

后来就去PhoneWindow 的父类别Window 找.

[Window.java]
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,  boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated
|| SystemProperties.getBoolean(PROPERTY_HARDWARE_UI,
false);
if (wm == null) {
//1. 由ServiceManger取得Window Manger service proxy.
wm =
(WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
//2. 利用Window Manger service proxy来产生WindowManager.
mWindowManager =
((WindowManagerImpl)wm).createLocalWindowManager(this);
}

[WindowManagerImpl.java]
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mDisplay, parentWindow);
}
由以上的分析就可以知道WindowManager
就是一个WindowManagerImpl对象.

2. setContentView 里的View 物件

由前面的分析, 可以知道 getWindow 传回来的mWindow就是一个 PhoneWindow
对象, 因此可以从 PhoneWindow 类别去分析.

[PhoneWindow.java]
@Override
public void setContentView(View view) {
//详见以下分析
setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT,
MATCH_PARENT));
}

@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
//1. mContentParent 为 ViewGroup类型, 预设为 null.
if (mContentParent == null) {
//产生DecoreView,详见以下分析
installDecor();
} else {
mContentParent.removeAllViews();
}
//2. 将 View加入 mContentParent (DecoreView)中.
mContentParent.addView(view, params);
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}

private void installDecor() {
if (mDecor == null) {
//DecorView 对象,由 FrameLayout 类别所衍生的.
mDecor = generateDecor();
//...
}
if (mContentParent == null) {
//详见以下分析
mContentParent = generateLayout(mDecor);
//...
} else {

//...

}
}
}

protected ViewGroup generateLayout(DecorView decor) {
//...
View in = mLayoutInflater.inflate(layoutResource, null);
//将ViewGroup的LayoutParams对象加入DecoreView
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT,
MATCH_PARENT));
//由findViewById函数搭配ID_ANDROID_CONTENT得到ViewGroup的物
//件参考.
ViewGroup contentParent =
(ViewGroup)findViewById(ID_ANDROID_CONTENT);
//...
retrun contentParent;
}
setContentView函数中的第二个步骤可以知道,setContentView里的View
对象就是一个 DecoreView (ViewGroup)的子View.

到此我们先做个结论, performLaunchActivity函数里会去呼叫
mInstrumentation.callActivityOnCreate, 接下来便会去触发 Activity 的 onCreate function,一般在 onCreate 中第一件事就是利用setContentView 来设置UI组件.setContentView 这函数会带出PhoneWindow,
WindowManagerImpl,DecoreView 这三个跟UI相关的对象.

1. getWindow 得到一个 mWindow, 这个 mWindow 就是一个PhoneWindow对象.

2. 利用 PhoneWindow 对象设为WindowManagerImpl的角色.

3. PhoneWindow 物件设置一个 DecoreView的子 view.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐