Android點將臺:顏值擔當[-Activity-]

我的全部文章整理在此篇,將陸續更新收錄:知無涯,行者之路莫言終(個人編程之路)java


零、前言

1.本文的知識點
[1].Acticity生命週期測試與分析  
[2].Activity間的[數據傳遞]  
[3].Activity的四種[啓動模式]詳細分析  
[4].Activity的[跳轉動畫] 
[5].Acticity的生命[週期源碼]分析
複製代碼

2.Activity總覽

Activity.png

類名:Activity      父類:ContextThemeWrapper      修飾:public
包名:android.app   依賴類個數:115
內部類/接口個數:5
源碼行數:7754       源碼行數(除註釋):3197
屬性個數:20       方法個數:282       public方法個數:245
複製代碼

Activity繼承關係.png


1、生命週期測試:

1.打開與關閉

打開與關閉.png

1.1.打開LifeCycleActivity:
2019-01-19 14:06:10.614 : LifeCycleActivity--onCreate: 
2019-01-19 14:06:10.617 : LifeCycleActivity--onStart: 
2019-01-19 14:06:10.634 : LifeCycleActivity--onResume: 
複製代碼
1.2.返回鍵關閉LifeCycleActivity:
2019-01-19 14:08:52.675 : LifeCycleActivity--onPause: 
2019-01-19 14:08:53.247 : LifeCycleActivity--onStop: 
2019-01-19 14:08:53.249 : LifeCycleActivity--onDestroy: 
複製代碼

2.跳轉普通Activity時兩個Activity的生命週期

普通跳轉與返回.png

2.1.在LifeCycleActivity中打開CommonActivity:
2019-01-19 14:15:57.454 : LifeCycleActivity--onPause: 
2019-01-19 14:15:57.495 : CommonActivity--onCreate: 
2019-01-19 14:15:57.497 : CommonActivity--onStart: 
2019-01-19 14:15:57.501 : CommonActivity--onResume: 
2019-01-19 14:15:58.256 : LifeCycleActivity--onStop: 
複製代碼
2.2.CommonActivity返回鍵到LifeCycleActivity:
2019-01-19 14:19:09.511 : CommonActivity--onPause: 
2019-01-19 14:19:09.527 : LifeCycleActivity--onRestart: 
2019-01-19 14:19:09.528 : LifeCycleActivity--onStart: 
2019-01-19 14:19:09.529 : LifeCycleActivity--onResume: 
2019-01-19 14:19:09.963 : CommonActivity--onStop: 
2019-01-19 14:19:09.963 : CommonActivity--onDestroy: 
複製代碼

3.跳轉對話框Activity時兩個Activity的生命週期

打開對話框Activity.png

3.1.在LifeCycleActivity中打開DialogActivity:
2019-01-19 14:43:32.842 : LifeCycleActivity--onPause: 
2019-01-19 14:43:32.908 : DialogActivity--onCreate: 
2019-01-19 14:43:32.910 : DialogActivity--onStart: 
2019-01-19 14:43:32.912 : DialogActivity--onResume:
複製代碼
3.2.DialogActivity返回鍵到LifeCycleActivity:
2019-01-19 14:44:45.771 : DialogActivity--onPause: 
2019-01-19 14:44:45.812 : LifeCycleActivity--onResume: 
2019-01-19 14:44:45.874 : DialogActivity--onStop: 
2019-01-19 14:44:45.874 : DialogActivity--onDestroy: 
複製代碼

4.LifeCycleActivity旋轉屏幕(至關於關閉再開啓):

橫豎屏切換時.png

2019-01-19 14:46:28.619 : LifeCycleActivity--onPause: 
2019-01-19 14:46:28.639 : LifeCycleActivity--onStop: 
2019-01-19 14:46:28.639 : LifeCycleActivity--onDestroy: 
2019-01-19 14:46:28.743 : LifeCycleActivity--onCreate: 
2019-01-19 14:46:28.744 : LifeCycleActivity--onStart: 
2019-01-19 14:46:28.751 : LifeCycleActivity--onResume: 
複製代碼

activity生命週期測試總覽(電腦上查看原圖效果最佳)android

activity生命週期.gif


五、保存數據:

onStop以前,會調用onSaveInstanceState 其中有一個Bundle對象能夠用來儲存數據
該對象即是onCreate中的Bundle對象savedInstanceState,下圖旋轉屏時使用onSaveInstanceState編程

