To use viewbinding in an android app I am basically creating base classes for Activity & Fragment to remove boilerplate of everytime writing inflating code.

ACTIVITY:

BaseActivity with viewbinding:

abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = getViewBinding()
    }

    abstract fun getViewBinding(): VB

}

MainActivity:

class MainActivity : BaseActivity<ActivityMainBinding>() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        //we can directly use binding now and it works fine inside activity
        //binding.view.doSomething() 
    }

 override fun getViewBinding(): ActivityMainBinding = ActivityMainBinding.inflate(layoutInflater)
}

FRAGMENTS :

BaseFragment:

abstract class BaseFragment<VB : ViewBinding> : Fragment() {

    var binding: VB? = null

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding = getViewBinding(view)
    }

    abstract fun getViewBinding(view: View): VB
}

DemoFragment:

class DemoFragment : BaseFragment<DemoFragmentBinding>() {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        //problem is here
        binding.txtData.text="Something"
    }

    override fun getViewBinding(view: View): DemoFragmentBinding = DemoFragmentBinding.bind(view)

}

demo_fragment.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.fragments.DemoFragment">

    <TextView
        android:id="@+id/txt_data"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Hello" />

</FrameLayout>

Problem : Unable to access views using binding inside Demofragment. I don't know why it works with activity and not with fragment.

2nd way that I don't want todo:

implementation 'androidx.fragment:fragment-ktx:1.3.1'

class DemoFragment : Fragment(R.layout.demo_fragment) {

    lateinit var binding: DemoFragmentBinding

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding = DemoFragmentBinding.bind(view).apply {
            txtData.text = "Hello World"
        }
    }
}

You need to override onCreateView in BaseFragment and initialize the viewbinding

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

Then change this line

override fun getViewBinding(view: View): DemoFragmentBinding = DemoFragmentBinding.bind(view)

with

override fun getViewBinding() = DemoFragmentBinding.inflate(layoutInflater)

BaseFragment:

abstract class BaseFragment<VB : ViewBinding> : Fragment() {
    private var _binding: VB? = null
    val binding get() = _binding!!

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

    abstract fun getViewBinding(): VB
}

DemoFragment:

class DemoFragment : BaseFragment<DemoFragmentBinding>() {

    override fun getViewBinding() = DemoFragmentBinding.inflate(layoutInflater)

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

        binding.apply {
            txtData.text = "Something"
        }
    }
}

Here is another way to implement this factory abstraction with ViewBinding. I am sharing the implementation code below. I am using genrics here. If anyone needs further explanation, I am here for that. Make sure you have enabled viewbinding feature already into the build.gradle file. Then use the following BaseFragment.kt as your fragment abstraction.

BaseFragment:

typealias Inflate<T> = (LayoutInflater, ViewGroup?, Boolean) -> T

abstract class BaseFragment<V: ViewBinding>(
    private val inflate: Inflate<V>
    ) : Fragment() {

    private lateinit var _binding: V
    val binding get() = _binding

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

N:B: Know more about typealias.

HomeFragment:

// Implement the BaseFragment like below
class HomeFragment : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::inflate) {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // usages by calling public variable 'binding' from base class
        binding.message.text = "update $value"
    }
}