我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android中Activity Result API怎么用

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android中Activity Result API怎么用

小编给大家分享一下Android中Activity Result API怎么用,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

如果你将项目中的appcompat库升级到1.3.0或更高的版本,你会发现startActivityForResult()方法已经被废弃了。

Android中Activity Result API怎么用

这个方法相信所有做过Android的开发者都用过,它主要是用于在两个Activity之间交换数据的。

那么为什么这个如此常用的方法会被废弃呢?官方给出的说法是,现在更加建议使用Activity Result API来实现在两个Activity之间交换数据的功能。

Android中Activity Result API怎么用

我个人的观点是,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<Button>(R.id.first_button)        firstButton.setOnClickListener {            val intent = Intent(this, SecondActivity::class.java)            startActivityForResult(intent, 1)        }    }    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {        super.onActivityResult(requestCode, resultCode, data)        when (requestCode) {            1 -> {                if (resultCode == RESULT_OK) {                    val data = data?.getStringExtra("data")                    // Handle data from SecondActivity                }            }        }    }    }

这里调用了startActivityForResult()方法去向SecondActivity请求数据,然后在onActivityResult()方法中去解析SecondActivity返回的结果。

那么SecondActivity中的代码是什么样的呢?这里我们就简单模拟一下,随便返回一个数据即可:

class SecondActivity : AppCompatActivity() {    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_second)        val secondButton = findViewById<Button>(R.id.second_button)        secondButton.setOnClickListener {            val intent = Intent()            intent.putExtra("data", "data from SecondActivity")            setResult(RESULT_OK, intent)            finish()        }    }}

如此一来,FirstActivity向SecondActivity请求数据的功能就通了,是不是感觉也挺简单的?所以我刚才说了,startActivityForResult()方法并没有什么致命的问题。

那么接下来我们学习一下如何使用Activity Result API来实现同样的功能。

首先,SecondActivity中的代码是不需要修改的。这部分代码并没有被废弃,Activity Result API也与它无关。

FirstActivity中的代码,我们需要使用Activity Result API来替代startActivityForResult()的写法,如下所示:

class FirstActivity : AppCompatActivity() {    private val 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<Button>(R.id.first_button)        firstButton.setOnClickListener {            val intent = Intent(this, SecondActivity::class.java)            requestDataLauncher.launch(intent)        }    }    }

注意这里的代码变更。我们完全移除了对onActivityResult()方法的重写,而是调用registerForActivityResult()方法来注册一个对Activity结果的监听。

registerForActivityResult()方法接收两个参数,第一个参数是一种Contract类型,由于我们是希望从另外一个Activity中请求数据,因此这里使用了StartActivityForResult这种Contract。第二个参数是一个Lambda表达式,当有结果返回时则会回调到这里,然后我们在这里获取并处理数据即可。

registerForActivityResult()方法的返回值是一个ActivityResultLauncher对象,这个对象当中有一个launch()方法可以用于去启用Intent。这样我们就不需要再调用startActivityForResult()方法了,而是直接调用launch()方法,并把Intent传入即可。

这两种写法到底孰优孰劣呢?我个人感觉还是Activity Result API的写法更简单一点,不过总体优势并没有那么大。Activity Result API真正的优势在于我们接下来要讲的内容。

请求运行时权限

除了startActivityForResult()方法之外,requestPermissions()方法也被废弃了。至于理由都是一样的,推荐使用Activity Result API。

Android中Activity Result API怎么用

那么要如何使用Activity Result API来请求运行时权限呢?不要惊讶,它将会出奇得简单:

class FirstActivity : AppCompatActivity() {        private val 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<Button>(R.id.first_button)        firstButton.setOnClickListener {            requestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)        }    }    }

我们只需关注代码变更的部分。

由于这次是请求运行时权限,因此不能再使用刚才的StartActivityForResult来作为Contract了,而是要使用RequestPermission这种Contract。

另外由于指定了不同的Contract类似,Lambda表达式的参数也会发生变化。现在Lambda表达式会传入一个布尔型的参数,用于告诉我们用户是否允许了我们请求的权限。

最后,launch()方法的参数也发生了变化,现在只需传入要请求的权限名即可。

