Activity启动流程源码详解(下)

Activity启动流程源码讲解(上)

https://blog.csdn.net/weixin_37730482/article/details/69569670

 

通过上一章节,我们知道了以下内容

 

1.ActivityThread类performLaunchActivity方法是启动Activity的入口。

 

2.performLaunchActivity方法中,核心功能初始化上下文对象获取ClassLoader利用获取的ClassLoader创建Activity创建Application执行其onCreate方法执行Activity源码类的attach方法,最后执行Activity的onCreate方法
 

 

3.Activity的attach方法中,使用PhoneWindow对象创建Window对象。然后再PhoneWindow的构造方法中初始化DecorView。

 

4.onCreate方法中 执行setContentView()方法。


  <4.1> 自己的Activity通过  Activity类的setContentView方法  利用PhoneWindow类的setContentView方法  创建DecorView 然后通过DecorView生成一个id是com.android.internal.R.id.content的ViewGroup。并初始化各种系统的View。比如导航栏等等。

 

  <4.2> 再通过 AppCompatActivity的setContentView方法 将PhoneWindow类的setContentView方法生成的id是com.android.internal.R.id.content的ViewGroup为父布局 解析自己的布局文件。

 

这里 仅仅执行到Activity的onCreate方法。所以仅仅是 由xml布局文件 显示出一个View结构。下面我们看一下 Activity的下一个生命周期方法  onResume。

 

 

 

 

一.Activity启动流程之onResume方法

 

 

源码讲解之 ActivityThread类

 

handleResumeActivity方法源码

@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,String reason) {
  

    // TODO Push resumeArgs into the activity for consideration
    final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
    if (r == null) {
        // We didn't actually resume the activity, so skipping any follow-up actions.
        return;
    }

    final Activity a = r.activity;

    if (r.window == null && !a.mFinished && willBeVisible) {
        r.window = r.activity.getWindow();
        View decor = r.window.getDecorView();
        decor.setVisibility(View.INVISIBLE);

        
        //获取ViewManger
        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;
                
            ViewRootImpl impl = decor.getViewRootImpl();
            if (impl != null) {
                impl.notifyChildRebuilt();
            }
        }
        if (a.mVisibleFromClient) {
            if (!a.mWindowAdded) {
                a.mWindowAdded = true;

                //ViewManager添加View
                wm.addView(decor, l);
            } else {
                // The activity will get a callback for this {@link LayoutParams} change
                // earlier. However, at that time the decor will not be set (this is set
                // in this method), so no action will be taken. This call ensures the
                // callback occurs with the decor set.
                a.onWindowAttributesChanged(l);
            }
        }

        // If the window has already been added, but during resume
        // we started another activity, then don't yet make the
        // window visible.
    } else if (!willBeVisible) {
        if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
        r.hideForNow = true;
    }

    
    // The window is now visible if it has been added, we are not
    // simply finishing, and we are not starting another activity.
    if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
        
        Looper.myQueue().addIdleHandler(new Idler());
}

由上可知,handleResumeActivity方法的核心功能是

<1> 执行本类的performResumeActivity方法。生成一个ActivityClientRecord对象。稍后详解。

<2> 获取ViewManager对象,调用ViewManager对象的addView方法

 

 

performResumeActivity方法源码

public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,String reason) {
    final ActivityClientRecord r = mActivities.get(token);
        
    if (r.getLifecycleState() == ON_RESUME) {
            
        if (finalStateRequest) {
            r.hideForNow = false;
            r.activity.mStartedActivity = false;
        }
        try {
            r.activity.onStateNotSaved();
            r.activity.mFragments.noteStateNotSaved();
            checkAndBlockForNetworkAccess();
            if (r.pendingIntents != null) {
                deliverNewIntents(r, r.pendingIntents);
                r.pendingIntents = null;
            }
            if (r.pendingResults != null) {
                deliverResults(r, r.pendingResults, reason);
                r.pendingResults = null;
            }
            r.activity.performResume(r.startsNotResumed, reason);

            r.state = null;
            r.persistentState = null;
            r.setState(ON_RESUME);
        } catch (Exception e) {
           
        }
        return r;
}
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();

该方法的核心就是 通过Binder获取ActivityClientRecord 对象。

 

因为 上述  获取ViewManager对象,调用ViewManager对象addView方法。 所以我们看一下ViewManager

/** Interface to let you add and remove child views to an Activity. To get an instance
  * of this class, call {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
  */
public interface ViewManager
{
    /**
     * Assign the passed LayoutParams to the passed View and add the view to the window.
     * <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming
     * errors, such as adding a second view to a window without removing the first view.
     * <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a
     * secondary {@link Display} and the specified display can't be found
     * (see {@link android.app.Presentation}).
     * @param view The view to be added to this window.
     * @param params The LayoutParams to assign to view.
     */
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

ViewManager是一个接口,提供了 添加View 更新View 删除View 方法。

 

WindowManager接口 继承了  ViewManager接口

public interface WindowManager extends ViewManager

 

WindowManagerImpl类 实现了 WindowManager接口

public final class WindowManagerImpl implements WindowManager {

}

 

所以 ViewManager对象的addView方法 其实执行的是 WindowManagerImpl类的addView方法

 

WindowManagerImpl类addView方法源码

private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();


@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}

也就是说,该方法的核心代码是 执行WindowManagerGlobal类的addView方法

 

 

WindowManagerGlobal类addView方法源码

private final ArrayList<View> mViews = new ArrayList<View>();
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
private final ArrayList<WindowManager.LayoutParams> mParams =new ArrayList<WindowManager.LayoutParams>();


public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow) {
    

    ViewRootImpl root;
    View panelParentView = null;

    synchronized (mLock) {
        
        //核心代码1 创建ViewRootImpl
        root = new ViewRootImpl(view.getContext(), display);

        view.setLayoutParams(wparams);

        //核心代码2 将view和root存入ArrayList集合中
        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);

        
        try {

            //核心代码3 调用ViewRootImpl的setView方法
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
           
        }
    }
}