onSaveInstanceState.png

override
fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.ac_lifecycle)
    title = "LifeCycleActivity"
    if (savedInstanceState != null) {
        title = savedInstanceState.getString("name")
    }
}

override fun onSaveInstanceState(outState: Bundle?) {
    super.onSaveInstanceState(outState)
    Log.e(TAG, "LifeCycleActivity--onSaveInstanceState: ")
}
複製代碼

2、生命週期方法解釋:

之所謂生命週期,就是從生到死有明確的回調函數
函數在不一樣狀態下由安卓框架層進行回調,簡化開發流程。
讓開發者使用時只須要關注Activity狀態,根據狀態構建邏輯,而無需深刻底層實現。
Activity主要有7個生命週期回調函數,以下,是最經典的Activity生命週期圖示:bash

Activity生命週期

建立:onCreate():
    |---可用於初始化工做,如setContentView界面資源、初始化數據
啓動:onStart():
    |---可見但沒法交互
恢復:onResume():
    |---恢復播放動畫、音樂、視頻等
暫停:onPause():
    |---可作數據存儲、中止動畫、音樂、視頻等
中止:onStop():
    |---此時Activity不可見,可作視狀況作些重量級回收工做,避免被Killed
銷燬:onDestroy():
    |---回收工做、資源釋放
重現:onRestart():
    |---可作一些恢復工做
複製代碼

3、Activity間的數據傳遞

傳遞數據.png

1.實體類:Person
/**
 * 做者:張風捷特烈
 * 時間:2018/4/26:12:13
 * 郵箱:1981462002@qq.com
 * 說明:簡單實體Person
 */
class Person(var name: String?, var age: Int) : Serializable {
    override fun toString(): String {
        return "Person{" +
                "name='" + name + '\''.toString() + ", age=" + age + '}'.toString() } } 複製代碼

2.傳遞基本數據類型、Serializable對象、Parcelable對象

注意Bundle不能傳遞過大數據app

傳遞基本數據類型和Serializable對象,Parcelable對象.png

---->[FromActivity點擊]-----------
id_btn_for_result.setOnClickListener {
    val intent = Intent(this, ToActivity::class.java)
    val bundle = Bundle()
    bundle.putSerializable("person", Person("form", 24))
    val bitmap = BitmapFactory.decodeResource(resources, R.mipmap.wall_a)
    bundle.putParcelable("bitmap", bitmap)
    intent.putExtra("from", bundle)
    intent.putExtra("title", "張風捷特烈")
    startActivity(intent)

---->[ToActivity接收使用]-----------
val title = intent.getStringExtra("title")
if (title != null) {
    this.title = title
}
val extra = intent.getBundleExtra("from")
if (extra != null) {
    val from = extra.get("person") as Person
    val icon = extra.get("bitmap") as Bitmap
    id_tv_result.text = from.toString()
    id_iv_icon.setImageBitmap(icon)
}
複製代碼

3.FromActivity使用startActivityForResult打開ToActivity接返回值

startActivityForResult.png

startActivityForResult測試.png

---->[FromActivity]-----------
companion object {
    private const val DATA_CODE = 0x0001
}
//點擊時
id_btn_for_result.setOnClickListener {
    val intent = Intent(this, ToActivity::class.java)
    startActivityForResult(intent, DATA_CODE)
}
//回調
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
    when (requestCode) {
        DATA_CODE -> if (resultCode == Activity.RESULT_OK) {
            val dataFormTarget = data.getStringExtra("data")
            val personData = data.getBundleExtra("To")
            val person = personData.get("person") as Person
            id_tv_result_back.text = ("dataFormTarget:" + dataFormTarget
                    + "\nperson:" + person.toString())
        }
    }
}

---->[ToActivity傳遞數據給FromActivity]-----------
private fun backWithData() {
    val jt = Person("捷特", 24)
    val intent = Intent()
    intent.putExtra("data", "我是ToActivity的數據")
    val bundle = Bundle()
    bundle.putSerializable("person", jt)
    intent.putExtra("To", bundle)
    setResult(Activity.RESULT_OK, intent)
}
複製代碼

4.打開圖庫並設置圖片

打開圖庫選擇圖片.png

//點擊圖片
id_iv_icon.setOnClickListener {
    val intent = Intent(Intent.ACTION_PICK)
    intent.type = "image/*";
    startActivityForResult(intent, 0)
}

