activity+window+view简单说明

来源:互联网 发布:艾宾浩斯遗忘曲线软件 编辑:程序博客网 时间:2024/06/05 10:31

本章博客经过自己查了源码以及参考了别人的的些许博客,就算做一个小小的总结加深自己的体会和理解,算是个学习笔记。

window是一个抽象类,正如api所说这个类只有一个子类,也就是PhoneWindow,该子类位于com.android.internal.policy.impl包里面;查看源码可以知道Activity类有一个Window类的引用mWindow,并且可以通过getWindow()来获取这个Window对象。简单的追踪一下源码可以发现window在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,            NonConfigurationInstances lastNonConfigurationInstances,            Configuration config) {        attachBaseContext(context);        mFragments.attachActivity(this);                mWindow = PolicyManager.makeNewWindow(this);        mWindow.setCallback(this);        mWindow.getLayoutInflater().setPrivateFactory(this);        ............        mWindow.setWindowManager(null, mToken, mComponent.flattenToString(),                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);        if (mParent != null) {            mWindow.setContainer(mParent.getWindow());        }        mWindowManager = mWindow.getWindowManager();       ........... }

通过上面的代码可以知道mWindow是通过PolicyManager的makeNewWindow(this)来进行初始化的,PolicyManager这个类很简单(注意该类是final类型的并且不可以通过new来初始化),该类包含了一个IPoliciy的引用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);        }    }
IPolicy是一个接口,该接口提供了三个方法,其中一个方法就是makeNewWindow(Context context);IPolicy的子类为Policy,该类实现了makNewWindow方法:

public PhoneWindow makeNewWindow(Context context) {        return new PhoneWindow(context);    }

而PolicyManager的makeNewWindow就只是简单的调用sPolicy.makeNewWindow()了,他们的代码脉络很简单,追踪源代码很容易发现。其实PolicyManger就是一个简单工厂模式的应用,它在工厂模式中扮演着工厂类角色,IPolicy为抽象产品角色,它的实现类Policy就是具体产品角色了!

通过上面的说明,我们知道mWindow在attach方法中游PolicyManger的makeNewWindow方法来初始化。

当调用了attach方法过后就会调用onCreate方法了:

   public void setContentView(int layoutResID) {        getWindow().setContentView(layoutResID);        initActionBar();    }

方法定位到了Window的setContentView,那就看看PhoneWindow类的setContentView的实现:该类聚合了两个View对象,一个是mDecor
该对象是FrameLayout的子类;另一个是mContentParent对象;

   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();        }    }
这个方法先判断mContentParent是否为null,如果为null的情况下就在installDecor方法里面完成了mDecor以及mContentParent初始化工作:

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);                }            }        }    }

该方法先调用generateDecor方法对mDecor来进行初始化,后初始化mContentParent,在generateLayout方法里面有这么一句话可以看出mDecor跟mContentParent的关系:

ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);return contentParent;

而这个findViewById方法是父类Window提供的

 public View findViewById(int id) {        return getDecorView().findViewById(id);    }
可以看出来的是从mDecor获取一个View对象来赋值给mContentParent,所以mDecor和mContentParent是父View与子View关系。mContentParent有什么用么?

继续观察 setContentView方法:

mLayoutInflater.inflate(layoutResID, mContentParent);
至于inflate的具体说明见此博客,也就是说mContentParent这View是作为你的xml文件的父View,xml通过解析生成的View对象被作为mContentParent的子View通过addView添加都mContentParent上来;而由于mConentParent是mDecor子View,所以我们说真个页面的父View或者根View就是mDecor这个View。

总结:通过上面的说明Activity,Window可以得到类图关系如下:

最后简单的用图表示一下Activity PhoneWindow DecorView的关系


其实,整个代码的脉络很清晰,只要追踪一下源代码就可以很清晰的得到上面的结论。






0 0