4

Is there any way to make an abstract class or interface for ViewBinding. Maybe I will show a simple example of what I exactly mean.

Let's say that I have two fragments. Both have TextView named universalTextView. In fragment classes I have value someText = "Text". I want to set this value to universalTextView. Now in both fragments, I have the same code so I made an abstract class, to reduce boilerplate code, that holds someText and set text for universalTextView. It looks like this:

abstract class AbstractFragment(
    @LayoutRes layout: Int
) : Fragment(layout)
{
    protected abstract val binding: ViewBinding
    protected val someText = "Text"

    override fun onViewCreated(view: View, savedInstanceState: Bundle?)
    {
        super.onViewCreated(view, savedInstanceState)
        binding.root.findViewById<TextView>(R.id.universalTextView).text = someText
    }
}

But with this approach, I am losing the biggest advantage of ViewBinding and I have to use findViewById. Is there any way to make an abstract class for ViewBinding, something like this:

abstract class AbstractViewBinding : ViewBinding
{
    abstract val universalTextView : TextView
}

So in AbstractFragment I can use protected abstract val binding: AbstractViewBinding and change text without using findViewById. But now, somehow I have to tell the app that ViewBinding used in every fragment that extends AbstractFragment will have universalTextView. Is this even possible?

Henry Twist
  • 5,666
  • 3
  • 19
  • 44
iknow
  • 8,358
  • 12
  • 41
  • 68
  • I'm interested in knowing exactly what the _boilerplate code_ is in this sentence: `so I made an abstract class, to reduce boilerplate code`. Because if you made an abstraction to set a value in a textView in two places, you now have two problems whereas before you only had two lines of code.... – Martin Marconcini Mar 29 '21 at 15:05
  • 1
    @MartinMarconcini This TextView is just the simplest example of what I want to achieve so everyone can easily understand this. If there were only these 2 TextViews in which value is statically set to `Text` I would have never asked this question :D – iknow Mar 29 '21 at 15:13
  • 1
    Ahh ok :) I was a bit worried. (You gotta forgive me, sometimes the questions I read *are* about that). – Martin Marconcini Mar 29 '21 at 15:17
  • 1
    In any case, I'm not sure you can do this this way. You're going to need a "layer" where you go from a Generic "T.setThisText" to "binding1.setThisText" and "binding2.setThisText" and at that point you are just introducing more complexity, but of course, there are valid reasons why you'd want to _abstract_ some of these things with similar layouts,. – Martin Marconcini Mar 29 '21 at 15:30
  • 1
    I just don't think you can do that with ViewBinding since it's kind of designed to be "type safe" and such, so... not with "generic" stuff in mind. – Martin Marconcini Mar 29 '21 at 15:33
  • 1
    Okay, thank You very much. I thought that it can be impossible to do in a way I want to do it. It is also not a thing that I have to do, and making it even with a `findViewById` is not very bad but I was just curious if there is any pattern of abstraction ViewBinding – iknow Mar 29 '21 at 15:51
  • No problem, good luck! :) – Martin Marconcini Mar 30 '21 at 09:14

1 Answers1

2

I don't think this is directly possible, there isn't any sort of inheritance mechanism in view binding. Instead you could have a structure like this:

abstract class AbstractFragment : Fragment {

    abstract val universalTextView: TextView
    protected val someText = "Text"

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

        super.onViewCreated(view, savedInstanceState)
        universalTextView.text = someText
    }
}
class Fragment1 : AbstractFragment {
  
    lateinit var binding: Fragment1Binding
    override val universalTextView
        get() = binding.utv
}

but I realise this isn't quite what you wanted.

Henry Twist
  • 5,666
  • 3
  • 19
  • 44
  • Thanks, this can help but also it can make a lot of boilerplate code in more complex examples. Because in every fragment I have to override the same fields in the same way – iknow Mar 29 '21 at 12:53
  • Yeah, when possible, avoid having "base fragments", instead prefer to _compose_ the behavior(s) you need into injectable components you can then call from your fragments (or have called automatically by lifecycle observers) – Martin Marconcini Mar 29 '21 at 15:34