1. Introduction
When I used the startActivityForResult() API these days, I suddenly noticed that it was deprecated.
Through the annotations of the source code, I found that the official has given a new solution.
2. Shortcomings of the original plan
When we use onActivityResult, there are often many different return cases. In this case, we need to set different return codes, and then judge in onActivityResult. Too many return codes will reduce the readability of the code, but also improve the coupling degree.
3.ActivityResult API is simple to use
First import the required dependencies.
Implementation 'androidx. Activity: the activity: 1.3.0' implementation 'androidx. Fragments: fragments: 1.3.4'Copy the code
Next, you need to create a class to integrate ActivityResultContract<I,O>, where I is the data type carried by the intent jump and O is the data type carried by the intent return. You also need to implement the createIntent and parseResult methods, one to create the intent and one to parse the data returned by the intent.
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 } }Copy the code
Once it’s created, we can use it in our Activity.
private val myActivityResultContract = registerForActivityResult(MyActivityResultContract()){ result ->
Toast.makeText(applicationContext, result, Toast.LENGTH_SHORT).show()
textView.text = result
}
Copy the code
Then just call ActivityResultContract where to jump. The launch method. After writing this whole step, you can see that the coupling is reduced, but the whole thing becomes more and more cumbersome, and you have to create a new class, which feels like the onActivityResult API. Fortunately, the official ActivityResulyContract has been provided with some defined ActivityResulyContract, which can meet most of our needs.
A. Contract B. Contract C. Contract D. Contract
Contract | role |
---|---|
StartActivityForResult | Contract, I–>Intent, O –> ActivityResult |
RequestMultiplePermissions | Multi-permission request, I- >Array, O- >Map<String,Boolean>, enter the permission name to request, output the permission name and whether the Map |
TakePicturePreview | Call mediastore.action_image_capture to take a picture and return a Bitmap |
TakePicture | Call mediastore.action_image_capture to take a photo, save it to the given Uri address, and return a Boolean |
TakeVideo | Call mediastore. ACTION_VIDEO_CAPTURE to capture the video, save it to the specified Uri, and return a thumbnail |
PickContact | Select a contact from the Contacts APP and return a URI |
GetContent | Passing in a specific MIME type opens the corresponding file manager |
CreateDocument | Prompts the user to create a file with I as the file name |
CreateMultipleDocuments | The user is prompted to select multiple documents. I indicates the file type |
OpenDocumentTree | Prompts the user to select a directory and returns the Uri of the user’s choice |
Demo
package com.zjl.activityresultdemo import android.Manifest import android.content.ContentValues import android.os.Bundle import android.provider.MediaStore import android.util.Log import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { private val myActivityResultContract = registerForActivityResult(MyActivityResultContract()) { result -> Toast.makeText(applicationContext, result, Toast.LENGTH_SHORT).show() } private val mPermissionResultContract = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { Toast.makeText(applicationContext, "${it.keys}... ${it.values}", Toast.LENGTH_SHORT) .show() } private val mTakePictureContract = registerForActivityResult(ActivityResultContracts.TakePicture()) { Toast.makeText(applicationContext, "$it", Toast.LENGTH_SHORT).show() } private val mTakePicturePreviewContract = registerForActivityResult(ActivityResultContracts.TakePicturePreview()) { iv.setImageBitmap(it) } private val mTakeVideoContract = registerForActivityResult(ActivityResultContracts.TakeVideo()) { iv.setImageBitmap(it) } private val mPicContact = registerForActivityResult(ActivityResultContracts.PickContact()) { Log.e("Testtt",it.toString()) } private val mGetContact = registerForActivityResult(ActivityResultContracts.GetContent()) { Log.e("Testtt",it.toString()) } private val mCreateDoc = registerForActivityResult(ActivityResultContracts.CreateDocument()) { } private val mOpenMultipleDoc = registerForActivityResult(ActivityResultContracts.OpenMultipleDocuments()) { } private val mOpenDocTree = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) btn_permission.setOnClickListener { //myActivityResultContract.launch("test") mPermissionResultContract.launch( arrayOf( Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE ) ) } btn_take_pic.setOnClickListener { contentResolver.insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, ContentValues() ).let { mTakePictureContract.launch(it) } } btn_take_pic_preview.setOnClickListener { mTakePicturePreviewContract.launch(null) } btn_take_video.setOnClickListener { contentResolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, ContentValues()) .let { mTakeVideoContract.launch(it) } } btn_pic_contact.setOnClickListener { mPicContact.launch(null) } btn_get_contact.setOnClickListener { mGetContact.launch("video/*") //mime type } btn_create_doc.setOnClickListener { mCreateDoc.launch("image/*") } btn_open_multi_Doc.setOnClickListener { mOpenMultipleDoc.launch(arrayOf("image/*","video/*")) } btn_open_doc_tree.setOnClickListener { mOpenDocTree.launch(MediaStore.Images.Media.EXTERNAL_CONTENT_URI) } } }Copy the code
5. Receive results in non-activity /Fragment
We can receive results between an Activity and a Fragment because their base classes implement an ActivityResultCaller. Sometimes we need to receive results in a component that is not an Activity or Fragment. This can be done using ActivityResultRegistry.
The Demo:
class SecondActivity : AppCompatActivity() {
private lateinit var observer: MyLifeCycleObserver
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
observer = MyLifeCycleObserver(activityResultRegistry)
lifecycle.addObserver(observer)
btn2.setOnClickListener { observer.selectImage() }
}
}
class MyLifeCycleObserver(private val registry: ActivityResultRegistry) : LifecycleObserver{
private lateinit var getContent: ActivityResultLauncher<String>
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun onCreate(owner: LifecycleOwner) {
getContent = registry.register("key",owner,ActivityResultContracts.GetContent()) {
Log.e("TTTEE",it.toString())
}
}
fun selectImage() {
getContent.launch("image/*")
}
}
Copy the code
References:
1. Goodbye! OnActivityResult! Hello, Activity Results API!