還在用startActivityForResult處理數據傳遞?試試ActivityResultContract吧

關注個人公衆號 「安安安安卓」 學習更多知識java

ActivityResultContract是什麼

很簡單的一句話,ActivityResultContract是用來在大部分場景中對startActivityForResultonActivityResult進行替代的官方apiapi

ActivityResultContract提供了一種類型安全的獲取返回值的方式,好比拍照的api會返回泛型指定的bitmap。這避免了咱們手動處理onActivityResult回調致使的各類問題。瀏覽器

固然了我認爲ActivityResultContract最好的地方就是省心,尤爲對於系統預置的集中ActivityResultContract,只須要兩步模板代碼便可實現功能。安全

自定義一個ActivityResultContract

要實現自定義行爲須要先自定義一個ActivityResultContract類,定義以下:markdown

  1. 集成ActivityResultContract類

ActivityResultContract類中有兩個泛型,第一個泛型是I,第二個泛型是O,I表示輸入也就是咱們啓動activity須要putExtra的內容,O表述輸入即onActivityResult返回的數據app

ActivityResultContract有兩個方法ide

  • createIntent表示建立啓動activityIntent,其中方法的第二個參數可用於傳給待啓動activity的參數
  • parseResult表示對返回數據的解析,方法的返回值就是registerForActivityResult中回調的數據
class CustomResultContracts : ActivityResultContract<Int, String>() {
    override fun createIntent(context: Context, input: Int?): Intent {
        return Intent(context, DestinishActivity::class.java).putExtra("input",input)
    }

    override fun parseResult(resultCode: Int, intent: Intent?): String {
        return intent?.getStringExtra("data") ?: "未返回數據"
    }
}
複製代碼
  1. 註冊監聽
private val customContract = registerForActivityResult(CustomResultContracts()){
        getData(14).content="自定義Contracts返回數據:$it"
        getData(14).notifyDataSetChange()
    }
複製代碼
  1. 啓動activity
customContract.launch(1)
複製代碼

官方提供的預置ActivityResultContract

StartActivityForResult啓動activity返回結果

本例調用方法後會啓動一個activity,新的activity點擊返回數據將數據返回到列表中展現學習

  1. 代碼

註冊代碼this

//註冊結果監聽
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
            if (it.resultCode == 3) {
                showResult(it.data?.getStringExtra("data"))
            }
        }
複製代碼

啓動代碼spa

//啓動activity,參數傳intent
startForResult.launch(Intent(this@MainActivity, DestinishActivity::class.java))
複製代碼
  1. 效果

TakePicturePreview跳轉拍照頁面

跳轉到拍照頁面,拍攝的照片會被保存到圖庫中

  1. 代碼
registerForActivityResult(ActivityResultContracts.TakePicturePreview()) {
            getData(1).let {
                it.notifyDataSetChange()
            }
        }
複製代碼

模擬器錄製不變,暫無效果圖

TakePicture拍攝預覽圖片

TakePicture方法會跳轉到系統相機拍攝一張照片,返回bitmap,可是不會把圖片保存到圖庫

  1. 代碼
private val takePreviewPic = registerForActivityResult(ActivityResultContracts.TakePicture()) {
        logEE("搞預覽圖片成功")
    }
複製代碼

CaptureVideo拍攝視頻

拍攝代碼,須要說明的是拍攝視頻完成後會須要等待較長時間,等待手機處理完視頻的存儲

private val captureVideo = registerForActivityResult(ActivityResultContracts.CaptureVideo()) {
        logEE("拍攝視頻成功:$it")
    }
複製代碼

模擬器錄製不變,暫無效果圖

RequestPermission請求權限

很是簡潔的方式實現權限申請

  1. 申請權限代碼
cameraPermission.launch(Manifest.permission.CAMERA)
複製代碼
  1. 註冊申請權限監聽
private val cameraPermission =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) {
            getData(3).apply {
                content = "請求相機權限結果$it"
                notifyDataSetChange()
            }
        }
複製代碼
  1. 效果

RequestMultiplePermissions請求多個權限

  1. 調用申請多個權限代碼
mutlePermission.launch(
                    arrayOf(
                        Manifest.permission.CAMERA,
                        Manifest.permission.READ_EXTERNAL_STORAGE,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE
                    )
                )
複製代碼
  1. 註冊申請多個權限的代碼
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
            var result = ""
            it.forEach { gaint ->
                result += "獲取${gaint.key} 權限 ${if (gaint.value) "成功" else "失敗"}"
            }
            getData(4).content = result
            getData(4).notifyDataSetChange()
        }
複製代碼
  1. 效果

PickContact獲取聯繫人

  1. 請求打開聯繫人選擇頁面
pickContact.launch(null)//參數傳空
複製代碼
  1. 監聽獲取聯繫人結果
private val pickContact = registerForActivityResult(ActivityResultContracts.PickContact()) {
        logEE(it.toString())
        getData(8).apply {
            content = it.toString()
            notifyDataSetChange()
        }
    }
複製代碼
  1. 實現效果

GetContent打開文件瀏覽器

實現使用文件瀏覽器選擇圖片功能

  1. 打開文件瀏覽器
getContent.launch("image/*")
複製代碼
  1. 處理返回結果
private val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) {
        logEE(it.toString())
    }
複製代碼
  1. 實現效果

由於模擬器沒有圖片可選,因此沒有內容展現

2021/08/06 更新新內容以下

Fragment中使用ActivityForResultContract

Fragment中的使用和activity中是同樣的,直接放參考代碼吧

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        view.findViewById<Button>(R.id.btn).setOnClickListener {
            request.launch(Intent(activity, DestinishActivity::class.java))//啓動新activity
        }
    }

    /** * 註冊結果監聽 */
    val request = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
        logEE(it.data?.getStringExtra("data")!!)
    }
複製代碼

最終效果和activity是一致的

相關文章
相關標籤/搜索