2020.8.1
一.Application的啟動流程
- 手機(jī)開機(jī)->應(yīng)用程序的縮略圖標(biāo)被點(diǎn)擊
- ①點(diǎn)擊圖標(biāo)->
②啟動ActivityThread->線程的入口點(diǎn):main函數(shù)->創(chuàng)建ActivityThread
③將ActivityThread的對象進(jìn)行綁定 thread.attach(false, startSeq)
④創(chuàng)建儀表對象,管理程序的生命周期 mInstrumentation = new Instrumentation()->
⑤創(chuàng)建上下文: ContextImpl context = ContextImpl.createAppContext(this,getSystemContext().mPackageInfo);
⑥創(chuàng)建應(yīng)用程序:
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
app=mActivityThread.mInitialApplication.newApplication(cl,appClass,appContext)
⑦回調(diào)application的onCreate方法:instrumentation.callApplicationOnCreate(app)
二.啟動Activity的流程:ActivityThread
①handleLaunchActivity->performLaunchActivity
②創(chuàng)建Activity上下文 createBaseContextForActivity
③創(chuàng)建啟動的頁面
activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent);
④將界面和窗口Window綁定 activity.attach(appContext,getInstrumentation(),window)
⑤調(diào)用onCreate方法布局Activity界面
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);->
activity.performCreate(icicle, persistentState);->
onCreate(icicle);
-
所以在Activity的子類中,通過實(shí)現(xiàn)onCreate方法,來對界面進(jìn)行初始化(UI布局,邏輯初始化)
APP啟動流程圖.png
三.上下文——Context
上下文:運(yùn)行環(huán)境,可以理解為就是一個(gè)橋梁,Context提供了調(diào)用系統(tǒng)資源的方法,設(shè)備<--->Context<--->界面
- Activity的context和applicationContext的區(qū)別
①大多數(shù)情況下,可以相互使用
②如果在涉及界面的跳轉(zhuǎn),盡量使用Activity的context,因?yàn)樗峁┝四J(rèn)的任務(wù)棧,applicationContext沒有提供任務(wù)棧 - 一個(gè)Activity的繼承于Context,所以通常情況下使用其本身作為Context
四.Activity之間的跳轉(zhuǎn)
- Activity就是一個(gè)獨(dú)立的頁面
- 實(shí)現(xiàn)頁面之間的跳轉(zhuǎn)->Intent意圖
- 顯示跳轉(zhuǎn):同一個(gè)應(yīng)用程序,不同界面之間的跳轉(zhuǎn),明確指定從哪個(gè)頁面切換到哪個(gè)頁面
??????????????不傳遞數(shù)據(jù)的跳轉(zhuǎn)
- val intent=Intent(this,目的界面的java字節(jié)碼文件)
- startActivity(intent) 啟動意圖,進(jìn)行界面跳轉(zhuǎn)
//明確指定從當(dāng)前頁面跳轉(zhuǎn)到app頁面
val intent=Intent(this,app::class.java)
//啟動
startActivity(intent)
- finish():結(jié)束當(dāng)前界面,即把當(dāng)前界面刪除,然后從任務(wù)棧中調(diào)出上一個(gè)界面并顯示,其實(shí)在manifests配置文件中給Activity添加父界面,就是等價(jià)于添加了finish()方法
?????????????傳遞數(shù)據(jù)的跳轉(zhuǎn) - intent.putExtra(Key,Value):通過給intent添加鍵值對的方式來傳遞數(shù)據(jù)
- intent.getStringExtra(Key):在目的界面中可以通過intent的鍵獲取對應(yīng)的值
- 注:putExtra()->只能傳遞系統(tǒng)默認(rèn)的基本類型
intent.putExtra("name","jack")//起始界面?zhèn)鬟f數(shù)據(jù)
val name:String?=intent.getStringExtra("name")//目的界面中獲取值
- val bundle=Bundle()->管理一對鍵值對
bundle.putString(Key,Value) - intent.putExtras(bundle)同樣可以實(shí)現(xiàn)傳遞數(shù)據(jù)
val bundle=Bundle().apply {
putString("name","jack")
putInt("age",20)
}
intent.putExtras(bundle)
- val bundle2=intent.extras:在目的界面中獲取Bundle的一個(gè)對象
bundle2.getString(Key)獲取對應(yīng)的值
val bundle2:Bundle?=intent.extras
val name=bundle2?.getString("name")
val age=bundle2?.getInt("age")
?????????????需要返回值的跳轉(zhuǎn)
- startActivityForResult(intent,自定義的請求碼)
- 同時(shí)必須重寫onActivityResult(requestCode: Int, resultCode: Int, data: Intent?)方法
-----------------------------------起始界面--------------------------------------------
startActivityForResult(intent,1)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
//1.判斷是不是我請求的數(shù)據(jù)
if (requestCode==1){
//2.判斷處理結(jié)果 resultCode
if(resultCode==0){
Log.v("cx","處理成功:${data?.getStringExtra("uid")}")
}else{
Log.v("cx","處理失敗")
}
}
}
- 目的界面中setResult(自定義結(jié)果碼)->不帶數(shù)據(jù)的返回
setResult(自定義結(jié)果碼,Intent的一個(gè)對象)->帶數(shù)據(jù)的返回
返回的數(shù)據(jù)保存在函數(shù)參數(shù)data中
-----------------------------------目的界面--------------------------------------------
//1.回調(diào)結(jié)果 不帶數(shù)據(jù)
setResult(0)
//2.帶數(shù)據(jù)
Intent().apply {
putExtra("uid","001")
setResult(0,this)
}
- 原界面可以通過data獲取返回的數(shù)據(jù)
-
隱式跳轉(zhuǎn):不同程序之間,運(yùn)行界面的跳轉(zhuǎn)(微信支付、支付寶支付)
????????打開系統(tǒng)提供的服務(wù)(相機(jī)、撥號、發(fā)消息)
使用方式:由于系統(tǒng)提供的類無法在程序中通過Intent(當(dāng)前頁面,目的頁面的字節(jié)碼文件)來訪問,只能通過配置文件的意圖過濾器來查找我們需要的Activity,即添加一個(gè)action,每個(gè)界面有很多個(gè)意圖過濾器,使用任意一個(gè)意圖都可以啟動該服務(wù),并跳轉(zhuǎn)到服務(wù)界面
注:你想要啟動系統(tǒng)某個(gè)服務(wù)界面,如撥號,那么得知道撥號對應(yīng)的action,你可以通過閱讀源代碼來查找撥打電話對應(yīng)的action,也可以通過Intent的靜態(tài)屬性來獲取
//撥打電話
Intent().apply {
//通過配置文件的意圖過濾器來查找我們需要的Activity
action=Intent.ACTION_DIAL //靜態(tài)屬性獲取action
//data傳遞數(shù)據(jù)
data=Uri.parse("tel:10086") //傳遞所需的電話號碼,必須按照源碼格式
//滿足以上兩種條件,便可進(jìn)行隱式跳轉(zhuǎn)
}.also {
startActivity(it)
}

