RegisterForActivityResult介绍


首先介绍一下其作用:

  1. 它可以取代 startActivityForResult方法,获取另一个Activity的返回结果。
  2. 它可以取代 requestPermissions方法,请求运行时权限。

并且,RegisterForActivityResult的实现方式比传统的方式更加便捷,合理。


1. 添加引用库

要在项目中使用该方法,需要添加两个官方的库:

implementation 'androidx.activity:activity-ktx:1.2.1'
implementation 'androidx.fragment:fragment-ktx:1.3.1'

添加之后支持在Activity或者Fragment里调用 RegisterForActivityResult方法。比较奇怪的一点是,如果只添加 activity-ktx而不添加 fragment-ktx,即使只在Activity里面调用该方法,App仍然会崩溃报如下错误:

 java.lang.IllegalArgumentException: Can only use lower 16 bits for requestCode

添加了Fragment支持库之后,问题就消失了。


2. 相关类和方法介绍

registerForActivityResult方法完整代码如下:

public final <I, O> ActivityResultLauncher<I> registerForActivityResult(
            @NonNull ActivityResultContract<I, O> contract,
            @NonNull ActivityResultCallback<O> callback) {
        return registerForActivityResult(contract, mActivityResultRegistry, callback);
}

//另一个文件
public abstract class ActivityResultLauncher<I> {   
      public void launch(I input) {        
            launch(input, null);    
      }
}

  • 它需要传入 ActivityResultContract
  • 它需要传入一个回调 ActivityResultCallback
  • 它返回一个 ActivityResultLauncher 对象
  • 调用 ActivityResultLauncherlaunch方法可以跳转到另一个Activity或者发起权限请求

下面我们分别来了解这些参数的作用:


2.1 ActivityResultContract

ActivityResultContract是一个抽象类,如下:

public abstract class ActivityResultContract<I, O> {  
      public abstract Intent createIntent( Context context,  I input);  
      public abstract O parseResult(int resultCode, Intent intent); 
      ... ...
}

其中:

  1. I表示传入的参数类型,O表示结果参数类型。这两个类型用来规范入参和返回结果。
    比如要跳转到另一个Activity,那么入参应该是一个Intent类型,包含要跳转的目标Activity信息。返回结果类型是希望从该Activity获取的数据的类型。

  2. createIntent方法用来新建一个Intent,以发起请求或跳转。其中的 input参数是由 ActivityResultLauncher.launch(I input)方法传入的。

  3. parseResult方法用来解析返回结果。

2.2 ActivityResultCallback

这个接口里只有一个方法,如下:

public interface ActivityResultCallback<O> { 
      void onActivityResult( O result);
}

ActivityResultContractparseResult方法返回的结果会回传到 onActivityResult方法。


3. 示例

下面来写一个实例,实现 startActivityForResult的功能。
这个例子功能很简单,我们有ActivityAActivityB,以及一个数据类 TestBean,我们要做的就是从 ActivityA跳转到 ActivityB,并从 ActivityB获取一个 TestBean并返回给 ActivityA

首先,定义 ActivityResultContract,要跳转到另一个Activity,入参显然得是一个Intent,返回的结果是一个TestBean,那么可以定义如下:

private val activityResultContract = object : ActivityResultContract<Intent, TestBean>(){    

      override fun createIntent(context: Context, input: Intent): Intent { 
            //这个intent由resultLauncher调用launch方法时传入
            return input    
      }    
      
      override fun parseResult(resultCode: Int, intent: Intent?): TestBean? {        
            if(resultCode == Activity.RESULT_OK){
                  return intent?.getParcelableExtra("testBean") ?: TestBean.EMPTY
            }
            return TestBean.EMPTY
      }
}

然后,创建 ActivityResultLauncher

private val resultLauncher = registerForActivityResult(activityResultContract){    
      tvResult.text = it.toString()
}

最后,发起调用:

resultLauncher.launch(Intent(ActivityA.this, ActivityB::class.java))

ActivityB中,调用如下方法:

val resultIntent = Intent().apply{ putExtra("testBean", testBean) }
setResult(Activity.RESULT_OK, resultIntent)
finish()

ActivityA就能获取到ActivityB传过来的TestBean对象。


4. 官方的封装

4.1 实现startActivityForResult

从上面的示例来看,用起来还是有点麻烦,需要自定义 ActivityResultContract。其实,谷歌已经针对不同的使用场景封装好了相应的ActivityResultContract。全部都放在 ActivityResultConstracts 类中, 包括运行时权限请求,选取图片,拍照获取uri,选取联系人等等。就不一一介绍了。我们试着用官方封装好的类来实现第三节示例中的功能。

//创建ActivityResultLauncher
val resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){    
      if(it.resultCode == Activity.RESULT_OK){        
            val result = it.data?.getStringExtra("testBean") ?: TestBean.EMPTY        
            tvResult.text = result.toString()    
      }
}
//跳转到ActivityB
resultLauncher.launch(Intent(ActivityA.this, ActivityB::class.java))

使用已经封装好的 ActivityResultContract, 实现和 3 的示例中完全相同的功能,代码量减少了一半以上。

4.2 实现requestPermissions
//创建ActivityResultLauncher
private val permissionResult = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()){    
      val resultCamera = it[Manifest.permission.CAMERA] ?: false    
      if(resultCamera){
          //Camera权限请求成功 
      }    
      val storageResult = it[Manifest.permission.READ_EXTERNAL_STORAGE] ?: false    
      if(storageResult){
          //存储权限请求成功
      }
}
//发起请求
permissionResult.launch(arrayOf(    
      Manifest.permission.CAMERA,    
      Manifest.permission.READ_EXTERNAL_STORAGE
))

请求运行时权限从未如此轻松简单。


以上。

  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值