Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use Activity Result API in Android

2025-04-12 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

Editor to share with you how to use Activity Result API in Android. I hope you will get something after reading this article. Let's discuss it together.

If you upgrade the appcompat library in your project to version 1.3.0 or later, you will find that the startActivityForResult () method is obsolete.

This method is believed to have been used by all developers who have done Android, and it is mainly used to exchange data between two Activity.

So why is this method so commonly used abandoned? The official statement is that it is now more recommended to use Activity Result API to exchange data between two Activity.

My personal view is that there is nothing fatal with the startActivityForResult () method, but that Activity Result API does better in terms of ease of use and interface uniformity. Now that there is a better API, it is no longer recommended to use the old API, so the startActivityForResult () method is marked as obsolete.

In fact, in addition to the startActivityForResult () method, there are also methods like requestPermissions () that are marked as obsolete. There seems to be no correlation between the two, but in Activity Result API, they are grouped into a unified API template. Therefore, we can use very similar code to implement the function of exchanging data between two Activity and requesting runtime permissions.

In addition, the use of Activity Result API is very simple, as soon as you learn it. I believe that after reading this article, you can upgrade all the relevant code in your project to the use of Activity Result API.

So let's get started.

Exchange data between two Activity

If you want to exchange data between two Activity, let's review the traditional way of writing:

