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.