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

Android FrameWork AMS+WMS+PMS详解(上)

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

 

 

Android FrameWork AMS+WMS+PMS详解(下)

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

 

 

本章节 我们从ActivityThread的performLaunchActivity方法开始我们的讲解。

 

 

 

一.Activity启动流程之onCreate方法

 

 

源码讲解之 ActivityThread类

 

performLaunchActivity方法源码

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ActivityInfo aInfo = r.activityInfo;
    if (r.packageInfo == null) {
        r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                Context.CONTEXT_INCLUDE_CODE);
    }

    ComponentName component = r.intent.getComponent();
    if (component == null) {
        component = r.intent.resolveActivity(
            mInitialApplication.getPackageManager());
        r.intent.setComponent(component);
    }

    if (r.activityInfo.targetActivity != null) {
        component = new ComponentName(r.activityInfo.packageName,
                r.activityInfo.targetActivity);
    }

    ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        StrictMode.incrementExpectedActivityCount(activity.getClass());
        r.intent.setExtrasClassLoader(cl);
        r.intent.prepareToEnterProcess();
        if (r.state != null) {
            r.state.setClassLoader(cl);
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(activity, e)) {
            throw new RuntimeException(
                "Unable to instantiate activity " + component
                + ": " + e.toString(), e);
        }
    }

    try {
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);

        if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
        if (localLOGV) Slog.v(
                TAG, r + ": app=" + app
                + ", appName=" + app.getPackageName()
                + ", pkg=" + r.packageInfo.getPackageName()
                + ", comp=" + r.intent.getComponent().toShortString()
                + ", dir=" + r.packageInfo.getAppDir());

        if (activity != null) {
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mCompatConfiguration);
            if (r.overrideConfig != null) {
                config.updateFrom(r.overrideConfig);
            }
            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                    + r.activityInfo.name + " with config " + config);
            Window window = null;
            if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                window = r.mPendingRemoveWindow;
                r.mPendingRemoveWindow = null;
                r.mPendingRemoveWindowManager = null;
            }
            appContext.setOuterContext(activity);
            activity.attach(appContext, this, getInstrumentation(), r.token,
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,
                    r.embeddedID, r.lastNonConfigurationInstances, config,
                    r.referrer, r.voiceInteractor, window, r.configCallback);

            if (customIntent != null) {
                activity.mIntent = customIntent;
            }
            r.lastNonConfigurationInstances = null;
            checkAndBlockForNetworkAccess();
            activity.mStartedActivity = false;
            int theme = r.activityInfo.getThemeResource();
            if (theme != 0) {
                 activity.setTheme(theme);
            }

            activity.mCalled = false;
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
            if (!activity.mCalled) {
                 throw new SuperNotCalledException(
                    "Activity " + r.intent.getComponent().toShortString() +
                    " did not call through to super.onCreate()");
             }
            r.activity = activity;
        }
        r.setState(ON_CREATE);

        mActivities.put(r.token, r);

    } catch (SuperNotCalledException e) {
        throw e;

    } catch (Exception e) {
        if (!mInstrumentation.onException(activity, e)) {
            throw new RuntimeException(
                "Unable to start activity " + component
                + ": " + e.toString(), e);
        }
    }

    return activity;
}

 

1.注释


源码注释:Core implementation of activity launch. 

翻译:启动Activity的核心。也就是说这个方法是启动Activity的入口。

 

 

2.核心代码

 

<1> 初始化上下文对象

ContextImpl appContext = createBaseContextForActivity(r);
class ContextImpl extends Context {

}

 

<2> 获取ClassLoader

java.lang.ClassLoader cl = appContext.getClassLoader();

 

<3> 使用上述获取的ClassLoader对象创建Activity 具体执行的是Instrumentation类的方法 稍后详解

activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);

 

<4> makeApplication 具体执行的是LoadedApk类的方法 稍后讲解

Application app = r.packageInfo.makeApplication(false, mInstrumentation);

 

<5> 执行Activity类attach方法 稍后讲解

activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);

 

<6> 执行Activity的onCreate方法 具体执行的是Instrumentation类的方法 稍后详解

if (r.isPersistable()) {
    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
    mInstrumentation.callActivityOnCreate(activity, r.state);
}

 

小结1

ActivityThread类的performLaunchActivity方法是启动Activity的入口。此方法中主要的核心功能是

初始化上下文对象获取ClassLoader对象使用ClassLoader对象创建Activity对象初始化Application的相关方法(核心是执行Application的onCreate方法)调用Activity的attach方法最后调用Activity的onCreate方法

 

 

 

 

源码讲解之 Instrumentation类

 