//處理結果
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == 0 && resultCode == Activity.RESULT_OK) {//成功
        val selectedImage = data?.data ?: return
        val filePathColumn = arrayOf(MediaStore.Images.Media.DATA)
        val cursor = contentResolver.query(// 獲取選擇照片的數據視圖
            selectedImage, filePathColumn, null, null, null
        )
        cursor.moveToFirst()
        // 從數據視圖中獲取已選擇圖片的路徑
        val columnIndex = cursor.getColumnIndex(filePathColumn[0])
        val picturePath = cursor.getString(columnIndex)
        cursor.close()
        id_iv_icon.setImageBitmap(BitmapFactory.decodeFile(picturePath))
    }
}
複製代碼

3、Activity的四種啓動模式

Activity任務棧:Activity的活動序列框架

standard:標準棧
singleTop:頂複用棧
singleTask:對象惟一棧
singleInstance:單獨實例棧
複製代碼

1.standard: 標準棧

當啓動一個Activity,建立該Activity的新實例。入棧處於棧頂
測試:Activity一、2皆爲standardide

standard.png

standard.gif

依次打開Activity一、二、二、一、2
 E/TASK_ID: Activity1 Task id is 89
 E/TASK_ID: Activity2 Task id is 89
 E/TASK_ID: Activity2 Task id is 89
 E/TASK_ID: Activity1 Task id is 89
 E/TASK_ID: Activity2 Task id is 89
依次返回
 E/TASK_ID: Activity2 銷燬
 E/TASK_ID: Activity1 銷燬
 E/TASK_ID: Activity2 銷燬
 E/TASK_ID: Activity2 銷燬
 E/TASK_ID: Activity1 銷燬
複製代碼

2:singleTop模式:頂複用棧

在啓動活動時若棧頂已是該Activity,則直接使用它,不建立實例
測試:Activity1爲standard, Activity2 爲singleTop函數

singleTop.png

singleTop.gif

依次打開Activity一、二、二、一、2
E/TASK_ID: Activity1 Task id is 82
E/TASK_ID: Activity2 Task id is 82
E/TASK_ID: Activity1 Task id is 82
E/TASK_ID: Activity2 Task id is 82
依次返回
E/TASK_ID: Activity2 銷燬
E/TASK_ID: Activity1 銷燬
E/TASK_ID: Activity2 銷燬
E/TASK_ID: Activity1 銷燬
複製代碼

3:singleTask模式:對象惟一棧

整個棧中沒有相同的實例,兩次相同實例之間的Activity會被殺死(夠霸道,我喜歡)
測試:Activity1爲standard, Activity2 爲singleTaskoop

singleTask.png

singleTask.gif

依次打開Activity一、二、二、一、2
E/TASK_ID: Activity1 Task id is 94
E/TASK_ID: Activity2 Task id is 94
E/TASK_ID: Activity1 Task id is 94
E/TASK_ID: Activity1 銷燬
依次返回
E/TASK_ID: Activity2 銷燬
E/TASK_ID: Activity1 銷燬
複製代碼

4:singleInstance 單獨實例棧

啓用一個新的活動棧來管理這個活動(夠豪,夠任性)
測試:Activity1爲standard, Activity2 singleInstance源碼分析

singleInstance.png

singleInstance.gif

依次打開Activity一、二、二、一、2
 E/TASK_ID: Activity1 Task id is 115
 E/TASK_ID: Activity2 Task id is 116
 E/TASK_ID: Activity1 Task id is 115
依次返回
 E/TASK_ID: Activity2 銷燬
 E/TASK_ID: Activity1 銷燬
 E/TASK_ID: Activity1 銷燬
複製代碼

注意一點:
singleTask模式和singleTop模式時,非第一次啓動,不會調用onCreate方法!   
但會走onNewIntent方法
複製代碼

4、Activity的跳轉動畫

這裏只是簡單的四個平移動畫,須要的更酷炫的效果道理是同樣的
關於動畫的更多知識,這裏不廢話了,可詳見:Android 動畫 Animator 家族使用指南

默認 修改

1.代碼實現Activity跳轉

Activity跳轉動畫.png

/**
 * 做者:張風捷特烈<br></br>
 * 時間:2019/1/20/020:18:25<br></br>
 * 郵箱:1981462002@qq.com<br></br>
 * 說明:紅色Activity
 */
class RedActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val view = View(this)
        view.setBackgroundColor(Color.RED)
        title = "RedActivity"
        view.setOnClickListener { v ->
            startActivity(Intent(this, BlueActivity::class.java))
            overridePendingTransition(R.anim.open_enter, R.anim.open_exit);
        }
        setContentView(view)
    }
    override fun onBackPressed() {
        super.onBackPressed()
        overridePendingTransition(R.anim.open_enter, R.anim.open_exit);
    }
}

/**
 * 做者:張風捷特烈<br></br>
 * 時間:2019/1/20/020:18:25<br></br>
 * 郵箱:1981462002@qq.com<br></br>
 * 說明:綠色Activity
 */
class BlueActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val view = View(this)
        view.setBackgroundColor(Color.BLUE)
        title = "BlueActivity"
        view.setOnClickListener { v ->
            startActivity(Intent(this, RedActivity::class.java))
            overridePendingTransition(R.anim.close_enter, R.anim.close_exit)
        }
        setContentView(view)
    }
    override fun onBackPressed() {
        super.onBackPressed()//右移入---右移出
                overridePendingTransition(R.anim.close_enter, R.anim.close_exit)
    }
}
複製代碼

2.跳轉動畫
---->[open_enter.xml]----------------------
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:interpolator="@android:anim/decelerate_interpolator">
    <!--左移入-->
    <translate
            android:duration="500"
            android:fromXDelta="100%p"
            android:toXDelta="0%p"/>
</set>

---->[open_exit.xml]----------------------
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:interpolator="@android:anim/decelerate_interpolator">
    <!--左移出-->
    <translate
            android:duration="500"
            android:fromXDelta="0%p"
            android:toXDelta="-100%p"/>
</set>

