Sunday 24 April 2022

Android registerForActivityResult


As a very fundamentals that we Android developer has learned, and it shows the way for communicating between two components. The provided startActivityForResult(..), onActivityForResut(..) was simple enough to implement for many years, but now we are hard to accept the change, it would be the evolution of language and its features which really helps to do the code in concise way.  So, as per this we see some pitfalls on the earlier approach like

  • Difficult to search the caller function in our project, 
  • Tedious in getting and handles the results on the fragment, 
  • Chance of missing out the results when the component is recreated, 
  • Conflicts with the same request code, 
  • Handling self-permissions request etc.
Earlier Approach:


Now, with updates to androidx.activity:activity-ktx to 1.2.0. It has deprecated startActivityForResult in favor of registerForActivityResult, notable thing is this implementation avoids and taken care of the above mentioned issues.  Notable thing is here we no need of permission request code, it will be taken care automatically. 

Let’s see the new implementation on implicit and explicit calls with registerForActivityResult, ActivityResultLauncher, ActivityResultContracts, ActivityResultCallback.

The class registerForActivityResult helps to register with ActivityResultContracts (which handles explicit or implicit calls) and other param as the callback action as lambda blocks with (ActivityResultCallback) and returns the launcher (ActivityResultLauncher) object, where we use the launch (...) method with params.

New Approach:

Explicit Calls: We all know calling another activity or component and getting result from there on finish on explicit intent calls.


In the above approach we are creating our explicit launcher which gets data on the resultant callbacks, so this way it would be easy to define our multiple launcher and those are handled independently.  Here the same approach can be used on the Fragment as well.

Implicit Calls: The implicit calls which invoke the system contracts such as take a Picture from camera gallery, accessing contacts, etc.  Please refer the below link for all available ActivityResultContracts


Conclusion:  The approach towards registerForActivityResult is really clean & concise, IMO below are the pros 
  • Improved code readability, here we no need to jump between onActivityResult() & startActivityForResult.
  • ActivityResultLauncher is returned by registerForActivityResult and this used to launch the components, the input parameter is clearly defined to get the desired results is the callback.
  • There is no Boilerplate code for requesting permission from the user.



Saturday 2 April 2022

Get context in Jetpack Compose

In Android Compose, you can get the context by using the LocalContext, but it should be call'd from the composable function / scope.

val context = LocalContext.current

In the below code snippet we are retrieving the context and show a toast message inside the composable.

@Composable
fun MyToastDisplay(name: String) {
    val ctx = LocalContext.current
    Column(
        Modifier
            .fillMaxHeight()
            .fillMaxWidth(), verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(text = "Hello $name", color = Color.Red,
            modifier = Modifier
                .background(Color.Green)
                .clickable {
                    Toast
                        .makeText(ctx, "Welcome to the Compose World", Toast.LENGTH_SHORT)
                        .show()
                })
    }
}

If you use the LocalContext.current directly inside the clickable function results in the compilation error “@composable invocations can only happen from the context of an @composable function”.


Since the LocalContext.current is composable, you can’t invoke it within the non-composable function.  i.e. clickable function is not a composable function and so can’t accept other composable functions. 

Alternatively, you can get the context outside the clickable function scope and use, as shown in the above code snippet.


Happy Coding :-)