Activity Threa创建Window和View分析
http://blog.csdn.net/ljsbuct/article/details/7094580
1. 入口。
以前一直都说Activity的人口是onCreate方法。其实android上一个应用的入口,应该是ActivityThread。和普通的java类一样,入口是一个main方法。
public static final void main(String[] args) {
SamplingProfilerIntegration.start();
……
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
ActivityThread thread = new ActivityThread();
thread.attach(false);
……
Looper.loop();
……
thread.detach();
……
Slog.i(TAG, "Main thread of " + name + " is now exiting");
}
下面仔细分析一下这个main方法。
2.Looper.prepareMainLooper();
ActivityThread其实就是我们经常说的UI
thread,也就是主线程。我们都知道主线程可以使用Handler进行异步通信,因为主线程中已经创建了Looper,而这个Looper就是在这里
创建的。如果其他线程需要使用Handler通信,就要自己去创建Looper。
3. sMainThreadHandler = new Handler();
创建一个Handler。
4. 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;
5. handleLaunchActivity(r, null);
从名字中就可以看出,这里就将进行启动activity的工作了。
方法中主要调用了这一句:
Activity a = performLaunchActivity(r, customIntent);
6. performLaunchActivity()
进行了一些初始化和赋值操作后,创建activity。
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
然后调用:
mInstrumentation.callActivityOnCreate(activity, r.state);
这一句就会调用到acitivity的onCreate方法了,就进入了大多数应用开发的入口了。
http://blog.csdn.net/ljsbuct/article/details/7094575
一.Activity启动
Activity由ActivityThread负责启动。 ActivityThread的分析将在《ActivityThread分析》中,在此,只需要知道创建activity的入口在ActivityThread就行,不影响以下的分析。
ActivityThread.java
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
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);
}
}
return activity;
}
二。调用Activity的attach方法。
ActivityThread.java
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
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);
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstance,
r.lastNonConfigurationChildInstances, config);
}
三。Activity的attach实现
1.attach的实现
Activity.java //Activity implement Window.Callback
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); //ContextThemeWrapper中实现,赋值给mBase
mWindow = PolicyManager.makeNewWindow(this); //创建window,实际上是一个PhoneWindow对象
mWindow.setCallback(this); //设置Window.Callback,因为Activity implement Window.Callback
mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
mWindowManager = mWindow.getWindowManager();
}
2.PolicyManager.makeNewWindow实现
(1).PolicyManager.java
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
Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
sPolicy = (IPolicy)policyClass.newInstance();
}
public static Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context);
}
(2).Policy.java //Policy implements IPolicy
public PhoneWindow makeNewWindow(Context context) {
return new PhoneWindow(context);
}
3.设置WindowManager
mWindow.setWindowManager(null, mToken, mComponent.flattenToString()); //为Window中的WindowManager赋值
mWindowManager = mWindow.getWindowManager(); //为Acitivity中的WindowManager赋值
WindowManager只是一个interface,实现类有两个:Window.LocalWindowManager和WindowManagerImpl。
(1).Window.LocalWindowManager实现,只是对WindowManagerImpl的封装调用。
private class LocalWindowManager implements WindowManager {
private final WindowManager mWindowManager;
LocalWindowManager(WindowManager wm) {
mWindowManager = wm;
}
public final void addView(View view, ViewGroup.LayoutParams params) {
//some code to check params here
mWindowManager.addView(view, params);
}
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
mWindowManager.updateViewLayout(view, params);
}
public final void removeView(View view) {
mWindowManager.removeView(view);
}
public final void removeViewImmediate(View view) {
mWindowManager.removeViewImmediate(view);
}
}
(2).Window.setWindowManager实现分析
public void setWindowManager(WindowManager wm, IBinder appToken, String appName) {
if (wm == null) {
wm = WindowManagerImpl.getDefault();
}
mWindowManager = new LocalWindowManager(wm);
}
四。回调Activity的onCreate方法。
(1). ActivityThread.java
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
(2). Instrumentation.java
public void callActivityOnCreate(Activity activity, Bundle icicle) {
activity.onCreate(icicle);
}
五。Activity中setContentView(int layout)分析
Activity.java
public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
}
public Window getWindow() {
return mWindow; //mWindow = PolicyManager.makeNewWindow(this);
}
六。Window中setContentView(int layout)分析
(1)PhoneWindow.java //因为Window是个abstract class, mWindow实际上是一个PhoneWindow对象
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();
}
}
(2) installDecor()分析 //PhoneWindow.java中
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
}
}
mDecor: class DecorView extends FrameLayout
mContentParent: class ViewGroup
(3)generateDecor()分析
protected DecorView generateDecor() {
return new DecorView(getContext(), -1);
}
DecorView:继承自FrameLayout,可以理解成窗口修饰,这个窗口修饰可以有各种style,比如标题栏,显示进度条等。常见的窗口修
饰的layout路径为:frameworks/base/core/res/res/layout,比如
R.layout.dialog_title_icons, R.layout.screen_title_icons.
(4)generateLayout()分析
protected ViewGroup generateLayout(DecorView decor) {
// Inflate the window decor.
int layoutResource;
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;
}
} else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0) {
layoutResource = com.android.internal.R.layout.screen_progress;
} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
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 (mIsFloating) {
layoutResource = com.android.internal.R.layout.dialog_title;
} else {
layoutResource = com.android.internal.R.layout.screen_title;
}
} else {
layoutResource = com.android.internal.R.layout.screen_simple;
}
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");
}
return contentParent;
}
DecorView的样式的定义:第一种是在Activity中onCreate中调用requestFeature()。另一种是在AndroidManifest.xml中配置android:theme="xxx".
DecorView添加View:generateLayout的前部分代码,就是确定DecorView的样式,然后inflate这个layout文件,再调用DecorView.addView()添加到DecorView上。
mContentParent赋值:窗口修饰的layout中必须有一个FrameLayout,id为ID_ANDROID_CONTENT(实际上id=content),将这个FrameLayout赋值给mContentParent。
(5)添加窗口内容到mContentParent。
mLayoutInflater.inflate(layoutResID, mContentParent);
将activity传入的layoutRes添加到窗口装饰中。
(6)Window.Callback回调
final Callback cb = getCallback(); //Activity实现了Window.Callback接口,并且在创建PhoneWindow后,调用mWindow.setCallback(this)
if (cb != null) {
cb.onContentChanged();
}
七。通知WmS,显示DecorView
Activity准备好后会通知AmS,AmS通过一些条件判断,回调Activity的makeVisible().
(1.) Activity.java
public void setVisible(boolean visible) {
if (mVisibleFromClient != visible) {
mVisibleFromClient = visible;
if (mVisibleFromServer) {
if (visible) makeVisible();
else mDecor.setVisibility(View.INVISIBLE);
}
}
}
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes()); //通过WindowManager将DecorView添加到window。
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
public Window getWindow() {
return mWindow;
}
(2.) Window.java
public final WindowManager.LayoutParams getAttributes() {
return mWindowAttributes;
}
private final WindowManager.LayoutParams mWindowAttributes =
new WindowManager.LayoutParams();
(3.) WindowManager.LayoutParams
public LayoutParams() {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = TYPE_APPLICATION;
format = PixelFormat.OPAQUE;
}
(4.)Window.LocalWindowManager
wm.addView(mDecor, getWindow().getAttributes())分析
这个wm是LocalWindowManager,是对WindowManagerImpl的封装,目地是对params进行一些校验后,再调用WindowManagerImpl的addView。
校验params:
if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
} else {
}
八。WindowManagerImpl.addView分析
方法:addView(View view, ViewGroup.LayoutParams params, boolean nest);
class WindowManagerImpl extends WindowManager, interface WindowManager extends ViewManager
3个成员变量:
private View[] mViews;//每个view对象都将成为WmS所认为的一个窗口
private ViewRoot[] mRoots;//每个view对应一个ViewRoot
private WindowManager.LayoutParams[] mParams;//对应mViews的每个view的param
(1.)检查view是否已经添加过,不允许重复添加
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.)检查窗口类型是否为sub window。如果是,则找到它的父窗口,并保存在临时变量panelParentView中,为下面调用ViewRoot的setView使用。
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,上文说过每个view都对应一个ViewRoot。
root = new ViewRoot(view.getContext());
root.mAddNesting = 1;
ViewRoot的构造方法:
public ViewRoot(Context context) {
super();
// 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()); //init static IWindowSession sWindowSession;
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();
mWindow = new W(this, context); // class W extends IWindow.Stub
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;
}
(4.)将view,root和param添加到上面的3个数组中。
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]; //新建一个数组,长度+1
System.arraycopy(old, 0, mViews, 0, index-1); //将原来的数组copy到新建的数组中
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的setView方法,完成最后的添加工作。
九。ViewRoot的setView分析
参数意义:
view: WindowManagerImpl中mViews数组中的元素,也就是新建的窗口界面
attrs:窗口参数,描述窗口的风格,大小,位置。attrs中的token变量指明了该窗口和activity的关系。
panelParentView:view的父窗口
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;//给成员变量赋值。
mWindowAttributes.copyFrom(attrs);//给成员变量赋值。
attrs = mWindowAttributes;//给成员变量赋值。
………………………………
mSoftInputMode = attrs.softInputMode;//给成员变量赋值。
mWindowAttributesChanged = true;//给成员变量赋值。
mAttachInfo.mRootView = view;//给成员变量赋值。
if (panelParentView != null) {
mAttachInfo.mPanelParentWindowToken
= panelParentView.getApplicationWindowToken();
}
………………………………
requestLayout(); //发出重绘请求,使该 在相应消息前变的可见
………………………………
try {
//通知WmS,添加窗口
res = sWindowSession.add(mWindow, mWindowAttributes,
getHostVisibility(), mAttachInfo.mContentInsets,
mInputChannel);
} catch (RemoteException e) {
}
}
}
}
十。sWindowSession.add分析
(1)IWindowSession是一个aidl接口,实现类是在WmS中:class Session extends IWindowSession.Stub
(2)sWindowSession的初始化: //static IWindowSession sWindowSession;
public static IWindowSession getWindowSession(Looper mainLooper) {
synchronized (mStaticInit) {
if (!mInitialized) {
try {
InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
sWindowSession = IWindowManager.Stub.asInterface(
ServiceManager.getService("window")) //先获得WmS
.openSession(imm.getClient(), imm.getInputContext()); //再通过WmS获取分配的IWindowSession
mInitialized = true;
} catch (RemoteException e) {
}
}
return sWindowSession;
}
}
(3)sWindowSession为static,WmS为每个进程只分配1个。调用sWindowSession.add是app请求WmS添加窗口的唯一入口。
总结:至此,从客户端的角度讲,已经完成了窗口创建的全部工作。
Activity Threa创建Window和View分析的更多相关文章
- Activity、Window、View三者之间的联系
Activity类:Android四大组件之一,是开发者最常用的一个组件 Window类:是一个抽象类,具有窗口管理的功能,实现类为PhoneWindow View类:提供对View的操作,包括绘制测 ...
- Android开发之漫漫长途 Ⅱ——Activity的显示之Window和View(2)
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...
- Android开发之漫漫长途 Ⅱ——Activity的显示之Window和View(1)
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...
- Android GUI之Activity、Window、View
相信大家在接触Android之初就已经知道了Activity中的setContentView方法的作用了,很明显此方法是用于为Activity填充相应的布局的.那么,Activity是如何将填充的布局 ...
- Android开发之漫漫长途 Ⅲ——Activity的显示之Window和View(2)
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...
- Android 中Activity,Window和View之间的关系
转自:http://hi.baidu.com/xiaofanqing/blog/item/8261ac114ab14f64cb80c435.html 我这里根据我个人的理解来讲讲我个人对这3个概念的理 ...
- Android 中的Activity、Window、View之间的关系
一.概述 Activity 可以说是应用程序的载体(也可以理解为界面的载体,但是不界面),用户能够在上面绘制界面(Activity本身不绘制界面),并提供用户处理事件的API,维护应用程序的生命周 ...
- activity 、window与view的关系(下)
在activity的attacth方法中,通过policymanager 的makenewwindow来创建window 而window的具体实现是phonewindow 接下来通过setconten ...
- Android进阶笔记08:Android 中Activity、Window和View之间的关系
1. Android 中Activity.Window和View之间的关系(比喻): Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图) LayoutI ...
随机推荐
- 【UVA11478】Halum (最短路解差分约束)
题目: Sample Input2 11 2 102 11 2 -103 31 2 42 3 23 1 54 52 3 44 2 53 4 23 1 01 2 -1Sample OutputInfin ...
- C语言嵌入式系统编程修炼之四:屏幕操作
汉字处理 现在要解决的问题是,嵌入式系统中经常要使用的并非是完整的汉字库,往往只是需要提供数量有限的汉字供必要的显示功能.例如,一个微波炉的LCD上没有必要提供显示"电子邮件"的功 ...
- 14.6.1 InnoDB Startup Configuration 启动配置
14.6.1 InnoDB Startup Configuration 启动配置 首先描述关于InnoDB 配置设计数据库文件,日志文件,page size 和内存buffer 的配置. 推荐你定义数 ...
- (转载)Undefined variable: PHP_SELF的问题解决方法
(转载)http://blog.sina.com.cn/s/blog_4ab014680100gx43.html 在PHP使用了$PHP_SELF函数时,出现以下错误 Undefined variab ...
- idea安装Scala插件
最近在学习研究kafka,当我们进行debug跟踪时,就需要研究源码了.kafka的源码是Scala语言,在此就需要Scala环境来运行kafka源码了. 接下来记录的是我在IDEA中安装Scala插 ...
- 阻止iOS设备锁屏
[[UIApplicationsharedApplication] setIdleTimerDisabled: YES];
- MySQL索引原理与慢查询优化
索引目的 索引的目的在于提高查询效率,可以类比字典,如果要查“mysql”这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql.如果没有索引,那么你可能需要把所有单词看一遍才 ...
- poj 3620 Avoid The Lakes【简单dfs】
Avoid The Lakes Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 6795 Accepted: 3622 D ...
- ASP.NET与SOAP协议使用记录
近期初次接手一个公司的管理系统开发任务,因为公司需要有Android,IOS客户端,又要求有PC端的网页客户端....对服务请求的要求自然也就落在了统一接口访问上了.... 使用ASP.NET的WEB ...
- python处理xml的常用包(lib.xml、ElementTree、lxml)
python处理xml的三种常见机制 dom(随机访问机制) sax(Simple APIs for XML,事件驱动机制) etree python处理xml的三种包 标准库中的xml Fredri ...