背景
Activity Result API使用。比之前的接受页面返回的api更友好。
新的api需要的配置
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-parcelize'
}
插件是必须的。
implementation 'androidx.activity:activity:1.8.0'
依赖库尽量高一点就行。
简单使用
tv.setOnClickListener {
resultLauncher.launch(Intent(this, ResultApiActivity::class.java))
}
打开一个新的activity。接受返回值。
// 注册回调函数, 简单模式
private var resultLauncher: ActivityResultLauncher<Intent> = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
// 处理返回的结果
val code = result.resultCode
val data = result.data
Log.i(TAG, "code: $code, result? : ${data?.getStringExtra(ResultApiActivity.KEY_TRANSFER)}")
}
之前是重写一个函数,现在换了一个callback对象。
setResult(RESULT_OK, intent.putExtra(KEY_TRANSFER, "act return str $code"))
第二个页面返回数据。
看起来确实方便很多,和之前的比起来更独立。也就是A页面启动其他多个页面的逻辑可以隔离出来,谁启动谁接受什么内容也一一对应上。
传递其他数据类型
class CustomContract : ActivityResultContract<Int, String>() {
companion object {
const val DEFAULT_VALUE = "default_value"
const val TAG = "CustomContract"
}
/**
* 创建Intent
* @param context Context
* @param input 当前类的第一个泛型参数
* @return 启动的intent
*/
override fun createIntent(context: Context, input: Int): Intent {
Log.i(TAG, "createIntent: $input")
val i = Intent(context, ResultApiActivity::class.java)
i.putExtra(ResultApiActivity.KEY_PWD, input)
return i
}
/**
* 解析结果,类似于Activity#onActivityResult
* @param resultCode 返回码 [Activity.setResult] 的 resultCode
* @param intent [Activity.setResult] 的 intent
* @return
*/
override fun parseResult(resultCode: Int, intent: Intent?): String {
Log.i(TAG, "parseResult: $resultCode")
if (resultCode != Activity.RESULT_OK || intent == null) return DEFAULT_VALUE
return intent.getStringExtra(ResultApiActivity.KEY_TRANSFER) ?: DEFAULT_VALUE
}
}
传递int类型到第二个页面,接受string返回值。
// Activity中使用自定义Contract,包括创建intent,限制传递数据和返回的数据类型
private val mLauncher = registerForActivityResult(CustomContract()) { result ->
Log.i(
TAG, "return result:$result"
)
Toast.makeText(this, result, Toast.LENGTH_SHORT).show()
}
接受的结果就是string,直接使用,因为CustomContract中解析了返回值。把启动传递参数和解析都抱在一起。
mLauncher.launch(300)
启动并传递参数
传递多个参数-对象
一般页面数据传递都是多个参数的,也就是把一个对象传递过去。
id 'kotlin-parcelize'
需要依赖这个插件。
@Parcelize
data class User(val name: String = "", val age: Int = 0) : Parcelable
这是需要传递的数据结构。当然可以更复杂。
// 拿到结果
private val mLauncherUser = registerForActivityResult(CustomContractUser()) { result ->
Log.i(
TAG, "return result:$result"
)
Toast.makeText(this, result, Toast.LENGTH_SHORT).show()
}
class CustomContractUser : ActivityResultContract<User, String>() {
companion object {
const val DEFAULT_VALUE = "default_value"
const val TAG = "CustomContract"
}
/**
* 创建Intent
* @param context Context
* @param input 当前类的第一个泛型参数
* @return 启动的intent
*/
override fun createIntent(context: Context, input: User): Intent {
Log.i(TAG, "createIntent: $input")
val i = Intent(context, ResultApiActivity::class.java)
i.putExtra(ResultApiActivity.KEY_USER, input)
return i
}
/**
* 解析结果,类似于Activity#onActivityResult
* @param resultCode 返回码 [Activity.setResult] 的 resultCode
* @param intent [Activity.setResult] 的 intent
* @return
*/
override fun parseResult(resultCode: Int, intent: Intent?): String {
Log.i(TAG, "parseResult: $resultCode")
if (resultCode != Activity.RESULT_OK || intent == null) return DEFAULT_VALUE
return intent.getStringExtra(ResultApiActivity.KEY_TRANSFER) ?: DEFAULT_VALUE
}
}
启动并传递参数:
mLauncherUser.launch(User("debug", 18))
第二个页面接受参数:
val code = intent.getIntExtra(KEY_PWD, 0)
// android 13可以使用这个api
// val user = intent.getParcelableExtra("user", User::class.java)
// 接受对象
val user = intent.getParcelableExtra<User>(KEY_USER)
val str = user?.name + ", " + user?.age
解析对象Android13还新增了api。和之前差不多。
第二个页面的完整代码:
package com.example.aa
class ResultApiActivity : AppCompatActivity() {
companion object {
const val KEY_TRANSFER = "key_transfer"
const val KEY_PWD = "pwd"
const val KEY_USER = "user"
}
private lateinit var btn: Button
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_result_api)
btn = findViewById(R.id.btn)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
val code = intent.getIntExtra(KEY_PWD, 0)
// android 13可以使用这个api
// val user = intent.getParcelableExtra("user", User::class.java)
val user = intent.getParcelableExtra<User>(KEY_USER)
val str = user?.name + ", " + user?.age
btn.text = str
btn.setOnClickListener {
val i = Intent()
i.putExtra(KEY_TRANSFER, "hello $code")
// 都可以
setResult(RESULT_OK, intent.putExtra(KEY_TRANSFER, "act return str $code"))
// setResult(RESULT_OK, i)
finish()
}
}
}
整体来说好像写的代码没比之前少,但是每个启动和接受都独立隔离,更清晰。
参考https://juejin.cn/post/7237014602751279161#heading-7