有没有发现,这两段代码的模板出奇得一致。我们使用了两段差不多的代码,实现了之前几乎并没有太大联系的两个功能。这就是Activity Result API的好处,它将一些API的接口统一化,使得我们在实现特定功能的时候能够变得非常简单。

内置Contract

刚才我们体验了StartActivityForResult和RequestPermission这两种Contract,分别用于在两个Activity之间交换数据,以及请求运行时权限。它们都是Activity Result API中内置的Contract。

那么除此之外,我们还有哪些内置Contract可以使用呢?

下面是我列出的appcompat 1.3.0版本所支持的所有内置Contract,以后还可能会继续增加新的Contract:

StartActivityForResult()
StartIntentSenderForResult()
RequestMultiplePermissions()
RequestPermission()
TakePicturePreview()
TakePicture()
TakeVideo()
PickContact()
GetContent()
GetMultipleContents()
OpenDocument()
OpenMultipleDocuments()
OpenDocumentTree()
CreateDocument()

每个Contract的命名已经明确表示它们的作用是什么了,也就是说,当我们要实现以上Contract所包含的功能时,都不需要再自己手动费力去写了,Activity Result API已经帮我们支持好了。

比如,我想要调用手机摄像头去拍摄一张图片,并且得到这张图片的Bitmap对象,那么就可以使用TakePicturePreview这个Contract。

实现代码如下:

