天天看點

activity 點選後傳遞資料給fragment_教你用更好的方式在Activity或Fragment之間傳遞以及傳回資料...

原文連結:https://juejin.im/post/6869045188963074061

前言

我們都知道在Activity之間傳遞資料很繁瑣,為了簡化,很多人都是使用過EventBus,可EventBus在追蹤問題時反而束手無策,反而增加調試時間,那我們能不能找一個折中的方案,又能簡單的實作,又能容易追查問題呢?下面請允許我介紹一下最新的方式在實作資料的Result。

先來看看以前我們都是如何做的

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
    }
複制代碼
           

以前,我們都是這樣處理Result,分别定義不同的RequestCode,然後根據這個值來比對資料。我們再來看看新的方式,然後做個比較

Activity Result新方式

step one

加入依賴

implementation 'androidx.activity:activity-ktx:1.2.0-alpha08'
implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha08'
複制代碼
           

step two

編碼

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
    }
}
複制代碼
           

繼承ActivityResultContract,并覆寫createIntent和parseResult函數,這倆函數很好了解,一個負責建立Intent,一個負責解析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"
    }

}
複制代碼
           

隻需要調用registerForActivityResult函數,然後在點選事件中,用其傳回值調用launch函數即可

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()
    }

}
複制代碼
           

代碼運作效果

activity 點選後傳遞資料給fragment_教你用更好的方式在Activity或Fragment之間傳遞以及傳回資料...

這麼實作有什麼優點呢?

  • 一方面針對ResultActivity的啟動傳參數,更加的具體,啟動該Activity,不必要關心postId的key是什麼,這樣在其他頁面需要調用的時候,也隻是傳入參數,這樣對于以後key的重構就不會影響其他部分
  • 另一方面不再需要定義RequestCode,也不錯哦
  • 其實它還有個優勢哦,看過源碼才知道,其實它是結合了lifecycle,在頁面銷毀的時候,會自動将生成的RequestCode給remove掉

Fragment Result新方式

一張圖看清整個通訊的過程

activity 點選後傳遞資料給fragment_教你用更好的方式在Activity或Fragment之間傳遞以及傳回資料...

Fragment B 使用 FragmentManager 将資料發送到 Fragment A

在生成結果的 Fragment B 中,必須使用相同的 requestKey 在同一 FragmentManager 上設定結果。您可以使用 setFragmentResult() API 來完成此操作:

button.setOnClickListener {
    val result = "result"
    // Use the Kotlin extension in the fragment-ktx artifact
    setResult("requestKey", bundleOf("bundleKey" to result))
}
複制代碼
           

在Fragment A中注冊回調結果監聽

FragmentManager.setFragmentResultListener(
    requestKey,
    lifecycleOwner,
    FragmentResultListener { requestKey: String, result: Bundle ->
        // 處理結果
    })
複制代碼
           

這種情況需要注意的就是requestKey,在出去和傳回的時候都要保持一緻。還有一種情況是,如果有多個資料傳遞,隻會接收到最新的值,更Activity一樣,在DESTROYED時,會自動取消listener,以上是同級Fragment的傳遞,如果是父子級呢?

activity 點選後傳遞資料給fragment_教你用更好的方式在Activity或Fragment之間傳遞以及傳回資料...

如圖所示,需要在Parent Fragment 調用 childFragmentManager來注冊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..
    }
}
複制代碼
           

這麼實作有什麼優點呢?

  • 完全解耦,無需依賴對方
  • 當ON_DESTROY時自動登出

總結

經過這期,主要了解到,最新的Activity和Fragment之間如何用新的方式傳遞資料,且都是kotlin版本的擴充,java也能用,但kotlin更加的簡潔好用,也希望能幫助到你,記得點個贊哦。

繼續閱讀