---->[close_enter.xml----------------------
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:interpolator="@android:anim/decelerate_interpolator">
    <!--右移入-->
    <translate
            android:duration="500"
            android:fromXDelta="-100%p"
            android:toXDelta="0%p"/>
</set>

---->[close_exit.xml]----------------------
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:interpolator="@android:anim/decelerate_interpolator">
    <!--右移出-->
    <translate
            android:duration="500"
            android:fromXDelta="0%p"
            android:toXDelta="100%p"/>
</set>
複製代碼

這樣就能夠了


3.另外還能夠配置動畫的style

用起來比在代碼裏方便些

<!--配置Activity進出動畫-->
<style name="TranAnim_Activity" parent="@android:style/Animation.Activity">
    <item name="android:activityOpenEnterAnimation">@anim/open_enter</item>
    <item name="android:activityOpenExitAnimation">@anim/open_exit</item>
    <item name="android:activityCloseEnterAnimation">@anim/close_enter</item>
    <item name="android:activityCloseExitAnimation">@anim/close_exit</item>
</style>

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:windowAnimationStyle">@style/TranAnim_Activity</item>
</style>
複製代碼

5、Acticity的啓動源碼分析

一直想總結一下Activity的啓動流程(),這裏從Activity的生命週期入手
本文所講述的啓動流程主要是ActivityThread的H在接收到消息以後,即handleMessage
至於消息如何傳遞過來的將在跨進程通訊篇講述

Activity繼承關係.png


1.誰是幕後黑手?
翻一下源碼能夠看出Context只是一個抽象類,定義了不少抽象方法 
而ContextWrapper做爲實現類將全部的工做甩手給了一個mBase的Context成員變量
ContextThemeWrapper寥寥百行代碼,也不會是幕後黑手,如今檯面上只有mBase
複製代碼

ContextWrapper.png


2.Activity是如何建立的?

相信應該沒有人去new Activity(),framework 層是如何建立Activity的實例呢?

Activity實例化.png

---->[ActivityThread]-------
 final H mH = new H();
 
 ---->[ActivityThread$H#handleMessage]-------
public void handleMessage(Message msg) {
 switch (msg.what) {
      case LAUNCH_ACTIVITY: {//啓動Activity
          Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
          //r:記錄Activity的一些描述信息
          final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
          //經過r來獲取包信息
          r.packageInfo = getPackageInfoNoCheck(
                  r.activityInfo.applicationInfo, r.compatInfo);
          //開啓的核心方法(劃重點)
          handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
          Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

 ---->[ActivityThread#handleLaunchActivity]-------
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    //在這裏返回來Activity的對象
    Activity a = performLaunchActivity(r, customIntent);
    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);
        //略...
}

 ---->[ActivityThread#performLaunchActivity]-------
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
 //略...
   ComponentName component = r.intent.getComponent();
   Activity activity = null;
   try {
       java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
       //此處可見是mInstrumentation建立的Activity
       activity = mInstrumentation.newActivity(
               cl, component.getClassName(), r.intent);
       StrictMode.incrementExpectedActivityCount(activity.getClass());
 //略...
    return activity;
    }
    
    
 ---->[Instrumentation#newActivity]-------
 public Activity newActivity(ClassLoader cl, String className,
         Intent intent)
         throws InstantiationException, IllegalAccessException,
         ClassNotFoundException {
    //經過類加載器生成Activity實例
     return (Activity)cl.loadClass(className).newInstance();
 }
 
複製代碼

3.Application實例化及onCreate()方法調用

實現移到剛纔建立Activity的performLaunchActivity方法

Application實例化.png

---->[ActivityThread#performLaunchActivity]-------
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
 //略...
   ComponentName component = r.intent.getComponent();
   Activity activity = null;
   try {
       java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
       activity = mInstrumentation.newActivity(
               cl, component.getClassName(), r.intent);
       StrictMode.incrementExpectedActivityCount(activity.getClass());
 //略...
    try {
    //建立Activity以後經過ActivityClientRecord的packageInfo對象的makeApplication
    //來建立Application,packageInfo是一個LoadedApk類的對象
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
//略...
    }

 ---->[LoadedApk#makeApplication]-------
public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        if (mApplication != null) {
            return mApplication;
        }
        Application app = null;
//略...

        try {
            java.lang.ClassLoader cl = getClassLoader();
//略...
            //這裏ContextImpl出場了
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            //這裏經過mInstrumentation的newApplication方法建立Application對象
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            //將建立的Application設置到appContext上
            appContext.setOuterContext(app);
        }
        //略...
        //mActivityThread將當前app加入mAllApplications列表中
        mActivityThread.mAllApplications.add(app);
        mApplication = app;
        if (instrumentation != null) {
            try {
            //這時調用application的OnCreate方法
                instrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                if (!instrumentation.onException(app, e)) {
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    throw new RuntimeException(
                        "Unable to create application " + app.getClass().getName()
                        + ": " + e.toString(), e);
                }
            }
        }
        return app;
    }

 ---->[Instrumentation#newApplication]-------
public Application newApplication(ClassLoader cl, String className, Context context)
        throws InstantiationException, IllegalAccessException, 
        ClassNotFoundException {
        //也是經過反射獲取Application實例
    return newApplication(cl.loadClass(className), context);
}

 ---->[Instrumentation#callApplicationOnCreate]-------
 public void callApplicationOnCreate(Application app) {
     app.onCreate();//直接調用onCreate onCreate
 }
    

複製代碼

4.Activity的Context的建立及onCreate()方法的調用

Activity的oncreate.png

---->[ActivityThread#performLaunchActivity]-------
 if (activity != null) {
    Context appContext = createBaseContextForActivity(r, activity);
    CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
    //Activity的一些配置信息
    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;
    }
    //將Activity和window綁定
    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);

    if (customIntent != null) {
        activity.mIntent = customIntent;
    }
    r.lastNonConfigurationInstances = null;
    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);
    }


---->[ActivityThread#createBaseContextForActivity]-------
private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
//略...
    //看這裏appContext是ContextImpl類對象,Activity的Context幕後黑手出現了
    ContextImpl appContext = ContextImpl.createActivityContext(
            this, r.packageInfo, r.token, displayId, r.overrideConfig);
    appContext.setOuterContext(activity);
    Context baseContext = appContext;

    final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
    // For debugging purposes, if the activity's package name contains the value of // the "debug.use-second-display" system property as a substring, then show // its content on a secondary display if there is one. String pkgName = SystemProperties.get("debug.second-display.pkg"); if (pkgName != null && !pkgName.isEmpty() && r.packageInfo.mPackageName.contains(pkgName)) { for (int id : dm.getDisplayIds()) { if (id != Display.DEFAULT_DISPLAY) { Display display = dm.getCompatibleDisplay(id, appContext.getDisplayAdjustments(id)); baseContext = appContext.createDisplayContext(display); break; } } } return baseContext; } ---->[ContextImpl#createActivityContext]------- static ContextImpl createActivityContext(ActivityThread mainThread, LoadedApk packageInfo, IBinder activityToken, int displayId, Configuration overrideConfiguration) { if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); return new ContextImpl(null, mainThread, packageInfo, activityToken, null, 0, null, overrideConfiguration, displayId); } ---->[Instrumentation#callActivityOnCreate]------- public void callActivityOnCreate(Activity activity, Bundle icicle, PersistableBundle persistentState) { prePerformCreate(activity); activity.performCreate(icicle, persistentState); postPerformCreate(activity); } ---->[Activity#performCreate]------- final void performCreate(Bundle icicle, PersistableBundle persistentState) { restoreHasCurrentPermissionRequest(icicle); onCreate(icicle, persistentState); mActivityTransitionState.readState(icicle); performCreateCommon(); } ---->[Activity#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) { attachBaseContext(context); mFragments.attachHost(null /*parent*/); //這裏的Window實現類是PhoneWindow mWindow = new PhoneWindow(this, window); 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); } if (info.uiOptions != 0) { mWindow.setUiOptions(info.uiOptions); } mUiThread = Thread.currentThread(); mMainThread = aThread; mInstrumentation = instr; mToken = token; mIdent = ident; mApplication = application; mIntent = intent; mReferrer = referrer; mComponent = intent.getComponent(); mActivityInfo = info; mTitle = title; mParent = parent; mEmbeddedID = id; mLastNonConfigurationInstances = lastNonConfigurationInstances; if (voiceInteractor != null) { if (lastNonConfigurationInstances != null) { mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor; } else { mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this, Looper.myLooper()); } } 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(); mCurrentConfig = config; } 複製代碼

5.Activity的佈局加載

setContentView咱們再熟悉不過了,看一下Activity源碼是如何加載的

添加布局.png

---->[Activity#setContentView]-----------------
public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

//可見是經過Window的setContentView來加載佈局的,
//經過attach方法知道這個window對象是PhoneWindow類

---->[PhoneWindow#setContentView]-----------------
 @Override
 public void setContentView(View view, ViewGroup.LayoutParams params) {
     if (mContentParent == null) {
         installDecor();//初始化DecorView
     } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
         mContentParent.removeAllViews();
     }
     if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
         view.setLayoutParams(params);
         final Scene newScene = new Scene(mContentParent, view);
         transitionTo(newScene);
     } else {
         mContentParent.addView(view, params);
     }
     mContentParent.requestApplyInsets();
     final Callback cb = getCallback();
     if (cb != null && !isDestroyed()) {
         cb.onContentChanged();
     }
 }

---->[PhoneWindow#installDecor]-----------------
 private void installDecor() {
        if (mDecor == null) {
            mDecor = generateDecor();
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        }
        if (mContentParent == null) {
            //經過DecorView來建立mContentParent
            mContentParent = generateLayout(mDecor);
         //對mDecor進行處理,略...
         
---->[PhoneWindow#generateDecor]-----------------
    protected DecorView generateDecor() {
        return new DecorView(getContext(), -1);
    }

>DecorView何許人也?
private final class DecorView extends FrameLayout implements RootViewSurfaceTaker
可見是一個幀佈局FrameLayout,最頂層的視圖
複製代碼

DecorView.png


6.Activity的onResume和onRestart方法的回調

onCreate分析了,onResume基本是差很少,仍是在H類中的
handleMessage中處理信息,當標識爲RESUME_ACTIVITY時,調用handleResumeActivity

onResume.png

---->[ActivityThread#handleMessage]-------
case RESUME_ACTIVITY:
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
    SomeArgs args = (SomeArgs) msg.obj;
    handleResumeActivity((IBinder) args.arg1, true, args.argi1 != 0, true,
            args.argi3, "RESUME_ACTIVITY");
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

---->[ActivityThread#handleResumeActivity]-------
 final void handleResumeActivity(IBinder token,
         boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
     ActivityClientRecord r = mActivities.get(token);
     if (!checkAndUpdateLifecycleSeq(seq, r, "resumeActivity")) {
         return;
     }

     // If we are getting ready to gc after going to the background, well
     // we are back active so skip it.
     unscheduleGcIdler();
     mSomeActivitiesChanged = true;

     // TODO Push resumeArgs into the activity for consideration
     r = performResumeActivity(token, clearHide, reason);

---->[ActivityThread#performResumeActivity]-------
public final ActivityClientRecord performResumeActivity(IBinder token,
        boolean clearHide, String reason) {
    ActivityClientRecord r = mActivities.get(token);
            //略...
            r.activity.performResume();
            
---->[Activity#performResume]-------
final void performResume() {
    performRestart();//可見是先調用了Restart方法
    mFragments.execPendingActions();
    mLastNonConfigurationInstances = null;
    mCalled = false;
    // mResumed is set by the instrumentation
    mInstrumentation.callActivityOnResume(this);
    if (!mCalled) {

---->[Activity#performRestart]-------
final void performRestart() {
        //略...
        mInstrumentation.callActivityOnRestart(this);
//又看到老朋友mInstrumentation了,
//能夠看到Activity的生命週期由mInstrumentation全權負責  
//就連調用本類的一個onRestart方法都要mInstrumentation來轉手

---->[Instrumentation#callActivityOnRestart]-------
public void callActivityOnRestart(Activity activity) {
    activity.onRestart();
}

---->[Instrumentation#callActivityOnResume]-------
public void callActivityOnResume(Activity activity) {
    activity.mResumed = true;
    activity.onResume();
    
    if (mActivityMonitors != null) {
        synchronized (mSync) {
            final int N = mActivityMonitors.size();
            for (int i=0; i<N; i++) {
                final ActivityMonitor am = mActivityMonitors.get(i);
                am.match(activity, activity, activity.getIntent());
            }
        }
    }
}

---->[ActivityThread#handleResumeActivity]-------
//回調onResume後進行window界面顯示
 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;
         wm.addView(decor, l);
     }

複製代碼

7.Activity的onStop方法的回調

onstop.png

---->[ActivityThread#handleMessage]-------
case STOP_ACTIVITY_SHOW: {
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
    SomeArgs args = (SomeArgs) msg.obj;
    handleStopActivity((IBinder) args.arg1, true, args.argi2, args.argi3);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;


---->[ActivityThread#handleStopActivity]-------
private void handleStopActivity(IBinder token, boolean show, int configChanges, int seq) {
    ActivityClientRecord r = mActivities.get(token);
    StopInfo info = new StopInfo();
    performStopActivityInner(r, info, show, true, "handleStopActivity");
//略...
    updateVisibility(r, show);
//略...
}

---->[ActivityThread#performStopActivityInner]-------
private void performStopActivityInner(ActivityClientRecord r,
        StopInfo info, boolean keepShown, boolean saveState, String reason) {
//略...
    // One must first be paused before stopped...
    performPauseActivityIfNeeded(r, reason);//暫停邏輯
//略...
    if (!keepShown) {
    try {
        // Now we are idle.
        r.activity.performStop(false /*preserveWindow*/);//中止
    
---->[ActivityThread#performPauseActivityIfNeeded]-------
private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {
//略...
        mInstrumentation.callActivityOnPause(r.activity);

---->[Instrumentation#callActivityOnPause]-------
public void callActivityOnPause(Activity activity) {
    activity.performPause();
}

---->[Activity#callActivityOnPause]-------
final void performPause() {
    mDoReportFullyDrawn = false;
    mFragments.dispatchPause();
    mCalled = false;
    onPause();
    //略...
}
複製代碼

8.Activity的onDestroy方法的回調

ondestory.png

---->[ActivityThread#handleMessage]-------
case DESTROY_ACTIVITY:
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy");
    handleDestroyActivity((IBinder)msg.obj, msg.arg1 != 0,
            msg.arg2, false);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

---->[ActivityThread#performDestroyActivity]-------
private void handleDestroyActivity(IBinder token, boolean finishing,
        int configChanges, boolean getNonConfigInstance) {
    ActivityClientRecord r = performDestroyActivity(token, finishing,
            configChanges, getNonConfigInstance);


---->[ActivityThread#performDestroyActivity]-------
private ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
            int configChanges, boolean getNonConfigInstance) {
        ActivityClientRecord r = mActivities.get(token);
             //略...
            performPauseActivityIfNeeded(r, "destroy");//暫停
            if (!r.stopped) {//若是沒stop,先stop
                try {
                    r.activity.performStop(r.mPreserveWindow);
            //略...
            try {
                r.activity.mCalled = false;
                mInstrumentation.callActivityOnDestroy(r.activity);
複製代碼
相關文章
相關標籤/搜索