Android 创建应用类窗口

参考书籍: <Android 内核剖析>

  • 每个应用窗口都对应一个Activity对象,创建应用类窗口首先需要创建一个Activity对象.
// ActivityThread.java
public final class ActivityThread {
    //创建Activity对象
    private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        Activity activity = null;
        try {
            //获取类加载器
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            // TODO 第一
            activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
            r.intent.setExtrasClassLoader(cl);
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            ...
        }
        ...
        try {
            if (activity != null) {
                //TODO 第三 去Activity中看看
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstance,
                        r.lastNonConfigurationChildInstances, config);
            }
        }
        //TODO 第五 callActivityOnCreate()方法最终会调用Activity.onCreate()
        mInstrumentation.callActivityOnCreate(activity, r.state);
        ...
        return activity;
    }
    // TODO 第十三, 当执行完第十二步之后,也就是Activity已经准备好了,最后会通知AMS,然后AMS经过调用,最终会执行到ActivityThread中的handleResumeActivity()
    final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
        // ActivityClientRecord对象的来历这里简单的说一下, 是在ApplicationThread中的scheduleLaunchActivity()被调用时候创建的.
        // 之后ActivityThread.performLaunchActivity()被调用存入变量mActivities集合中.
        // performLaunchActivity()被调用时会创建一个Activity,这个Activity对象也会被保存在ActivityClientRecord对象的activity变量中.
        ActivityClientRecord r = performResumeActivity(token, clearHide);
        //ActivityClientRecord 中的变量activity对应的是将要在手机中展示的Activity.
        final Activity a = r.activity;
        if (r.window == null && !a.mFinished && willBeVisible) {
            // 创建该activity时候的PhoneWindow.
            r.window = r.activity.getWindow();
            // 通过PhoneWindow获取decor
            View decor = r.window.getDecorView();
            ...
            // 将PhoneWinodw的decor赋值给Activity的mDecor变量,这个地方很容易忽略.当Activity要显示内容的时候,
            a.mDecor = decor;
            ...
        }
        if (r.activity.mVisibleFromClient) {
            // TODO 第十四 这里将要开始将Activity中的内容展示出来了.
            r.activity.makeVisible();
        }
    }
}
// Activity.java
public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks {
    // TODO 第三
    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);
        // TODO 第四 创建PhoneWindow
        mWindow = PolicyManager.makeNewWindow(this);
        mWindow.setCallback(this);
        ...
        // 创建 为PhoneWindow对象创建WindowManagerImpl对象变量和 Window.LocalWindowManager对象变量   
        mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
        ...
        mWindowManager = mWindow.getWindowManager();
    }
    // TODO 第六
    // 这个方法再熟悉不过了 经常用到得onCreate方法
    protected void onCreate(Bundle savedInstanceState) {
        mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
                com.android.internal.R.styleable.Window_windowNoDisplay, false);
        mCalled = true;
        //在Activity的子类中会重载onCreate方法,里面模板代码setContentView(R.layout.XXXX),我们现在来看看setContentView()方法
    }
    //TODO 第七
    public void setContentView(int layoutResID){
        // TODO 第八 看看PhoneWindow中的setContentView()方法
        getWindow().setContentView(layoutResID);
    }
    // TODO 第十四 再往下就是WMS那块的知识了,另外起一片笔记再来记录.
    void makeVisible() {
        if (!mWindowAdded) {
            // 获取Window.LocalWindowManager对象
            ViewManager wm = getWindowManager();
            // 最终会调到WindowManagerImpl.addView()
            // 接着会调到ViewRoot.setView()
            // 最后得跨进程了 sWindowSession.add(mWindow, mWindowAttributes,getHostVisibility(), mAttachInfo.mContentInsets,mInputChannel);
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }
}
// PhoneWindow.java
public class PhoneWindow extends Window implements MenuBuilder.Callback {
    // TODO 第八
    @Override
    public void setContentView(int layoutResID) {
        //这是创建Activity 所以mContentParent肯定为null   
        if (mContentParent == null) {
            // TODO 第九 安装decorView  
            installDecor();
        } else {
            mContentParent.removeAllViews();
        }
        // TODO 第十二 将传入的layoutResID布局文件添加到mContentParent中.
        mLayoutInflater.inflate(layoutResID, mContentParent);
        final Callback cb = getCallback();
        if (cb != null) {
            cb.onContentChanged();
        }
    }
    // TODO 第九  
    private void installDecor() {
        if (mDecor == null) {
            // TODO 第十 创建decorView
            mDecor = generateDecor();
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
        }
        if (mContentParent == null) {
            // TODO 第十一 获取用来盛放 setContentView(R.layout.XXX) 中的布局文件的容器.
            mContentParent = generateLayout(mDecor);
            ...
        }
    }
    // TODO 第十 
    protected DecorView generateDecor() {
        // 创建DecorView,它其实是一个FramLayout容器,下面会将一个布局放入这个容器中.
        // 这个布局是Framwork层定义好的布局, 它有标题栏和内容栏,这两个是Framwork层给划分好的.
        // 还记得当setContentView(R.layout.XXX)进来的一个布局么, 
        // 那个布局最终会被添加到内容栏中, 内容栏的id为android.R.id.content.
        return new DecorView(getContext(), -1);
    }
    // TODO 第十一
    protected ViewGroup generateLayout(DecorView decor) {
                
        TypedArray a = getWindowStyle();
        ...
        int layoutResource;
        int features = getLocalFeatures();
        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;
        }
        ...
        // 从上面的源码可以看出,layoutResource 这个布局文件是通过一系列的配置筛选出来的
        // TODO 第十二 将系统layoutResource布局文件解析为View
        View in = mLayoutInflater.inflate(layoutResource, null);
        // TODO 第十三 将View加入到decorView中
        // 上面讲过decroView其实是FramLayout, 然后系统layoutResource布局文件中有一个容器的id为android.R.id.content
        // id为content的这个容器最终会用来放setContentView(R.layout.XXX)中的布局文件
        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        // TODO 第十四 这里就是取出id为content的容器,将这个容器最终再返回去.
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        ...
        return contentParent;
    }
}
// Instrumentation.java
public class Instrumentation {
    // TODO 第一
    public Activity newActivity(ClassLoader cl, String className,Intent intent)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        // TODO 第二
        // 创建Activity对象
        return (Activity)cl.loadClass(className).newInstance();
    }
    //TODO 第五
    public void callActivityOnCreate(Activity activity, Bundle icicle) {
        if (mWaitingActivities != null) {
        ...
         // TODO 第六
        //这里调用onCreate()方法
        activity.onCreate(icicle);
        ...
    }  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值