過時(shí)的OnActivityResult(一)

在Android應(yīng)用程序開發(fā)中趁耗,啟動(dòng)一個(gè)Activity不一定是單項(xiàng)操作疆虚,從啟動(dòng)的Activity獲取數(shù)據(jù)是常見的場(chǎng)景苛败,最傳統(tǒng)的方式是通過Intent攜帶數(shù)據(jù),然后使用startActivityForResult方法來啟動(dòng)下一個(gè)Activity径簿,然后通過onActivityResult來接收返回的數(shù)據(jù)罢屈,代碼如下:

  1. 調(diào)用startActivityForResult方法啟動(dòng)
startActivityForResult(intent,1)
  1. 實(shí)現(xiàn)onActivityResult方法
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if(requestCode == 1 && resultCode == Activity.RESULT_OK){
            // 處理第二個(gè)頁面帶回的數(shù)據(jù)
        }
}

隨著應(yīng)用的擴(kuò)展,onActivityResult回調(diào)方法各種嵌套篇亭、耦合嚴(yán)重缠捌、難以維護(hù)。
Google 可能也意識(shí)到onActivityResult的這些問題译蒂,在androidx.activity:activity:1.2.0-alpha02 和androidx.fragment:fragment:1.3.0-alpha02 中曼月,已經(jīng)廢棄了startActivityForResult和onActivityResult方法。Google推薦使用什么方式從Activity中更好的獲取數(shù)據(jù)呢柔昼?答案就是 Activity Results API

Activity Results API

Activity Results API 是 Google官方推薦的Activity哑芹、Fragment獲取數(shù)據(jù)的方式。Activity Results API 中兩個(gè)重要的組件:ActivityResultContract和ActivityResultLauncher捕透。

  • ActivityResultContract: 協(xié)議聪姿,它定義了如何傳遞數(shù)據(jù)和如何處理返回的數(shù)據(jù)。ActivityResultContract是一個(gè)抽象類乙嘀,你需要繼承它來創(chuàng)建自己的協(xié)議末购,每個(gè) ActivityResultContract 都需要定義輸入和輸出類,如果您不需要任何輸入虎谢,可使用 Void(在 Kotlin 中招盲,使用 Void? 或 Unit)作為輸入類型。
  • ActivityResultLauncher: 啟動(dòng)器嘉冒,調(diào)用ActivityResultLauncher的launch方法來啟動(dòng)頁面跳轉(zhuǎn)曹货,作用相當(dāng)于原來的startActivity()

使用

  1. 首先,在app下的build.gradle中加入依賴:
implementation 'androidx.activity:activity:1.2.0-beta01'
implementation 'androidx.fragment:fragment:1.3.0-beta01'
  1. 定義協(xié)議

新建一個(gè)Contract類讳推,繼承自ActivityResultContract<I,O>顶籽,其中,I是輸入的類型银觅,O是輸出的類型礼饱。需要實(shí)現(xiàn)2個(gè)方法,createIntent和parseResult,輸入類型I作為createIntent的參數(shù),輸出類型O作為parseResult方法的返回值镊绪,在下面的例子中匀伏,輸入輸出類型都是String:

class MyActivityResultContract: ActivityResultContract<String,String>(){
        override fun createIntent(context: Context, input: String?): Intent {
            return Intent(context,SecondActivity::class.java).apply {
                putExtra("name",input)
            }
        }

        override fun parseResult(resultCode: Int, intent: Intent?): String? {
            val data = intent?.getStringExtra("result")
            return if (resultCode == Activity.RESULT_OK && data != null) data
            else null
        }

    }

如上代碼,我們?cè)赾reateIntent方法中創(chuàng)建了Intent蝴韭,并且攜帶了參數(shù)name,在parseResult方法中够颠,獲取了返回的數(shù)據(jù)result。

  1. 注冊(cè)協(xié)議榄鉴,獲取啟動(dòng)器-ActivityResultLauncher
    注冊(cè)協(xié)議履磨,使用registerForActivityResult方法,該方法由ComponentActivity或者Fragment提供,接受2個(gè)參數(shù)庆尘,第一個(gè)參數(shù)就是我們定義的Contract協(xié)議,第二個(gè)參數(shù)是一個(gè)回調(diào)ActivityResultCallback<O>,其中O就是前面Contract的輸出類型驶忌。代碼如下:
private val myActivityLauncher = registerForActivityResult(MyActivityResultContract()){result ->
   Toast.makeText(applicationContext,result,Toast.LENGTH_SHORT).show()
   textView.text = "回傳數(shù)據(jù):$result"
}

如上代碼,注冊(cè)了MyActivityResultContract,registerForActivityResult方法的返回值是ActivityResultLauncher, 因此我們定義了一個(gè)myActivityLauncher,回調(diào)方法中如筛,result就是從上一個(gè)界面?zhèn)骰氐闹凳闾А_@里我們簡(jiǎn)單的用Toast顯示擦剑。

  1. 最后,調(diào)用啟動(dòng)器的launch方法開啟界面跳轉(zhuǎn)
    MainActivity中添加一個(gè)Button,點(diǎn)擊Button時(shí)惠勒,調(diào)用launch方法跳轉(zhuǎn):

