那么为什么这个如此常用的方法会被废弃呢?官方给出的说法是,现在更加建议使用Activity Result API来实现在两个Activity之间交换数据的功能。
我个人的观点是,startActivityForResult()方法并没有什么致命的问题,只是Activity Result API在易用性和接口统一性方面都做得更好。既然有更好的API,那么就不再建议去使用过去老旧的API,所以才把startActivityForResult()方法标为了废弃。
其实除了startActivityForResult()方法之外,还有像requestPermissions()方法也被标为了废弃。看起来它们两者之间好像并没有什么关联,但是到了Activity Result API中,它们就被归属到了统一的API模板当中。因此,我们可以使用非常类似的代码去实现在两个Activity之间交换数据,以及请求运行时权限的功能。
另外,Activity Result API的用法非常简单,一学就会。相信你看完本篇文章之后,就可以将自己项目中所有相关的代码都升级成Activity Result API的用法。
那么我们开始吧。
在两个Activity之间交换数据
如果想要在两个Activity之间交换数据,我们先回顾一下传统的写法:
class FirstActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_first) val firstButton = findViewById
首先,SecondActivity中的代码是不需要修改的。这部分代码并没有被废弃,Activity Result API也与它无关。
FirstActivity中的代码,我们需要使用Activity Result API来替代startActivityForResult()的写法,如下所示:
class FirstActivity : AppCompatActivity() { privateval requestDataLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == RESULT_OK) { val data = result.data?.getStringExtra("data") // Handle data from SecondActivity } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_first) val firstButton = findViewById
这两种写法到底孰优孰劣呢?我个人感觉还是Activity Result API的写法更简单一点,不过总体优势并没有那么大。Activity Result API真正的优势在于我们接下来要讲的内容。
请求运行时权限
除了startActivityForResult()方法之外,requestPermissions()方法也被废弃了。至于理由都是一样的,推荐使用Activity Result API。
那么要如何使用Activity Result API来请求运行时权限呢?不要惊讶,它将会出奇得简单:
class FirstActivity : AppCompatActivity() { privateval requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted -> if (granted) { // User allow the permission. } else { // User deny the permission. } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_first) val firstButton = findViewById
/** * An {@link ActivityResultContract} to * {@link MediaStore#ACTION_IMAGE_CAPTURE take small a picture} preview, returning it as a * {@link Bitmap}. *
* This can be extended to override {@link #createIntent} if you wish to pass additional * extras to the Intent created by {@code super.createIntent()}. */public static class TakePicturePreview extends ActivityResultContract { ...}
public abstract class ActivityResultContract { public abstract @NonNull Intent createIntent(@NonNull Context context, I input); public abstract O parseResult(int resultCode, @Nullable Intent intent); ...}
class FirstActivity : AppCompatActivity() { privateval getDataLauncher = registerForActivityResult(GetDataFromSecondActivity()) { data -> // Handle data from SecondActivity } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_first) val firstButton = findViewById
在本篇文章的最后,我想再回答一个小问题。因为我自己当初在使用Activity Result API的时候产生过这样的疑惑,所以我猜或许也会有朋友有同样的问题,那么在这里就顺手解答了。
现在你已经知道,Activity Result API是可以完全取代startActivityForResult()方法的。但是我们在调用startActivityForResult()方法时,除了传入Intent之外,还需要再传入一个requestCode,用于在多个任务之间进行区分。比如如下代码:
class FirstActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_first) val firstButton = findViewById