因为上述的 使用ClassLoader对象创建Activity  执行Activity的onCreate方法  都是执行的Instrumentation类的方法。所以看一下这个类。

 

<1> 创建Activity

public Activity newActivity(ClassLoader cl, String className,
        Intent intent)
        throws InstantiationException, IllegalAccessException,
        ClassNotFoundException {
    String pkg = intent != null && intent.getComponent() != null
            ? intent.getComponent().getPackageName() : null;
    return getFactory(pkg).instantiateActivity(cl, className, intent);
}

 

AppComponentFactory类的instantiateActivity方法源码

public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className,
        @Nullable Intent intent)
        throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    return (Activity) cl.loadClass(className).newInstance();
}

也就是说,该方法大致的意思就是通过ClassLoader创建一个Activity类的对象。

 

 

<2> 调用Activity的onCreate方法 具体执行的是Activity类的方法 稍后详解

public void callActivityOnCreate(Activity activity, Bundle icicle) {
    prePerformCreate(activity);
    activity.performCreate(icicle);
    postPerformCreate(activity);
}

 

 

小结2

也就是,创建Activity,调用Activity的onCreate方法。都是通过Instrumentation类的相关方法执行的。

 

 

 

 

源码讲解之 LoadedApk类

 

因为上述的 makeApplication方法  执行的LoadedApk类的方法。所以看一下这个类。

 

makeApplication方法源码

public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {


   
   
    //核心代码 通过Instrumentation类执行Application的onCreate方法
    instrumentation.callApplicationOnCreate(app);


}

 

 

小结3

ActivityThread类的makeApplicatio方法 执行到 LoadedApk类的makeApplication方法  最后执行到  Instrumentation类的callApplicationOnCreate方法。即执行Application的onCreate方法。

 

 

 

 

源码讲解之 Activity类

 

因为上述ActivityThread类的performLaunchActivity方法执行了activity.attach方法。所以看一下Activity类的attach方法。

 

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, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback) {

        
      //操作FragmentController
      mFragments.attachHost(null /*parent*/);



      //创建Window对象 Window是抽象类 这里使用的PhoneWindow类 
      mWindow = new PhoneWindow(this, window, activityConfigCallback);
      mWindow.setWindowControllerCallback(this);
      mWindow.setCallback(this);
      mWindow.setOnWindowDismissedCallback(this);
      mWindow.getLayoutInflater().setPrivateFactory(this);
       

      
     //初始化输入法  
     if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
         mWindow.setSoftInputMode(info.softInputMode);
     }
        
    
    //private Thread mUiThread; UI线程赋值
    mUiThread = Thread.currentThread();

    //ActivityThread mMainThread; Main线程赋值
    mMainThread = aThread;
    
    //获取WindowManager 
    //Activity mParent; private Window mWindow;private WindowManager mWindowManager;
    mWindow.setWindowManager(
            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
            mToken, mComponent.flattenToString(),
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    if (mParent != null) {
        mWindow.setContainer(mParent.getWindow());
    }
    mWindowManager = mWindow.getWindowManager();

}

 

 

小结4

Activity类的attach方法主要的核心功能是。

使用PhoneWindow类创建Window对象初始化输入法相关内容初始化主线程内容获取WindowManager对象

 

 

 

总结

到这里,就执行到了Activity的onCreate方法。大致的流程是

<1> ActvityThread类的performLaunchActivity方法是入口。

<2> performLaunchActivity方法中主要的操作是 初始化上下文对象获取ClassLoader对象使用ClassLoader对象创建Activity对象初始化Application的相关方法(核心是执行Application的onCreate方法)

调用Activity的attach方法最后调用Activity的onCreate方法

<3> 通过performLaunchActivity方法中核心代码的操作顺序,我们可以获悉 Activity的onCreate方法要比Application的onCreate方法晚执行。

 

 

 

 

 

 

 

 

二.Activity启动流程之setContentView方法

 

上述讲解了通过 ActivityThread类的 performLaunchActivity方法 最终到达Activity的onCreate方法。也就是执行Activity的onCreate方法。接下来看一下setContentView方法。

 

setContentView方法有几个重载的方法。

//传一个布局文件Id 
public void setContentView(@LayoutRes int layoutResID)


//传一个View
public void setContentView(View view) 


//传一个View和LayoutParams对象
public void setContentView(View view, ViewGroup.LayoutParams params)

这里,我们以 传一个布局文件Id的方法为例。

 

因为我们的Activity依赖关系是

//我们自己的Activity MainActivity 
public class MainActivity extends AppCompatActivity 



//AppCompatActivity 继承 FragmentActivity
public class AppCompatActivity extends FragmentActivity