Class FirstActivity: AppCompatActivity () {override fun onCreate (savedInstanceState: Bundle?) {super.onCreate (savedInstanceState) setContentView (R.layout.activity_first) val firstButton = findViewById (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}

The startActivityForResult () method is called to request data from SecondActivity, and then the result returned by SecondActivity is parsed in the onActivityResult () method.

So what does the code in SecondActivity look like? Here we will simply simulate and return a random amount of data:

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

In this way, the ability of FirstActivity to request data from SecondActivity becomes available, doesn't it feel quite simple? So as I just said, there is nothing fatal about the startActivityForResult () method.

So let's learn how to use Activity Result API to achieve the same function.

First of all, the code in SecondActivity does not need to be modified. This part of the code is not obsolete, and Activity Result API has nothing to do with it.

For the code in FirstActivity, we need to use Activity Result API instead of writing startActivityForResult (), as follows:

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

Note the code changes here. Instead of completely removing the override to the onActivityResult () method, we call the registerForActivityResult () method to register a listener on the Activity result.

The registerForActivityResult () method takes two parameters, the first of which is a Contract type, and since we want to request data from another Activity, we use a Contract like StartActivityForResult. The second parameter is an Lambda expression, which is called back here when a result is returned, and then we can get and process the data here.

The return value of the registerForActivityResult () method is an ActivityResultLauncher object in which there is a launch () method that can be used to enable Intent. Instead of calling the startActivityForResult () method, we can simply call the launch () method and pass in the Intent.

Which of these two ways of writing is better or worse? Personally, I think Activity Result API is a little easier to write, but the overall advantage is not that great. The real advantage of Activity Result API is what we're going to talk about next.

Request runtime permissions

In addition to the startActivityForResult () method, the requestPermissions () method is also deprecated. For the same reason, it is recommended to use Activity Result API.

So how do you use Activity Result API to request runtime permissions? Don't be surprised, it will be surprisingly simple:

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 (R.id.first_button) firstButton.setOnClickListener {requestPermissionLauncher.launch (Manifest.permission.READ_EXTERNAL_STORAGE)}

We only need to focus on the part of the code change.

Since you are requesting runtime permissions this time, you can no longer use the same StartActivityForResult as Contract, but instead use RequestPermission as a Contract.

In addition, the parameters of the Lambda expression also change because different Contract is specified. Now the Lambda expression passes in a Boolean parameter that tells us whether the user has allowed the permission we requested.

Finally, the parameters of the launch () method have also changed, and now all you need to do is pass in the name of the permission to be requested.

Have you noticed that the templates of these two pieces of code are surprisingly consistent? We used two similar pieces of code to implement two functions that were hardly related before. This is the advantage of Activity Result API, which unifies some API interfaces, making it very easy for us to implement specific functions.

Built-in Contract

We just experienced two kinds of Contract, StartActivityForResult and RequestPermission, which are used to exchange data between two Activity and to request runtime permissions, respectively. They are all Contract built into Activity Result API.

So what other built-in Contract do we have to use?

Here are all the built-in Contract supported by the 1.3.0 version of appcompat I listed, and new Contract may continue to be added in the future:

StartActivityForResult ()

StartIntentSenderForResult ()

RequestMultiplePermissions ()

RequestPermission ()

TakePicturePreview ()

TakePicture ()

TakeVideo ()

PickContact ()

GetContent ()

GetMultipleContents ()

OpenDocument ()

OpenMultipleDocuments ()

OpenDocumentTree ()

CreateDocument ()

The naming of each Contract has made it clear what their purpose is, that is, when we want to implement the functions contained in the above Contract, we no longer need to write it manually. Activity Result API has already supported it for us.

For example, if I want to call the phone camera to take a picture and get the Bitmap object of the picture, then I can use the Contract of TakePicturePreview.

The implementation code is as follows:

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

The code is very simple, just change the Contract type, and then the parameters of the Lambda expression will become a bitmap object. In addition, since the Contract of TakePicturePreview does not require input parameters, we can simply pass in null when we call the launch () method.

Seeing this, some readers may be curious. How do I know what input parameters are required for each Contract and what parameters are returned in the Lambda expression?

This is very simple, just take a look at the source code of this Contract. For example, the source code of TakePicturePreview is as follows:

/ * 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 {...}

For the time being, we don't have to worry about the specific implementation within TakePicturePreview, just take a look at the generic type it specifies when inheriting the parent class. The first parameter is the required input parameter, and the second parameter is the output parameter returned by the Lambda expression.

As long as you master this little trick, you can easily use every kind of Contract. Then I won't do any more demonstrations, and the rest of these uses of Contract are waiting for you to explore.

Custom Contract

In addition to the above built-in Contract, we can indeed define our own Contract types.

Although I don't think this is very necessary, because the built-in Contract can already help us deal with most scenarios.

However, customizing Contract is not a complicated matter. On the contrary, it is very simple, so let's briefly mention it here.

Just now we probably saw the source implementation of TakePicturePreview, which must inherit from the ActivityResultContract class and specify the input and output parameters of the current Conract type through generics.

ActivityResultContract is an abstract class with two abstract methods defined inside it, as follows:

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

That is, any Contract that inherits from ActivityResultContract needs to override the createIntent () and parseResult () methods.

And the effect of these two methods is also very obvious. CreateIntent () is used to create an Intent, which is later used to initiate actions, such as starting another Activity to get data, or turning on the camera to take pictures, and so on. ParseResult () is the result of parsing the response and returning the parsed result as an output parameter to the Lambda expression.

Each built-in Contract uses this rule to encapsulate its own logic.

So what kind of Contract are we going to customize for demonstration?

I thought for a moment that when we were writing to exchange data between two Activity, we needed to start SecondActivity explicitly and manually parse the data returned by SecondActivity from the Intent, which was a bit of a hassle. This can be optimized with the help of custom Contract.

Create a new Contract called GetDataFromSecondActivity with the following code:

Class GetDataFromSecondActivity: ActivityResultContract () {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}}

We specify through generics that the input parameter of this Contract is Void and the output parameter is a string.

Then in the createIntent () method, we manually create an Intent and set its purpose to open SecondActivity.

Finally, in the parseResult () method, we parse the result returned by SecondActivity and return the parsed string as an output parameter.

Such a custom Contract is complete, and it will be easier for us to use this Contract to implement the original function of exchanging data between two Activity:

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 (R.id.first_button) firstButton.setOnClickListener {getDataLauncher.launch (null)}

As you can see, with the Contract of GetDataFromSecondActivity, we no longer need to explicitly declare to start the SecondActivity,launch () method and pass it directly into null. In addition, we no longer need to manually parse the data returned by SecondActivity, the parameters on the lambda expression are the parsed results.

One last little question.

At this point, we have basically learned all the contents of Activity Result API.

At the end of this article, I would like to answer one more small question. Because I had such doubts when using Activity Result API, I guess some friends might have the same question, so I can easily answer it here.

Now you know that Activity Result API can completely replace the startActivityForResult () method. But when we call the startActivityForResult () method, we need to pass in another requestCode, in addition to Intent, to distinguish between multiple tasks. For example, the following code:

Class FirstActivity: AppCompatActivity () {override fun onCreate (savedInstanceState: Bundle?) {super.onCreate (savedInstanceState) setContentView (R.layout.activity_first) val firstButton = findViewById (R.id.first_button) val secondButton = findViewById (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}

Here we call the startActivityForResult () method in two places, each of which is used to handle different tasks, so we need to set different requestCode for them.

In the onActivityResult () method, we judge the requestCode again here in order to distinguish which task the result came from.

This is the traditional way of writing when you used the startActivityForResult () method.

And Activity Result API has no place for you to introduce requestCode.

When I first came into contact with Activity Result API, I was perplexed by this problem due to the inertia of thinking. What should I do if there is no place to introduce requestCode?

Later, when I turned around, I realized that Activity Result API doesn't need requestCode at all. We can use the following words to achieve exactly the same function as before:

Class FirstActivity: AppCompatActivity () {privateval actionViewLauncher = registerForActivityResult (ActivityResultContracts.StartActivityForResult ()) {result-> / / Handle result for ACTION_VIEW} privateval 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 ( R.id.first_button) val secondButton = findViewById (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)}

It can also be seen that the design of Activity Result API is more reasonable, and multiple tasks can be distinguished without the help of magic numbers such as requestCode.

Everything is simpler and clearer.

After reading this article, I believe you have a certain understanding of "how to use Activity Result API in Android". If you want to know more about it, you are welcome to follow the industry information channel. Thank you for reading!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report