美文网首页
Activity启动流程,源码分析

Activity启动流程,源码分析

作者: Seven鑫洋 | 来源:发表于2017-07-21 11:10 被阅读37次

    ActivityThread通过调用handleLaunchActivity启动我们的目标activity

    第一步 创建Activity,执行onCreate()

    ActivityThread中执行performLaunchActivity方法。

    Activity a = performLaunchActivity(r, customIntent);
    
     Activity activity = null;
            try {
                java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
                //通过newInstance来创建一个activity
                activity = mInstrumentation.newActivity(
                        cl, component.getClassName(), r.intent);
                ...
            } catch (Exception e) {
                if (!mInstrumentation.onException(activity, e)) {
                    throw new RuntimeException(
                        "Unable to instantiate activity " + component
                        + ": " + e.toString(), e);
                }
            }
    
    //创建context
    if (activity != null) {
                    //创建context
                    Context appContext = createBaseContextForActivity(r, activity);
                    CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                    Configuration config = new Configuration(mCompatConfiguration);
                   //...
                   //执行activity的onCreate方法
                    if (r.isPersistable()) {
                        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                    } else {
                        mInstrumentation.callActivityOnCreate(activity, r.state);
                    }
                    //...
                }
    
    public void callActivityOnCreate(Activity activity, Bundle icicle) {
            prePerformCreate(activity);
            activity.performCreate(icicle);
            postPerformCreate(activity);
      }
    

    转到Activity类中执行onCreate方法

    final void performCreate(Bundle icicle) {
            restoreHasCurrentPermissionRequest(icicle);
            //调用我们自己写onCreate方法
            onCreate(icicle);
            mActivityTransitionState.readState(icicle);
            performCreateCommon();
        }
    

    第二步 显示Activity,执行onResume()

    在ActivityThread中首先判断第一步是否创建了Activity,如果创建了执行onResume

    if (a != null) {
                r.createdConfig = new Configuration(mConfiguration);
                reportSizeConfigurations(r);
                Bundle oldState = r.state;
                handleResumeActivity(r.token, false, r.isForward,
                        !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
                //...
     }
    

    handleResumeActivity方法源码阅读

     final void handleResumeActivity(IBinder token,
                boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
            ActivityClientRecord r = mActivities.get(token);
            //...
    
            //
            r = performResumeActivity(token, clearHide, reason);
    
            if (r != null) {
                //...
                if (r.window == null && !a.mFinished && willBeVisible) {
                    r.window = r.activity.getWindow();
                    View decor = r.window.getDecorView();
                    decor.setVisibility(View.INVISIBLE);
                    ViewManager wm = a.getWindowManager();
                    WindowManager.LayoutParams l = r.window.getAttributes();
                    a.mDecor = decor;
                    l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                    l.softInputMode |= forwardBit;
                    if (r.mPreserveWindow) {
                        a.mWindowAdded = true;
                        r.mPreserveWindow = false;
                        // Normally the ViewRoot sets up callbacks with the Activity
                        // in addView->ViewRootImpl#setView. If we are instead reusing
                        // the decor view we have to notify the view root that the
                        // callbacks may have changed.
                        ViewRootImpl impl = decor.getViewRootImpl();
                        if (impl != null) {
                            impl.notifyChildRebuilt();
                        }
                    }
                    if (a.mVisibleFromClient && !a.mWindowAdded) {
                        a.mWindowAdded = true;
                        //***** 这是关键代码 WindowManager的addView方法
                        wm.addView(decor, l);
                    }
    
               //...
        }
    

    WindowManager是连接Activity和View的桥梁

    WindowManager是个接口,其实现类是WindowManagerImpl

    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
            applyDefaultToken(params);
            //会调用global的addView方法
            mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
        }
    

    WindowManagerGlobal才是真是new出了ViewRootImpl
    来看WindowManagerGlobal的addView方法

    public void addView(View view, ViewGroup.LayoutParams params,
                Display display, Window parentWindow) {
           //...
            ViewRootImpl root;
            View panelParentView = null;
    
            synchronized (mLock) {
                //...
                //***关键点,new一个ViewRoot,持有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 {
                //这里才是到真正要显示View布局的地方,也是在这里界面要和用户见面了!!!
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                synchronized (mLock) {
                    final int index = findViewLocked(view, false);
                    if (index >= 0) {
                        removeViewLocked(index, true);
                    }
                }
                throw e;
            }
        }
    

    继续往下看RootViewImpl的setView()方法

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
            synchronized (this) {
                if (mView == null) {
                    mView = view;
    
                    //...
    
                    // 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.
                    //就是一个关键方法,来显示view
                    requestLayout();
                    //...
                }
            }
        }
    

    来看看说了那么多废话的requestLayout()到底是做了些什么

    @Override
        public void requestLayout() {
            if (!mHandlingLayoutInLayoutRequest) {
                //会检查线程,你所有的在子线程操作UI的错误都是在checkThread中爆出来的
                checkThread();
                mLayoutRequested = true;
                //这就要马上显示了
                scheduleTraversals();
            }
        }
    
    //what the fuck 什么方法都没有,哪有显示方法
    void scheduleTraversals() {
            if (!mTraversalScheduled) {
                mTraversalScheduled = true;
                mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
                mChoreographer.postCallback(
                        Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
                if (!mUnbufferedInputDispatch) {
                    scheduleConsumeBatchedInput();
                }
                notifyRendererOfFramePending();
                pokeDrawLockIfNeeded();
            }
        }
    

    别急,我们来看有个postCallback,来看看这个runnable干嘛的,没有就不看这FUNKING CODE了!!!

    final class TraversalRunnable implements Runnable {
            @Override
            public void run() {
                //熟不熟悉的单词 doTraversal 
                doTraversal();
            }
        }
    

    终于找到你,好像隔了几个世纪,到这里就要来执行View的绘制流程了,到这里我们的View也就绘制出来了,也是在这里我们才可以获得控件的宽高了,是在onResume之后我们才可以获取宽高,别再犯傻逼的错误了

    第三步 界面已显示,该干嘛干嘛,主要的是第二步

    image

    相关文章

      网友评论

          本文标题:Activity启动流程,源码分析

          本文链接:https://www.haomeiwen.com/subject/ndnskxtx.html