Say goodbye to onActivityResult, embrace ActivityResultContract

Insert picture description here
Many developers have onActivityResultcomplained for a long time: the need to define resultCodeand requestCode, the use is cumbersome and error-prone. Now the newly released KTX ActivityResultContractcan solve the above troubles a lot

Basic use


Before

Traditional onActivityResultwriting

class MainActivity : AppCompatActivity() {
    
    

    companion object {
    
    
        private const val REQUEST_CODE = 1234
    }

    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        button_open.setOnClickListener {
    
    
            startActivityForResult(
                    SecondActivity.createIntent(this),
                    REQUEST_CODE
            )
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    
    
        super.onActivityResult(requestCode, resultCode, data)
        Log.d("MainActivity", "requestCode: $requestCode, resultCode: $resultCode, data: $data")
    }
}

SecondActivity needs to be required before finishsetResult

setResult(Activity.RESULT_OK, intent)
finish()

After

Introduce gradle

implementation "androidx.activity:activity-ktx:$latest_vsersion"
  or
implementation "androidx.fragment:fragment-ktx:$latest_vsersion"
class MainActivity : AppCompatActivity() {
    
    

    private val launcher: ActivityResultLauncher<Intent> =
            registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
    
     activityResult ->
                Log.d("MainActivity", activityResult.toString())
            }

    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        button_open.setOnClickListener {
    
    
            launcher.launch(SecondActivity.createIntent(this))
        }
    }
}

Eliminate the annoying resultCodesum requestCode, the code is more elegant
Insert picture description here

Other scenes


See how to use ActivityResultContract in several common scenarios:

Select a document

Open the file manager, select the picture and return uri, first look at the implementation based on onActivityResult:

class MainActivity : AppCompatActivity() {
    
    
    companion object {
    
    
        private const val REQUEST_CODE_CHOOSER = 1234
    }

    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        button_get_content.setOnClickListener {
    
    
            startActivityForResult(
                    Intent(Intent.ACTION_GET_CONTENT).apply {
    
    
                        addCategory(Intent.CATEGORY_OPENABLE)
                        type = "image/*"
                    },
                    REQUEST_CODE_CHOOSER
            )
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    
    
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == REQUEST_CODE_CHOOSER && resultCode == Activity.RESULT_OK) {
    
    
            Log.d("MainActivity", "uri: ${
      
      data?.data}")
        }
    }
}

After implementation based on ActivityResultContracts:

class MainActivity : AppCompatActivity() {
    
    

    private val launcher = registerForActivityResult(ActivityResultContracts.GetContent()) {
    
     uri ->
        Log.d("MainActivity", "uri: $uri")
    }

    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        button_get_content.setOnClickListener {
    
    
            launcher.launch("image/*")
        }
    }
}

ActivityResultContracts.GetContentIt is one of several contracts preset by the system:
Insert picture description here
Of course, in addition to the above presets Contracts, you can also ActivityResultContractscustomize your own Contracts by inheriting

Permission request

The process of requestPermission and startActivityForResult is similar:

//权限请求
ActivityCompat.requestPermissions(this, arrayOf(WRITE_EXTERNAL_STORAGE), REQUEST_CODE)
//返回结果
override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray
) {
    
    
    if (requestCode == REQUEST_CODE) {
    
    
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    
    
            Toast.makeText(this, "result: granted", Toast.LENGTH_LONG).show()
        }
        return
    }
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}

Implementation based on ActivityResultContract:

// 设置回调
private val launcher = registerForActivityResult(RequestPermission()) {
    
    
    if (it) {
    
    
        Toast.makeText(this, "result: granted", Toast.LENGTH_LONG).show()
    }
}
// 请求权限
launcher.launch(WRITE_EXTERNAL_STORAGE)

Implementation principle


The principle of ActivityResultContract is relatively simple, interested students can refer to the in-depth understanding of ActivityResultContracts

Guess you like

Origin blog.csdn.net/vitaviva/article/details/107551620