class FirstActivity : AppCompatActivity() {    private val takePictureLauncher = registerForActivityResult(ActivityResultContracts.TakePicturePreview()) { bitmap ->        // bitmap from camera    }    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_first)        val firstButton = findViewById<Button>(R.id.first_button)        firstButton.setOnClickListener {            takePictureLauncher.launch(null)        }    }}

代码非常简单,就是换了一下Contract类型,然后Lambda表达式的参数会变成bitmap对象。另外由于TakePicturePreview这个Contract不需要输入参数,所以我们调用launch()方法的时候直接传入null就可以了。

看到这里,可能有些读者朋友会比较好奇。我怎么知道每种Contract要求什么输入参数,以及Lambda表达式中返回的参数是什么呢?

这个很简单,只需要看一下这个Contract的源码即可。比如TakePicturePreview的源码如下:

public static class TakePicturePreview extends ActivityResultContract<Void, Bitmap> {    ...}

我们暂时不用关心TakePicturePreview内部的具体实现,只要看一下它在继承父类时指定的泛型类型即可。其中第一个参数就是要求的输入参数,而第二个参数就是Lambda表达式返回的输出参数。

只要掌握这个小技巧,每种Contract你就都能轻松运用自如了。那么我就不再多做演示,剩下这些Contract的用法等待你自己去探索。

自定义Contract

除了以上内置Contract之外,我们确实也可以定义自己的Contract类型。

虽然我觉得这个必要性并不是很强,因为内置Contract已经可以帮助我们应对绝大多数场景了。

不过,自定义Contract并不是一件复杂的事情。相反,它非常简单,所以这里还是简略提一下吧。

刚才我们大概看到了TakePicturePreview的源码实现,它必须继承自ActivityResultContract类,并通过泛型来指定当前Conract类型的输入参数和输出参数。

ActivityResultContract是一个抽象类,它的内部定义了两个抽象方法,如下所示:

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

也就是说,任何一个继承自ActivityResultContract的Contract,都需要重写createIntent()和parseResult()这两个方法。

而这两个方法的作用也非常明显。createIntent()就是用于创建一个Intent,后续会使用这个Intent来发起动作,比如启动另外一个Activity去获取数据,或者打开相机去拍照等等。而parseResult()则是用于解析响应的结果,并把解析出来的结果作为输出参数返回到Lambda表达式当中。

每一个内置的Contract都是使用的这种规则来封装的自己的逻辑。

那么我们要自定义一个什么样的Contract来进行演示呢?

我想了一下,刚才在编写两个Activity之间交换数据的时候,我们需要显示地启动SecondActivity,并手动将SecondActivity返回的数据从Intent中解析出来,这就稍微有些麻烦。而借助自定义Contract就可以对此处进行优化。

新建一个叫做GetDataFromSecondActivity的Contract,代码如下所示:

class GetDataFromSecondActivity : ActivityResultContract<Void, String?>() {    override fun createIntent(context: Context, input: Void?): Intent {        return Intent(context, SecondActivity::class.java)    }    override fun parseResult(resultCode: Int, intent: Intent?): String? {        if (resultCode == Activity.RESULT_OK) {            if (intent != null) {                return intent.getStringExtra("data")            }        }        return null    }    }

我们通过泛型指定,这个Contract的输入参数是Void,输出参数是一个字符串。

然后在createIntent()方法中,我们手动创建了一个Intent,并将它的用途设置为打开SecondActivity。

最后在parseResult()方法中,我们对SecondActivity返回的结果进行解析,并将解析出来的字符串作为输出参数返回。

这样一个自定义的Contract就完成了,而我们使用这个Contract再去实现最开始的在两个Activity之间交换数据的功能,就会变得更加简单:

class FirstActivity : AppCompatActivity() {    private val getDataLauncher = registerForActivityResult(GetDataFromSecondActivity()) { data ->        // Handle data from SecondActivity    }    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_first)        val firstButton = findViewById<Button>(R.id.first_button)        firstButton.setOnClickListener {            getDataLauncher.launch(null)        }    }}

可以看到,借助GetDataFromSecondActivity这个Contract,我们不需要再显式地声明去启动SecondActivity,launch()方法直接传入null即可。另外,我们也不需要再去手动解析SecondActivity返回的数据,lambda表达式上的参数就是解析出来的结果了。

最后一个小问题

到这里,我们基本就将Activity Result API的所有内容都学完了。

在本篇文章的最后,我想再回答一个小问题。因为我自己当初在使用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<Button>(R.id.first_button)        val secondButton = findViewById<Button>(R.id.second_button)        firstButton.setOnClickListener {            val intent = Intent(Intent.ACTION_VIEW)            startActivityForResult(intent, 1)        }        secondButton.setOnClickListener {            val intent = Intent(Intent.ACTION_DIAL)            startActivityForResult(intent, 2)        }    }    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {        super.onActivityResult(requestCode, resultCode, data)        when (requestCode) {            1 -> {                // Handle result for ACTION_VIEW            }            2 -> {                // Handle result for ACTION_DIAL            }        }    }}

这里我们分别在两处调用了startActivityForResult()方法,它们各自用于处理不同的任务,因此需要给它们设置不同的requestCode。

在onActivityResult()方法当中,我们为了区分这个结果是来自之前的哪个任务的,所以要在这里再对requestCode进行判断。

这是以前使用startActivityForResult()方法时的传统写法。

而Activity Result API是没有地方让你传入requestCode的。

我在刚接触Activity Result API的时候受思维惯性的影响被这个问题困扰了一下,没有地方传入requestCode该怎么办呢?

后来思维转过来弯之后发现,原来Activity Result API根本就不需要requestCode这种东西,我们可以使用如下写法来实现和刚才完全一样的功能:

class FirstActivity : AppCompatActivity() {    private val actionViewLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->        // Handle result for ACTION_VIEW    }    private val actionDialLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->        // Handle result for ACTION_DIAL    }    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_first)        val firstButton = findViewById<Button>(R.id.first_button)        val secondButton = findViewById<Button>(R.id.second_button)        firstButton.setOnClickListener {            val intent = Intent(Intent.ACTION_VIEW)            actionViewLauncher.launch(intent)        }        secondButton.setOnClickListener {            val intent = Intent(Intent.ACTION_DIAL)            actionDialLauncher.launch(intent)        }    }}

由此也可以看出,Activity Result API的设计更加合理,不需要借助requestCode这种魔术数字也能对多个任务进行区分。

一切都更加简单和清晰。

看完了这篇文章,相信你对“Android中Activity Result API怎么用”有了一定的了解,如果想了解更多相关知识,欢迎关注编程网行业资讯频道,感谢各位的阅读!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android中Activity Result API怎么用

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android中Activity Result API怎么用

小编给大家分享一下Android中Activity Result API怎么用,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!如果你将项目中的appcompat库升级到1.3.0或更高的版本,你会发现startActivit
2023-06-29

Android中Activity组件怎么使用

今天小编给大家分享一下Android中Activity组件怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。Activi
2023-06-26

php中result怎么用

这篇文章主要介绍了php中result怎么用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇php中result怎么用文章都会有所收获,下面我们一起来看看吧。在php中,result的意思是“结果”,“mysql
2023-06-26

Android中Activity有什么用

小编给大家分享一下Android中Activity有什么用,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!理论概述Activity的理解Activity的定义Act
2023-06-22

android怎么调用activity方法

要调用一个Activity的方法,首先需要获取Activity的实例,然后通过该实例来调用方法。以下是一种常用的方法调用方式:1. 在目标Activity中定义需要调用的方法。例如,目标Activity中定义了一个名为"doSomethin
2023-09-16

Android中怎么关闭多个Activity

Android中怎么关闭多个Activity,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1、使用Application来进行关闭public class App exte
2023-05-30

android的activity怎么跳转到另一个activity

在Android中,要从一个Activity跳转到另一个Activity,可以使用Intent和startActivity方法。下面是一个简单的示例:1. 首先,在AndroidManifest.xml文件中注册要跳转的目标Activity
2023-08-17

Android中怎么利用Activity实现滑动返回

这期内容当中小编将会给大家带来有关Android中怎么利用Activity实现滑动返回,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Android 滑动返回Activity的实现代码package com
2023-05-30

Android中怎么使用Activity和Fragment传递数据

Android中怎么使用Activity和Fragment传递数据,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。1、第一种方式,也是最常用的方式,就是使用Bundle来传递参数
2023-05-30

Android中怎么实现Activity 间的传值

今天就跟大家聊聊有关Android中怎么实现Activity 间的传值,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Android 中两个Activity 之间的传值问题在Andro
2023-05-30

Android开发中怎么实现Activity切换

今天就跟大家聊聊有关Android开发中怎么实现Activity切换,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。具体如下:这里要实现的目的是:有3个Activity: A,B,C,
2023-05-31

怎么在Android中利用Activity实现单元测试

这期内容当中小编将会给大家带来有关怎么在Android中利用Activity实现单元测试,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。对Acitivity的测试对于Activity,我们大致有两种测试需求
2023-05-30

android怎么创建新的activity

要创建一个新的Activity,你需要按照以下步骤进行操作:1. 在Android Studio中打开你的项目。2. 在项目的"java"文件夹中找到你想要创建Activity的包。3. 右键点击包名,选择"New" -> "Activit
2023-08-18

Android 中怎么实现Activity 间传递参数

这篇文章将为大家详细讲解有关Android 中怎么实现Activity 间传递参数,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。1.传递简单数据在A Activity中findViewByI
2023-05-30

Android开发中怎么启动另一个应用中的Activity

这篇文章将为大家详细讲解有关Android开发中怎么启动另一个应用中的Activity,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Android 启动另一个App/apk中的Activit
2023-05-31

怎么在android中利用Activity进行横竖屏切换

这篇文章给大家介绍怎么在android中利用Activity进行横竖屏切换,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。设置屏幕的方向简介值描述unspecified默认值。系统自动选择屏幕方向behind跟activ
2023-05-31

怎么在Android中利用Activity实现一个监听器

怎么在Android中利用Activity实现一个监听器?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Activity在Activity中,使用findViewById(int
2023-06-14

怎么在Android中利用Activity实现跳转与传值

今天就跟大家聊聊有关怎么在Android中利用Activity实现跳转与传值,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Android Activity的跳转与传值详解Activi
2023-05-31

Android应用中的Activity跳转怎么利用滑动来实现

这篇文章给大家介绍Android应用中的Activity跳转怎么利用滑动来实现,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。通过手势识别器实现界面的转跳,具体内容如下1、创建 GestureDetector对象 2、创
2023-05-31

怎么在Android应用中利用Activity对动画进行切换

今天就跟大家聊聊有关怎么在Android应用中利用Activity对动画进行切换,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Android Activity切换动画Android
2023-05-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录