戏说Android view 工作流程《上》

view基本认识

回想你第一次看到Android设备时,上面各种酷炫的应用和游戏是不是让多年使用塞班手机的你感到amazing?能看到这篇文章说明你现在的工作多少和android开发相关。或许你是跟着教程写了一个HelloWold运行在模拟器或者真机上,结果出来的瞬间会有些自豪。心想着自己也是会android应用开发的人了。

接着可能陆陆续续的写了几个小Demo,这时候对android应用的印象多了四大组件等一些概念,提到view,你可能会说,视图不就是窗口,而一个窗口往往就是一个activity。所以会有一个activity就是一个view的错觉。其实也不能说完全错了,这其中确实有玄机。

setContentView说起

为啥会让我们有activity即view的印象,原因就在于Activity一般都在onCreate函数中里使用setContentView设置UI界面。我们略作分析:

mWindow为何物?

Activity.java

/*** 根据布局文件来填充activity的view。*/public void setContentView(int layoutResID) {getWindow().setContentView(layoutResID);//我们需要看下getWindow()返回的是什么。}/*** Retrieve the current {@link android.view.Window} for the activity.* This can be used to directly access parts of the Window API that* are not available through Activity/Screen.** @return Window The current window, or null if the activity is not*visual.*/public Window getWindow() {return mWindow;// 是window的一个实例}

mWindow是何方神圣,又是谁创造了它,我们control+F一下在attach函数中找到了它mWindow =PolicyManager.makeNewWindow(this),不过又多出来一个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-timetry {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);。。。。。。// The static methods to spawn new policy-specific objectspublic static Window makeNewWindow(Context context) {return sPolicy.makeNewWindow(context);}}

该类代码比较少,申明了一个Policy类型的单例对象,我们再看看它是神马。

public PhoneWindow makeNewWindow(Context context) {return new PhoneWindow(context);//亲,注意啦,出现关键词PhoneWindow。}

成员变量的真实类型是LocalWindowManager。

深入setContentView

弄清楚了以上概念,,我们可以重新回到setContenView函数了。根据上面的结论,直接到PhoneWindow去找它。

public void setContentView(View view, ViewGroup.LayoutParams params) {if (mContentParent == null) {installDecor();} else {mContentParent.removeAllViews();}mContentParent.addView(view, params);final Callback cb = getCallback();if (cb != null) {cb.onContentChanged();}}

可以知道mContentParent是viewGroup类型,它存在时就负责把view加载出来,不存在的时候会走installDecor方法。

private void installDecor() {if (mDecor == null) {mDecor = generateDecor();//创建mDecor,它是DecorView类型,继承于FrameLayout。mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);mDecor.setIsRootNamespace(true);}if (mContentParent == null) {mContentParent = generateLayout(mDecor);//创建标题栏mTitleView = (TextView)findViewById(com.android.internal.R.id.title);……}}

这里需要我们进一步看下generateDecor()方法:

protected ViewGroup generateLayout(DecorView decor) {// Apply data from current theme.//1,根据getWindowStyle()返回的数组来设定一些窗口属性值feature,如是否全屏,是否带标题栏。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()));}……// Inflate the window decor.//2,根据上面设定的features值,决定加载何种窗口布局文件。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;}……}mDecor.startChanging();//3,把特定的view添加到decorView里。View in = mLayoutInflater.inflate(layoutResource, null);decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));//4,这个contentParent由findViewById返回,实际上就是mDecorView一部分。ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);……mDecor.finishChanging();return contentParent;}

窗口布局文件解析

上面第二步提到根据上面设定的features值,决定加载何种窗口布局文件,我们找一个系统窗口布局文件分析一下:

带上心灵去旅行,以平和的心态看待一切,

戏说Android view 工作流程《上》

相关文章:

你感兴趣的文章:

标签云: