7

I'm looking for a way to combine different features in an Android activity, that should be reusable for different activity classes. Specifically the problem arises from overriding open methods where the super's implementation also has to be called.

open class FirstActivity : FragmentActicity() {
  override fun onStart() {
    super.onStart()
    doSomething()
  }
}

That's simple enough, but it is not reusable. I could e.g. want to have the same behavior with a different base activity class:

open class SecondActivity : AppCompatActivity() {
  override fun onStart() {
    super.onStart()
    doSomething()
  }
}

where I'd have to duplicate the code. If I have a very basic functionality like tracking the state of the activity, I would want this in more or less all of my activities which do have different base classes. It get's even worse when I want to create some more features that can be combined:

open class ThirdActivity : FragmentActivity() {
  override fun onResume() {
    super.onResume()
    doSomeResuming()
  }
}

open Class FirstActivityAgain : ThirdActivity {
  override fun onStart() {
    super.onStart()
    doSomething()
  }
}

class MyFragmentActivity : FirstActivity() {
  override fun onStop() {
    doSomethingElse()
    super.onStop()
  }
}

class MyFragmentActivityWithResuming : FirstActivityAgain() {
  override fun onStop() {
    doSomethingElse()
    super.onStop()
  }
}

class MyTopBarActivity : SecondActivity() {
  override fun onStop() {
    doSomethingElse()
    super.onStop()
  }
}


In Scala I can use Traits to do this stackable modification, which allows for very flexible mixins of functionality. It's even possible to modify the same method over and over again, one just has to be careful with the linearization order. None of this is possible in Kotlin because a Scala Trait is neither equivalent to a Kotlin abstract class nor to a Kotlin Interface.

It doesn't seem to be possible with Kotlin's delegates either. I also thought about using generics, which in my limited imagination could look like this:

open class FirstActivity<BaseActivity : Activity> : BaseActivity() {
  ...
}

which of course is also not possible.

Is there anything I've overlooked? Can it be done by using Dagger?

ThePMO
  • 413
  • 4
  • 13

1 Answers1

0

What you are referring to in Kotlin called interfaces in conjunction with some basic delegation.

interface Base {
    fun printMessage()
    fun printMessageLine()
}

class BaseImpl(val x: Int) : Base {
    override fun printMessage() { print(x) }
    override fun printMessageLine() { println(x) }
}

class Derived(b: Base) : Base by b {
    override fun printMessage() { print("abc") }
}

fun main() {
    val b = BaseImpl(10)
    Derived(b).printMessage()
    Derived(b).printMessageLine()
}

Though it won't save you from the super problem since it Android framework issue rather than Kotlin Language.

For your case I would do something like

interface BaseActivityContainer{
 var activity: Activity
}

class MainActivity: BaseActivityContainer{

override var activity: Activity = this

}

interface BaseDoable: BaseActivityContainer{

fun doActivityStuff(){
 activity.getString(...)
}

}

interface BaseDoableSecond: BaseActivityContainer{

fun doActivityStuff(){
 activity.getDrawable(...)
}

}

class SomeActivity: MainActivity, BaseDoableSecond by this

Handle Lyfecycle events with the help of Android Lifecycle

This is not complete and barely functional but I hope it will clear some stuff for you.

Pavlo Ostasha
  • 14,527
  • 11
  • 35
  • Thank you for your answer, but it doesn't cover a method of "inserting" functionality into the Android Activity framework functions like onCreate etc. – ThePMO Jan 23 '20 at 08:36
  • Also, if I'm not mistaken, its not possible to use "this" in any way when delegating interface properties, since "this" doesn't exist at the moment of delegation yet! – ThePMO Jan 27 '20 at 15:19
  • Regarding this you are correct - as I wrote in the answer the code "is not complete and barely functional". Using composition instead of inheritance will make this possible. – Pavlo Ostasha Jan 28 '20 at 10:10