button.setOnClickListener {
// 開啟頁面跳轉(zhuǎn)
myActivityLauncher.launch("豌豆公主")
}
以上幾步,就實(shí)現(xiàn)了使用新的Activity Results API 來完成Activity之間的數(shù)據(jù)傳遞纠屋,并獲取Activity返回的數(shù)據(jù)

但是盾计,我們發(fā)現(xiàn)雖然確實(shí)減少了代碼耦合,但是使用并不簡(jiǎn)單啊族铆。

確實(shí)哭尝,不過還有......

預(yù)定義的Contract

新的Activity Results API使用起來好像有點(diǎn)麻煩,每次都得定義Contract。Google肯定考慮到了這個(gè)問題的逝淹,于是,Google 預(yù)定義了很多Contract,把你們能想到的使用場(chǎng)景基本上都想到了栅葡,它們都定義在類ActivityResultContracts中,有以下這些Contract:

StartActivityForResult() 
RequestMultiplePermissions()
RequestPermission()
TakePicturePreview()
TakePicture()
TakeVideo()
PickContact()
CreateDocument()
OpenDocumentTree()
OpenMultipleDocuments()
OpenDocument()
GetMultipleContents()
GetContent()

StartActivityForResult: 通用的Contract,不做任何轉(zhuǎn)換妥畏,Intent作為輸入,ActivityResult作為輸出醉蚁,這也是最常用的一個(gè)協(xié)定。
RequestMultiplePermissions: 用于請(qǐng)求一組權(quán)限网棍。
RequestPermission: 用于請(qǐng)求單個(gè)權(quán)限。
TakePicturePreview: 調(diào)用MediaStore.ACTION_IMAGE_CAPTURE拍照滥玷,返回值為Bitmap圖片。
TakePicture: 調(diào)用MediaStore.ACTION_IMAGE_CAPTURE拍照蛋欣,并將圖片保存到給定的Uri地址如贷,返回true表示保存成功。
TakeVideo: 調(diào)用MediaStore.ACTION_VIDEO_CAPTURE 拍攝視頻杠袱,保存到給定的Uri地址,返回一張縮略圖楣富。
PickContact: 從通訊錄APP獲取聯(lián)系人。
GetContent: 提示用選擇一條內(nèi)容庄萎,返回一個(gè)通過塘安。ContentResolver#openInputStream(Uri)訪問原生數(shù)據(jù)的Uri地址(content://形式) 。默認(rèn)情況下耙旦,它增加了Intent#CATEGORY_OPENABLE, 返回可以表示流的內(nèi)容萝究。
CreateDocument: 提示用戶選擇一個(gè)文檔锉罐,返回一個(gè)(file:/http:/content:)開頭的Uri。
OpenMultipleDocuments: 提示用戶選擇文檔(可以選擇多個(gè))栽连,分別返回它們的Uri,以List的形式侨舆。
OpenDocumentTree: 提示用戶選擇一個(gè)目錄,并返回用戶選擇的作為一個(gè)Uri返回熔恢,應(yīng)用程序可以完全管理返回目錄中的文檔臭笆。
上面這些預(yù)定義的Contract中叙淌,除了StartActivityForResult和RequestMultiplePermissions之外鹰霍,基本都是處理的與其他APP交互茵乱,返回?cái)?shù)據(jù)的場(chǎng)景,比如督勺,拍照在验,選擇圖片堵未,選擇聯(lián)系人,打開文檔等等渗蟹。使用最多的就是StartActivityForResult和RequestMultiplePermissions了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末授艰,一起剝皮案震驚了整個(gè)濱河市淮腾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌谷朝,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件杈帐,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡挑童,警方通過查閱死者的電腦和手機(jī)跃须,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門回怜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來大年,“玉大人玉雾,你說我怎么就攤上這事「囱” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵壁涎,是天一觀的道長(zhǎng)志秃。 經(jīng)常有香客問我,道長(zhǎng)浮还,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任担汤,我火速辦了婚禮崭歧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘率碾。我一直安慰自己叔营,他們只是感情好审编,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布垒酬。 她就那樣靜靜地躺著件炉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪斟冕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天景描,我揣著相機(jī)與錄音秀撇,去河邊找鬼。 笑死呵燕,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的氧苍。 我是一名探鬼主播泛范,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼赡突!你這毒婦竟也來了柠傍?” 一聲冷哼從身側(cè)響起辩稽,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎患整,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體各谚,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年赴穗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了膀息。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡甸赃,死狀恐怖埠对,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情项玛,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布稍计,位于F島的核電站臣嚣,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏硅则。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一怎虫、第九天 我趴在偏房一處隱蔽的房頂上張望大审。 院中可真熱鬧,春花似錦徒扶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽圈澈。三九已至,卻和暖如春康栈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背啥么。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國打工饥臂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人隅熙。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓囚戚,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親驰坊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容