源碼解析.png
??????????????跳轉(zhuǎn)到其他應(yīng)用程序
前提:根據(jù)啟動系統(tǒng)提供的服務(wù)可知,隱式跳轉(zhuǎn)到其他系統(tǒng)服務(wù)/程序,需要目的Activity提供意圖過濾器和傳遞數(shù)據(jù)的格式
<intent-filter>在應(yīng)用程序的AndroidManifest.xml中配置
--------------------------------------app1----------------------------------------------
<!-- 添加意圖過濾器 -->
<intent-filter>
<!-- 系統(tǒng)定義 -->
<action android:name="android.intent.action.SEND"/>
<!-- 自定義 -->
<action android:name="cx.action.wiwi"/>
<!-- 如果希望外部程序能夠啟動這個(gè)頁面 必須設(shè)置Category為Default -->
<category android:name="android.intent.category.DEFAULT"/>
<!-- 如果希望外部啟動這個(gè)界面的時(shí)候傳遞數(shù)據(jù)過來 必須定義數(shù)據(jù)的格式 -->
<data android:scheme="cx"/>
</intent-filter>
在其他應(yīng)用中進(jìn)行跳轉(zhuǎn)
--------------------------------------app2----------------------------------------------
Intent().apply {
action="cx.action.wiwi"
data= Uri.parse("cx:MyAPP")
}.also {
startActivity(it)
}
跳轉(zhuǎn)到app1中,可通過data獲取傳遞的數(shù)據(jù)
--------------------------------------app1----------------------------------------------
val content=intent.data?.schemeSpecificPart
Log.v("cx",content)