也就是说,WindowManagerGlobal类的addView方法 核心代码就是创建ViewRootImpl对象,并且调用ViewRootImpl的setView方法

 

ViewRootImpl类构造方法源码

public ViewRootImpl(Context context, Display display) {
    
    //获取上下文对象
    mContext = context;

    
    //是一个Binder对象,用于进程间通信
    mWindowSession = WindowManagerGlobal.getWindowSession();
      

    //获取当前线程 requestLayout时,检测是否主线程更新UI 
    mThread = Thread.currentThread();
       
}

 

ViewRootImpl类setView方法源码

/**
 * We have one child
 */
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
        if (mView == null) {
            mView = view;

             requestLayout();
                
            
            if (res < WindowManagerGlobal.ADD_OKAY) {
                    
                switch (res) {
                    case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
                    case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
                        throw new WindowManager.BadTokenException(
                                "Unable to add window -- token " + attrs.token
                                + " is not valid; is your activity running?");
                    case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
                        throw new WindowManager.BadTokenException(
                                "Unable to add window -- token " + attrs.token
                                + " is not for an application");
                        case WindowManagerGlobal.ADD_APP_EXITING:
                            throw new WindowManager.BadTokenException(
                                    "Unable to add window -- app for token " + attrs.token
                     
            }
               
        }
    }
}

也就是说,ViewRootImpl类的setView方法 核心代码就是执行requestLayout()方法,并且根据WindowManagerGlobal的状态 抛出不同的window异常。

 

requestLayout()方法源码

@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
    }
}

 

checkThread()方法源码

void checkThread() {
    if (mThread != Thread.currentThread()) {
        throw new CalledFromWrongThreadException(
                "Only the original thread that created a view hierarchy can touch its views.");
    }
}

 

 

 

 

 

 

 

二.总结

 

1.总结

<1> 通过 ActivityThread类 的  handleResumeActivity方法 执行到Activity的onResume方法

<2> 该方法 核心功能有  通过Binder获取ActivityClientRecord对象通过ActivityClientRecord对象获取Activity对象通过Activity对象获取ViewManager对象,最后执行ViewManager的addView方法

<3> ViewManager是接口WindowManager也是接口并且继承ViewManagerWindowManagerImpl类 实现了 WindowManager接口。WindowManagerImpl类的addView方法调用的是WindowManagerGlobal类的addView方法

<4> WindowManagerGlobal类的addView方法中 初始化了ViewRootImpl对象

root = new ViewRootImpl(view.getContext(), display);

 

 

 

2.Activity、PhoneWindow、DecorView、ViewRootImpl 这几个关键的知识点


<1> Activity:Android四大组件之一。在ActivityThread类中的performLaunchActivity方法中,利用Instrumentation类的newActivity方法,传参ClassLoader对象 创建Activity。


<2> PhoneWindow:Window类的继承类,(包名:com.android.internal.policy),是Activity和View交互的中间层,主要的操作是:创建DecorView,处理输入法等等。在Activity类的attach方法中初始化。


<3> DecorView:窗体的顶级视图,继承FrameLayout类,在PhoneWindow类的构造方法中和setContentView方法执行installDecor()方法时初始化。主要用来生成一个id是com.android.internal.R.id.content的ViewGroup。


<4> ViewRootImpl:创建时机是 在ActivityThread类中的handleResumeActivity方法中,准备执行Activity的onResume方法时,使用ViewManager对象添加View。最终走到WindowManagerGlobal类的addView方法,在此方法中创建ViewRootImpl对象。ViewRootImpl主要用来绘制View。

 

 

 


3.子线程不能更新UI问题

ViewRootImpl类中有一个checkThread方法。而checkThread()方法调用地方比较多,比如本类的requestLayout()方法就会调用。也就是说绘制View的时候,可能会执行到这个方法。所以子线程不能更新UI。但是某些特殊的情况下子线程更新UI也是没有问题的。


具体详情:https://blog.csdn.net/weixin_37730482/article/details/72851014

 

 

 

4.UI优化

了解了Activity的启动过程,从onCreate方法到setContentView方法再到onResume方法。我们可以总结出几点UI优化的内容。

<1> 我们的页面在滑动或者首次打开的时候,最主要是加载布局,加载布局耗时点主要在inflate布局,而inflate布局主要耗时分为两部分:读取、解析layout xml文件耗时。反射创建View耗时。

<2> 所以为了减少加载布局的耗时,我们可以优化一下我们的布局,主要是减少布局嵌套。

详情:https://blog.csdn.net/weixin_37730482/article/details/76157085

<3> UI的卡顿,主要发生在主线程,所以一些耗时的操作我们最好在子线程中操作。

详情:https://blog.csdn.net/weixin_37730482/article/details/72781767

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值