//FragmentActivity 继承 ComponentActivity 
public class FragmentActivity extends ComponentActivity



//ComponentActivity 继承 Activity
public class ComponentActivity extends Activity



也就是说自己的Activity的setContentView方法



首先会执行Activity的setContentView方法。其次会执行AppCompatActivity的setContentView方法

所以,我们自己写的Activity的setContentView(R.layout.activity_main);方法,会执行Activity的setContentView方法。然后执行AppCompatActivity的setContentView方法。

 

 

Activity的setContentView方法说明

 

Activity类的setContentView方法源码

public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

可以看出,Activity类的setContentView方法 调用  Window类的setContentView方法

 

getWindow()方法源码

//Activity类中的全局变量
private Window mWindow;



//Activity类中 获取Window对象的方法
public Window getWindow() {
    return mWindow;
}



//Activity类中 初始化Window对象的方法
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,
            Window window, ActivityConfigCallback activityConfigCallback) {


    mWindow = new PhoneWindow(this, window, activityConfigCallback);
   
}
public abstract class Window {


}

也就是说 Window类是抽象类。在Activity类的attach方法中用PhoneWindow类初始化。所以  Window类的setContentView方法  其实是调用   PhoneWindow类的setContentView方法

 

PhoneWindow类的setContentView方法源码

//全局变量 这是放置窗口内容的视图。它要么是mDecor本身,要么是mDecor的一个子目录。
//This is the view in which the window contents are placed. It is either mDecor itself, or a child of mDecor where the contents go.
ViewGroup mContentParent;


@Override
public void setContentView(int layoutResID) {


    //首次执行setContentView方法时 mContentParent为空 所以installDecor方法会执行
    if (mContentParent == null) {
        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 {

         //首次执行setContentView方法时 会执行此方法 将刚刚生成的mContentParent作为父View解析xml文件
         mLayoutInflater.inflate(layoutResID, mContentParent);
     }

    ...
}

 

PhoneWindow类的installDecor方法源码

private void installDecor() {
        
    if (mDecor == null) {
        mDecor = generateDecor(-1);
        mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        mDecor.setIsRootNamespace(true);
        if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
            mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
        }
    } else {
        mDecor.setWindow(this);
    }


    //利用刚刚的DecorView生成一个ViewGroup
    if (mContentParent == null) {
        mContentParent = generateLayout(mDecor);
       
        ...
    }

    
    ...
        
}

上述方法中,使用了一个变量mDecor,那么mDecor是个什么东西呢?又是在什么地方赋值的呢?下面看

// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;

mDecor是PhoneWindow类的全局变量。注释说明:mDector 是窗体的顶级视图。

public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {



}

DecorView其实是一个FrameLayout。

 

赋值时机1

public PhoneWindow(Context context, Window preservedWindow,ActivityConfigCallback activityConfigCallback) {

    
    //此构造方法是在Activity类的attach方法中调用 而Activity类的attach方法在ActivityThread类的performLaunchActivity方法中调用 传入Window对象
    if (preservedWindow != null) {
        
       mDecor = (DecorView) preservedWindow.getDecorView();
    
    }

}

也就是说赋值时机之一是在PhoneWindow类的构造方法中赋值。

 

然后上面的installDecor方法使用时判断,如果是空重新获取。否则直接使用。

 

上面还调用了一个generateLayout方法

protected ViewGroup generateLayout(DecorView decor) {


     ...
     
     if (a.getBoolean(R.styleable.Window_windowLightStatusBar, false)) {
         decor.setSystemUiVisibility(
                 decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
     }
  
     if (a.getBoolean(R.styleable.Window_windowLightNavigationBar, false)) {
         decor.setSystemUiVisibility(
                 decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
     }


     ...

     
     //ID_ANDROID_CONTENT:com.android.internal.R.id.content 下面 ppCompatActivity的setContentView方法会用到
     ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);


     return contentParent;

}

这个方法就是将DecorView 转化成ViewGroup。

 

继续看PhoneWindow类的setContentView方法

mLayoutInflater.inflate(layoutResID, mContentParent);

也就是,通过LayoutInflater解析布局。传入刚刚生成的ViewGroup mContentParent(这是放置窗口内容的视图。它要么是mDecor本身,要么是mDecor的一个子目录)  传入的布局xml文件解析成View。

 

LayoutInflater类的inflate方法源码

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
    return inflate(resource, root, root != null);
}




public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
    final Resources res = getContext().getResources();
    if (DEBUG) {
        Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
                + Integer.toHexString(resource) + ")");
    }

    final XmlResourceParser parser = res.getLayout(resource);
    try {
        return inflate(parser, root, attachToRoot);
    } finally {
        parser.close();
    }
}



