深入理解Activity进阶系列(二):界面创建

来源:互联网 发布:python 伪装成浏览器 编辑:程序博客网 时间:2024/06/05 15:13

深入理解Activity进阶系列(二):界面创建

本系列主要讲解Activity的一些进阶知识,大部分是通过源码分析了解>Activity有关的内容,同时也会介绍一些平时比较不容易注意到的细节。

  1. 深入理解Activity进阶系列(一):Activity启动

  2. 深入理解Activity进阶系列(二):界面创建
    ……

本文主要来分析Activity界面有关的创建,包括Window、和视图。

Window

Window 是一个抽象类,表示一个窗口,它的具体实现类是 PhoneWindow,实现位于 WindowManagerService 中。
WindowManager是外界访问Window的入口,Window的具体实现位于WindowManagerService,WindowManager与WindowManagerService的交互是一个IPC过程。
Android中所有的View都是Window来呈现的,不管是Activity、Toast还是Dialog,它们的视图都是附加到Window上的,因此Window是View的直接管理者。


Activity

上文分析到ActivityThread的performLaunchActivity会将Activity实例,实例化之后会调用Activity的attach方法创建Window并给Window设置了一些Activity的回调,代码如下

 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, String referrer, IVoiceInteractor voiceInteractor) {        // mBase赋值        attachBaseContext(context);        // 实例化Window,目前PhoneWindow是Window的唯一实现        mWindow = new PhoneWindow(this);        // 设置回调,例如onWindowFocusChanged、onAttachedToWindow,事件发生时通知Activity        mWindow.setCallback(this);       ...       // 设置WindowManager,对于Window的操作,是通过WindowManger,       //WindowManger在通过Binder调用WindowMangerService实现的        mWindow.setWindowManager(                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),                mToken, mComponent.flattenToString(),                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);       ...    }

视图


Activity

Activity的attach调用完之后会通过mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState),最终调用到Activity的onCreate方法。正常情况我们会在Activity的onCreate方法的,调用setContentView来设置我们的视图,接下来就看看setContentView的实现。
getWindow()返回的是mWindow,mWindow是PhoneWindow的实例,进一步调到了PhoneWindow的setContentView。

 public void setContentView(@LayoutRes int layoutResID) {        // 调用了Window的setContentView方法        getWindow().setContentView(layoutResID);        initWindowDecorActionBar();    }

PhoneWindow

根据当前主题创建DecorView,并将我们自定义的视图添加到DecorView中的content中。

DecorView

DecorView是PhoneWindow类的一个内部类,继承于FrameLayout。是整个ViewTree的最顶层View,它是一个FrameLayout布局,代表了整个应用的界面。在该布局下面,有标题view和内容view这两个子元素,而内容view id是com.android.internal.R.id.content,我们自定义的视图就是添加到这个view上的。

@Override    public void setContentView(int layoutResID) {        // mContentParent是在installDecor()创建的,所以第一次调用setContentView时为空        if (mContentParent == null) {            // 创建DecorView,并创建mContentParent(DecorView中id为com.android.internal.R.id.content的View)            // 下面具体分析installDecor            installDecor();        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {            mContentParent.removeAllViews();        }        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,                    getContext());            transitionTo(newScene);        } else {           // 将我们的自定义的视图加到mContentParent中            mLayoutInflater.inflate(layoutResID, mContentParent);        }        mContentParent.requestApplyInsets();        final Callback cb = getCallback();        if (cb != null && !isDestroyed()) {            cb.onContentChanged();        }    }
  private void installDecor() {        if (mDecor == null) {           // 实例化DecorView            mDecor = generateDecor();            ...        }        if (mContentParent == null) {            // 调用generateLayout创建mContentParent,其中会调用            // View in = mLayoutInflater.inflate(layoutResource, null);        // decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));        // 根据不同主题等情况,创建不同的layoutResource的DecorView            mContentParent = generateLayout(mDecor);            ...        }        ...    }

ActivityThread

app的进程其实就是ActivityThread

视图已经添加到DecorView上,不过目前还没有显示,因为DecorView还没有添加到Window上。Activity 的performLaunchActivity接着会调用调用ActivityThread的handleResumeActivity。
handleResumeActivity会先调用performResumeActivity,performResumeActivity会调用Activity的onResume方法。到这里Activity的onResume已经调用,可是视图还没有显示出来,具体显示还在下面。
performResumeActivity调完之后会去调用会Activity的makeVisible显示视图。

 final void handleResumeActivity(IBinder token,            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {        ...        // performResumeActivity会调用Activity的onResume方法        r = performResumeActivity(token, clearHide, reason);        if (r.activity.mVisibleFromClient) {                    // 调用Activity的makeVisible方法显示视图                    r.activity.makeVisible();                }}

Activity

Activity的makeVisible会调用WindowManger的addView,将将DecorView添加到Window上,WindowManger通过Binder调用WindowMangerService添加。

void makeVisible() {        if (!mWindowAdded) {            // 获取WindowManger            ViewManager wm = getWindowManager();            // 通过WindowManger将DecorView添加到Window上,WindowManger通过Binder调用WindowMangerService添加            wm.addView(mDecor, getWindow().getAttributes());            mWindowAdded = true;        }        // 设置DecorView可见        mDecor.setVisibility(View.VISIBLE);    }

WindowManager

WindowManager的具体实现是WindowManagerImpl,WindowManagerImpl的addView方法调用了WindowManagerrGlobal的addView。

WindowManagerGlobal

WindowManagerGlobal的addView方法,创建了ViewRootImpl对象,ViewRootImpl是android view的根对象,负责view的绘制。之后调用了ViewRootImpl的setView方法。

 public void addView(View view, ViewGroup.LayoutParams params,            Display display, Window parentWindow) {        ...        ViewRootImpl root;        // 创建了ViewRootImpl对象         root = new ViewRootImpl(view.getContext(), display);         view.setLayoutParams(wparams);            mViews.add(view);            mRoots.add(root);            mParams.add(wparams);        }        // do this last because it fires off messages to start doing things        try {        // 调用ViewRootImpl的setView方法            root.setView(view, wparams, panelParentView);        }     }

ViewRootImpl

ViewRootImpl是个ViewParent,在DecoView添加的View时,就会将View中的ViewParent设为DecoView所在的ViewRootImpl。ViewRootImpl对添加到DecoView的所有View进行事件管理,实际管理Window中所有View的类。

ViewRootImpl的setView调用了requestLayout开始绘制view,之后会进行一些状态异常的检测。

 /**     * We have one child     */    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {                ...                // Schedule the first layout -before- adding to the window                // manager, to make sure we do the relayout before receiving                // any other events from the system.                // 调用了requestLayout,绘制view                requestLayout();                ...                ... //一些状态异常的检测                //  一些状态异常的检测,例如下面的异常                 throw new WindowManager.BadTokenException(                                    "Unable to add window -- token " + attrs.token                                    + " is not valid; is your activity running?");                ...}

requestLayout调用了scheduleTraversals,scheduleTraversals中往mChoreographer(是一个Handler)post了一个mTraversalRunnable。

void scheduleTraversals() {        if (!mTraversalScheduled) {           ...            mChoreographer.postCallback(                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);            ...        }    }

mTraversalRunnable的run方法调用了doTraversal,doTraversal中又调用了performTraversals。
performTraversals方法想必大家都不陌生吧,就是它调用的performMeasure、performLayout、performDraw,这里就不展开说view的绘制流程了。

void doTraversal() {        if (mTraversalScheduled) {           ...           // 开始view的绘制,其中会相继调用performMeasure、performLayout、performDraw            performTraversals();           ...        }    }

到这里我们的视图就绘制好了,在视图绘制完成之前就已经调用了onResume。所以在onResume的时候视图并未绘制好,从上面的分析也可以看出,onResume的时候是用户可交互了。

总结


流程图待补充

原创粉丝点击