Android Activity Result API with Hilt(Dependency Injection)

Oguzhan Alpayli
3 min readApr 22, 2021

--

Hello folks, I wanted to tell you everything about Activity Result API, but I will not do at all. :D As far as you know there are a lot of writings and also you can reach official info from here.

I am going to tell you about Activity Result API with using DI (Hilt) and LifecycleObserver. At last days I have been using Hilt, I am giving my sample with it. We can exemplify with camera and storage permissions.

Step1:

Firstly we are creating two helper classes , the first one is;

interface PermissionListener {
fun permissionGranted()
fun permissionDenied()
}

The second one is;

abstract class AbstractPermissionObserver : LifecycleObserver {

var granted: Boolean = false
var permissionListener: PermissionListener? = null

abstract fun launch()

abstract fun checkPermission(): Boolean
}

AbstractPermissionObserve inherits from lifecycleObserver, that’s why we can bind this permission class to any activity lifecycle.

Step 2:

We had created AbstractLifecycleObserver in step 1, so we will write main injectable permission class which is inherited by AbstractPermissionObserver.

@ActivityScoped
class CameraPermissionObserver @Inject constructor(
@ActivityContext private val appCompatContext: Context
) : AbstractPermissionObserver() {

private var requestPermission: ActivityResultLauncher<Array<String>>? = null

@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun onCreate() {
if (appCompatContext is AppCompatActivity) {
requestPermission = appCompatContext.registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
permissions.entries.forEach {
granted = it.value
if (!it.value) {
return@forEach
}
}
if (granted) {
permissionListener?.permissionGranted()
} else {
permissionListener?.permissionDenied()
}
}
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun onDestroy() {
requestPermission = null
}
override fun launch() {
requestPermission?.launch(arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE))
}

override fun checkPermission(): Boolean {
val cameraPermission = ContextCompat.checkSelfPermission(appCompatContext, Manifest.permission.CAMERA)
val writePermission = ContextCompat.checkSelfPermission(appCompatContext, Manifest.permission.WRITE_EXTERNAL_STORAGE)
val readPermission = ContextCompat.checkSelfPermission(appCompatContext, Manifest.permission.READ_EXTERNAL_STORAGE)
return cameraPermission == PackageManager.PERMISSION_GRANTED &&
writePermission == PackageManager.PERMISSION_GRANTED &&
readPermission == PackageManager.PERMISSION_GRANTED
}
}

Above, I am defining ActivityScoped for this class because I want it will bind to activity lifecycle.Another reason is ActivityContext. I need to reach activity instance thanks to ActivityContext qualifier that has been predefined in Hilt, we can do it easily. Also we have two main function inside class, in onCreate method we are registering ActivityResult and in onDestroy we are equals requestPermission object to null to avoid memory leak issue.

Step3:

launch: We are using this method to trigger request permission dialog from user.

override fun launch() {
requestPermission?.launch(arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE))
}

Step4:

The last thing in CameraPermissionObserver class is checkPermission method. Sometimes we might need to check all permission granted or denied, we can learn permissions’ status with using this method implementation.

override fun checkPermission(): Boolean {
val cameraPermission = ContextCompat.checkSelfPermission(appCompatContext, Manifest.permission.CAMERA)
val writePermission = ContextCompat.checkSelfPermission(appCompatContext, Manifest.permission.WRITE_EXTERNAL_STORAGE)
val readPermission = ContextCompat.checkSelfPermission(appCompatContext, Manifest.permission.READ_EXTERNAL_STORAGE)
return cameraPermission == PackageManager.PERMISSION_GRANTED &&
writePermission == PackageManager.PERMISSION_GRANTED &&
readPermission == PackageManager.PERMISSION_GRANTED
}

So far, we have explained what the permission classes and therir functions are, as well as what they do. So now, how do we use it in activity?
Just remember, we defined CameraPermissionObserver class as ActivityScoped because of that we should add this observer to Any Activity class. Like below I have a BaseActivity class and I am injecting observer.

open class BaseActivity : AppCompatActivity() {

@Inject
lateinit var cameraPermissionObserver: CameraPermissionObserver

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setTransparent()

lifecycle.addObserver(cameraPermissionObserver)
}
override fun onDestroy() {
super.onDestroy()
lifecycle.removeObserver(cameraPermissionObserver)
}
}

Eventually we can create a fragment to use our PermissionObserver.

@AndroidEntryPoint
class CameraPermissionSampleFragment : Fragment(R.layout.fragment_camera_permission_sample), PermissionListener {

@Inject
lateinit var cameraPermissionObserver: CameraPermissionObserver

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
cameraPermissionObserver.permissionListener = this

btn_camera_permission_request.setOnClickListener {
requestPermission()
}
}

override fun onDestroyView() {
super.onDestroyView()
cameraPermissionObserver.permissionListener = null
}

override fun permissionGranted() {
Toast.makeText(requireActivity(), "Permission Granted", Toast.LENGTH_SHORT).show()
}

override fun permissionDenied() {
Toast.makeText(requireActivity(), "Permission Denied", Toast.LENGTH_SHORT).show()
}

private fun requestPermission() {
if (cameraPermissionObserver.checkPermission()){
// Go
} else {
cameraPermissionObserver.launch()
}
}
}

Github sample project is here.

If you have any issue for codebase, please warn me from comments, as soon as possible I will fix.

Happy coding :)

--

--

Oguzhan Alpayli

Oktein Company, Software Engineer, Python Enthusiast