preface
We all know that transferring data between activities is tedious, and many of us have used EventBus to simplify, but EventBus can’t track problems and can increase debugging time. Can we find a compromise that is simple to implement and easy to track down problems? Next, please allow me to introduce the latest way to implement the Result of data.
How did we do it in the past
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (resultCode == Activity.RESULT_OK) { when (requestCode) { REQUEST_PERMISSION -> { // Do something if success / failed } REQUEST_MULTIPLE_PERMISSION -> { // Do something if success / failed } REQUEST_TO_POST -> { // Parse result and do something } } } super.onActivityResult(requestCode, resultCode, data) } companion object { const val REQUEST_PERMISSION = 1001 const val REQUEST_MULTIPLE_PERMISSION = 1002 const val REQUEST_TO_POST = 1003 }Copy the code
In the past, we’ve done this with Result, defining a separate RequestCode and matching the data against that value. Let’s look at the new approach again and make a comparison
Activity Result New way
step one
Join the rely on
Implementation 'androidx. Activity: activity - KTX: 1.2.0 - alpha08' implementation 'androidx. Fragments: fragments - KTX: 1.3.0 - alpha08'Copy the code
step two
coding
class PostActivityContract(val postId: Int) : ActivityResultContract<Int, String? >() { override fun createIntent(context: Context, input: Int): Intent { return Intent(context, ResultActivity::class.java).apply { putExtra(MainActivity.ID, postId) } } override fun parseResult(resultCode: Int, intent: Intent?) : String? { val data = intent? .getStringExtra(ResultActivity.TITLE) return if (resultCode == Activity.RESULT_OK && data ! = null) data else null } }Copy the code
We inherited ActivityResultContract, and overwrote the createIntent and parseResult functions. One is responsible for creating the Intent, and the other is responsible for parsing the Result.
class MainActivity : AppCompatActivity() { private val openPostActivityCustom = registerForActivityResult(PostActivityContract(2)) { result -> Log.d("MainActivity", "Result : $result") } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) openPostActivityCustom.launch(1) } companion object { val ID = "id" } }Copy the code
Just call registerForActivityResult function, and then click on the event, with its launch function calls a return value
class ResultActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_result)
Log.d("ResultActivity", intent.getIntExtra(MainActivity.ID,0).toString())
}
companion object{
val TITLE = "title"
}
fun result(view: View) {
setResult(Activity.RESULT_OK, Intent().apply {
putExtra(TITLE,"title")
})
finish()
}
}
Copy the code
Code performance
What are the advantages of this implementation?
- On the one hand, for the launch parameters of a ResultActivity, to be more specific, it is unnecessary to care about the key of the postId when the Activity is started, so that when other pages need to call, only the parameters are passed, so that the reconstruction of the key in the future will not affect other parts
- On the other hand, it’s nice to no longer have to define a RequestCode
- There is also an advantage that lifecycle will automatically remove the generated RequestCode when the page is destroyed
Fragment Result New method
A picture to see the entire communication process
Fragment B sends data to Fragment A using the FragmentManager
In Fragment B that generates the result, the result must be set on the same FragmentManager using the same requestKey. You can do this using the setFragmentResult() API:
button.setOnClickListener {
val result = "result"
// Use the Kotlin extension in the fragment-ktx artifact
setResult("requestKey", bundleOf("bundleKey" to result))
}
Copy the code
Register callback result monitoring in Fragment A
FragmentManager.setFragmentResultListener( requestKey, lifecycleOwner, FragmentResultListener { requestKey: String, result: Bundle -> // result: Bundle})Copy the code
The important thing to notice in this case is that the requestKey needs to be consistent on both the outgoing and the outgoing. In other cases, only the latest value will be received. As in the case of an Activity, the listener will be automatically cancelled when the listener is DESTROYED.
As shown in the figure, you need to call childFragmentManager on the Parent Fragment to register the Listener
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // We set the listener on the child fragmentManager childFragmentManager.setResultListener("requestKey") { key, bundle -> val result = bundle.getString("bundleKey") // Do something with the result.. }}Copy the code
What are the advantages of this implementation?
- Complete decoupling, no dependence on each other
- Automatic logout when ON_DESTROY
conclusion
After this installment, the main understanding, the latest Activity and Fragment between the new way to transfer data, and is kotlin version of the extension, Java can also use, but kotlin is more concise and easy to use, also hope to help you, remember to click like oh.