Ray Britton

Android Activity Launcher

I find the factory(ish) method approach to starting and creating Activities and Fragments is great at encapsulating the Activities/Fragments data within itself, in particular I feel it's necessary as external classes shouldn't need to be aware of how the Activity/Fragment is using data.

//This is the most simple implementation class SomeActivity : BaseActivity() { companion object { fun start(context: Activity) { context.startActivity(Intent(context, SomeActivity::class.java)) } } } //This is an example where values are passed in class SomeActivity : BaseActivity() { //we always put name.type as bundle keys so //it's clear what values could be valid when debugging private const val ARG_COUNT = "count.int" companion object { fun start(context: Activity, count: Int) { val intent = Intent(context, SomeActivity::class.java) intent.putExtra(ARG_COUNT, count) context.startActivity(intent) } } }


Recently working on a agile project where designs and behaviour where changing significantly every week I found this issue where I had to keep changing what would start activities (going from fragment to activity and vice versa) and had activities that were starting from activities and fragments. The issue here being that you need two different methods to start an Activity to support this, i.e.

class SomeActivity : BaseActivity() { companion object { fun start(context: Activity) { context.startActivity(Intent(context, SomeActivity::class.java)) } fun start(fragment: Fragment) { fragment.startActivity(Intent(fragment.requireContext(), SomeActivity::class.java)) } } }


In particular there was one activity with 5 methods for starting it when it could have been 3 and because Activity and Fragment almost have the same interface here, I created this:

interface Launcher { fun context(): Context fun launch(intent: Intent) fun launchForResult(intent: Intent, requestCode: Int) } class BaseActivity : AppCompatActivity(), Launcher { override fun context() = this override fun launch(intent: Intent) { startActivity(intent) } override fun launchForResult(intent: Intent, requestCode: Int) { startActivityForResult(intent, requestCode) } } class BaseFragment: Fragment(), Launcher { override fun context() = requireActivity() override fun launch(intent: Intent) { startActivity(intent) } override fun launchForResult(intent: Intent, requestCode: Int) { startActivityForResult(intent, requestCode) } }


Using this, the start methods can be replaced with

class SomeActivity : BaseActivity() { companion object { fun start(launcher: Launcher) { launcher.startActivity(Intent(launcher.context(), SomeActivity::class.java)) } } }


The launcher interface can also be implemented for Views but not in a nice, clean manner.