kotlin implements the interface jump of registerForActivityResult mode

Posted by BrianPeiris on Fri, 18 Feb 2022 02:54:56 +0100

In the latest Android SDK, startActivityForResult has been marked as an outdated method, instead of using registerForActivityResult.

1. Why use registerForActivityResult?
In the previous way of using startActivityForResult, you need to pass a requestCode. When the destination interface returns to this interface, you can use the requestCode to identify the return value of which request. This seems a little crude and rude.
In the way of using registerForActivityResult, you need to implement the listening callback and register the listening interface, then initiate the interface jump request, and realize the processing of the returned data in the listening callback, which is more in line with the interface oriented programming method.

2. Get familiar with registerForActivityResult
a. The first is the method of registering the listening interface

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

Two parameters are required. One parameter is ActivityResultContract, which can be called interface result contract. It mainly defines 1 What is the purpose of initiating interface jump 2 The data type of the parameter you want to input, i.e. I 3 in generic < I, O > You want to get the data type of the returned result, that is, O in generic < I, O >. It's troublesome to implement by yourself, but fortunately, the SDK has implemented most of the commonly used ActivityResultContracts and the internal classes defined in ActivityResultContracts. Another parameter is ActivityResultCallback, which is the processing of the returned results.
b. Initiate jump request
In the previous registration, you will get an ActivityResultLauncher. When initiating the jump, call the launch method of ActivityResultLauncher and pass in the parameters.

public void launch(@SuppressLint("UnknownNullness") I input) {
        launch(input, null);
    }

It should be noted that the step of registering the listening interface must be before the current Activity status is STARTED, otherwise a runtime exception will be reported when calling launch. You can usually register when the onCreate() callback of the Activity.

3. Jump and return processing of general interface

		lateinit var lunch01: ActivityResultLauncher<Intent>
		
        lunch01 = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
        	//The lambda expression used here is the implementation of the second parameter ActivityResultCallback
            if(it.resultCode == Activity.RESULT_OK){
                Log.d("yys", "Data returned successfully: ${it.data?.extras?.get("resultdata")}")
            }else{
                Log.d("yys", "Data failure return")
            }
        }
        
        dataTransforBtn.setOnClickListener {
            var goods = Goods("Notebook computer", 10)
            var intent = Intent()
            intent.setClass(this, DataTransforActivity::class.java)
            intent.putExtra("goods", goods);
            lunch01.launch(intent)
        }

The it variable in the above code is the data returned from the previous interface. It is of ActivityResult type, which is in activityresultcontracts What has been defined in startactivityforresult is for convenience.
The Goods in the above code is a user-defined data type and implements the Parcelable serialization interface. The implementation method in kotlin is very simple:

@Parcelize
data class Goods(var name:String, var number:Int) : Parcelable{

}

4. Return the result of applying for privacy permission
You can also dynamically apply for permission by registerForActivityResult, and the SDK has defined relevant protocol classes for us in ActivityResultContracts, which can be used directly. The following is an operation to apply for reading contact permission:

	lateinit var lunch02: ActivityResultLauncher<String>

        lunch02 = registerForActivityResult(ActivityResultContracts.RequestPermission()) {
            if (it) {
                Log.d("yys", "Get address book reading permission-success")
            } else {
                Log.d("yys", "Get address book reading permission-fail")
            }
        }
        contactPermissionBtn.setOnClickListener {
            lunch02.launch(Manifest.permission.READ_CONTACTS)
        }

5. Apply for multiple permissions at the same time

	lateinit var lunch03: ActivityResultLauncher<Array<String>>

	lunch03 = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
            for (item in it) {
                Log.d("yys", "obtain \"${item.key}\" jurisdiction ${if (item.value) "success" else "fail"}")
            }
        }
        multPermissionBtn.setOnClickListener {
            lunch03.launch(
                arrayOf(
                    Manifest.permission.READ_CONTACTS,
                    Manifest.permission.ACCESS_COARSE_LOCATION,
                    Manifest.permission.ACCESS_FINE_LOCATION
                )
            )
        }

You can see that the input parameter is an array of character types, and the returned result it becomes a map < string, Boolean > > collection.
Of course, you need to apply for the above permissions in the AndroidManifest file first, and then you can apply dynamically.

6. Call the file manager to select a file

	lateinit var lunch04: ActivityResultLauncher<String>

	lunch04 = registerForActivityResult(ActivityResultContracts.GetContent()) {
            Log.d("yys", it.toString())
        }
        contentBtn.setOnClickListener {
            lunch04.launch("text/plain")
        }

7. Write at the end
It can be seen that Android has developed the registerForActivityResult method to obtain the return data. At the same time, it has also developed many implemented contract classes in ActivityResultContracts, which makes the development logical, convenient and fast. In addition to the above contracts, there are:

public static class TakePicturePreview extends ActivityResultContract<Void, Bitmap> // Photo Preview

public static class TakePicture extends ActivityResultContract<Uri, Boolean> //Photo preservation

public static class TakeVideo extends ActivityResultContract<Uri, Bitmap> //videotape

public static class GetMultipleContents extends ActivityResultContract<String, List<Uri>> //Get multiple types of files

public static final class PickContact extends ActivityResultContract<Void, Uri>  // Select contact

public static class OpenDocument extends ActivityResultContract<String[], Uri>  //open documents

public static class CreateDocument extends ActivityResultContract<String, Uri>  //create documents


Topics: Android kotlin