Has someone managed to create a base fragment for ...
# android
p
Has someone managed to create a base fragment for ViewBinding? I'd like to just specify the subclass type as a generic and have a typesafe way to store the binding in a property without having to call XYBinding.inflate(layoutInflater, parent, false) in each implementation. The only thing I come up with is use reflection to call the static inflate function but I'm not too happy with using reflection for that.
w
You can do that:
Copy code
val binding = DataBindingUtil.inflate<TBinding>(inflater, layoutId, container, false)
binding.setVariable(BR.model, model)
Where
layoutId
and
model
are abstract properties on the base fragment. All layouts need to have a binding variable named
model
and the types just need to match
I believe you shouldn’t even need
TBinding
generic parameter for this base fragment,
ViewDataBinding
should work as well
p
I'm talking about ViewBinding, not DataBinding
w
🤦 sorry. I haven’t tried that yet
j
Inheritance for this (and anything) is discouraged, but you can pass
TheBinding::inflate
to the supertype constructor whose type is parameterized on
T : ViewBinding
and whose constructor accepts
(LayoutInflater) -> T
p
Why is it discouraged? I have exactly one binding per controller (conductor), always need to create it in onCreateView and need to null it in onDestroyView. It's error prone to repeat that over and over again. @jw
j
Well because it doesn't compose
p
And what's the alternative?
j
Well nothing if you're using fragments or conductor. They force it on you. If you switch to something that doesn't require nulling the reference ever then "duplicating" a single line of code isn't a big deal
p
And what's your solution if your using none of these?
j
i usually just build my own bespoke one for whatever thing i'm working on
p
I think it would be helpful for the community if you wrote a blog post on what's your take on these kind of architectural questions and how you would design these kind of things
👌🏼 1
👍 11
i
Copy code
open class BaseFragment<T : ViewBinding>(val inflater: (LayoutInflater) -> T): Fragment() {
    lateinit var binding: T
    
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? = inflater(inflater).root
}
This is what I did
p
You should pass the parent
i
Oh, I was following Jake examples.
Copy code
open class BaseFragment<T : ViewBinding>(val inflater: (LayoutInflater, ViewGroup?, Boolean) -> T) :
    Fragment()
{
    lateinit var binding: T

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? = inflater(inflater, container, false).root
}
p
And you forgot to set the binding property
i
Copy code
open class BaseFragment<T : ViewBinding>(private val inflater: (LayoutInflater, ViewGroup?, Boolean) -> T) :
    Fragment()
{
    lateinit var binding: T private set

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = inflater(inflater, container, false)
        return binding.root
    }
}
Done