public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
        synchronized (mConstructorArgs) {



   final View temp = createViewFromTag(root, name, inflaterContext, attrs);
   
   temp.setLayoutParams(params);  


}

其实,LayoutInflater类的inflate方法。我们可以理解就会解析xml文件成View。

 

View类的setLayoutParams()方法源码

public void setLayoutParams(ViewGroup.LayoutParams params) {
    if (params == null) {
        throw new NullPointerException("Layout parameters cannot be null");
    }
    mLayoutParams = params;
    resolveLayoutParams();
    if (mParent instanceof ViewGroup) {
         (ViewGroup) mParent).onSetLayoutParams(this, params);
    }
    requestLayout();
}

也就是说,LayoutInflater类的inflate方法中解析xml布局文件成View时,会调用View或者ViewGroup的requestLayout();方法。

 

 

 

小结1

通过Activity源码中的setContentView方法可知。

<1> 调用关系是:Activity类的setContentView方法  到  Window类的setContentView方法   到  PhoneWindow类的setContentView方法

<2> PhoneWindow类的setContentView方法重要的核心操作是 创建DecorView (窗体的顶级视图) (构造方法中初始化 然后setContentView时判断是否为空 为空重新初始化 否则直接使用)。然后利用DecorView 生成一个 ViewGroup mContentParent对象(放置窗体内容的容器)。最后结合这个mContentParent(为父布局)和我们传入的xml布局文件,利用LayoutInflater类的inflate方法生成了一个多层结构的View。

<3> PhoneWindow类的初始化是在Activity的源码中的attach()方法中初始化的。

<4> LayoutInflater类的inflate方法解析xml文件时,会调用到View或者ViewGroup的requestLayout();方法。

 

 

 

 

 

 

 

AppCompatActivity的setContentView方法说明

 

AppCompatActivity类的setContentView方法源码

@Override
public void setContentView(@LayoutRes int layoutResID) {
    getDelegate().setContentView(layoutResID);
}

 

AppCompatActivity类的getDelegate方法源码

@NonNull
public AppCompatDelegate getDelegate() {
    if (mDelegate == null) {
         mDelegate = AppCompatDelegate.create(this, this);
    }
    return mDelegate;
}

 

AppCompatDelegate类的create方法源码

@NonNull
public static AppCompatDelegate create(@NonNull Activity activity,
        @Nullable AppCompatCallback callback) {
    return new AppCompatDelegateImpl(activity, callback);
}

上述可以看出,AppCompatDelegate类是一个抽象类,所以  AppCompatDelegate类的setContentView方法  其实执行的是  AppCompatDelegateImpl类的setContentView方法


AppCompatDelegateImpl类的setContentView方法源码

@Override
public void setContentView(int resId) {
    ensureSubDecor();
    ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
    contentParent.removeAllViews();
    LayoutInflater.from(mContext).inflate(resId, contentParent);
    mAppCompatWindowCallback.getWrapped().onContentChanged();
}

通过 android.R.id.content 获取一个 ViewGroup。这个ViewGroup其实就是上述PhoneWindow类中setContentView方法中生成的DecorView,然后再 利用DecorView生成的ViewGroup。最后将刚刚获取的ViewGroup为父布局,利用LayoutInflater解析xml布局。这个布局才真正是我们的 ContentView。下面图片中的框框中的布局。

 

 

总结

到这里,setContentView方法的工作算是完成了。简单的说。有几个核心的内容。

<1> Activity的setContentView方法说明

      Activity类的setContentView方法  到  Window类的setContentView方法   到  PhoneWindow类的setContentView方法 创建了DecorView 并且通过DecorView生成一个ViewGroup ViewGroup的id是com.android.internal.R.id.content。

<2> AppCompatActivity的setContentView方法

       通过上述生成的id是com.android.internal.R.id.content的ViewGroup为父布局 解析自己的布局文件。

 

 

说明

 

AndroidStudio的Layout Inspector使用说明。

 

(AndroidStudio)   (Tools)   (Layout Inspector) (运行程序到某个想看的页面) 生成View树形结构

 

我的布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/activity_view_TextView"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="@color/colorPrimary"
        android:gravity="center"
        android:text="张三"
        android:textColor="#FFFFFF">

    </TextView>

</LinearLayout>

我们布局中  根布局是LinearLayout  里面有一个TextView。但是View树形结构中 系统给我们添加了好多东西。

比如 最外层的DecorView 

比如 手机屏幕下面的导航栏 navigationBarBackground 

比如 手机屏幕上面的状态栏 statusBarBackground 

 

这也能说明 setContentView给我们创建了一些系统的View。

 

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值