Git Product home page Git Product logo

android-viewbinding's Introduction

Android ViewBinding Kotlin

Android ViewBinding Library

Version Downloads

A simple library to simplify viewbinding delegation in your Android Application

Adding dependencies

Add this to your build.gradle:

allprojects {
	repositories {
		...
		maven { url 'https://jitpack.io' }
	}
}

enable viewbinding in your app/build.gradle:

android {
    ....
    buildFeatures {
        viewBinding true
    }
}

Add the dependencies in your app/build.gradle:

dependencies {
    ....
    implementation 'com.github.yogacp:android-viewbinding:x.x.x'
}

How to use the library

Create your regular XML layout. For example, create activity_sample.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">

    <TextView
        android:id="@+id/tvTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/app_name"
        android:layout_marginBottom="16dp"/>

    <Button
        android:id="@+id/btnSample"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/app_name"
        android:textStyle="bold"/>

        ....
</LinearLayout>

And use it in your Activity, just extend an binding variable that extend to your generated binding view and add by viewBinding() at the end:

class SampleActivity : AppCompatActivity() {

    private val binding: ActivitySampleBinding by viewBinding()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding.tvTitle.text = getString(R.string.sample_title)

        binding.btnSample.setOnClickListener {
            Toast.makeText(this, "Sample Button Clicked", Toast.LENGTH_SHORT).show()
        }
        ....
    }
}

And here if you want to use it in your Fragment. For example, you create a xml layout with name fragment_sample.xml:

class SampleFragment : Fragment(R.layout.fragment_sample) {

    private val binding: FragmentSampleBinding by viewBinding()

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

        binding.tvFragmentTitle.text = getString(R.string.sample_fragment_title)
        binding.btnFragmentSample.setOnClickListener {
            Toast.makeText(context, "Sample Fragment Button Clicked", Toast.LENGTH_SHORT).show()
        }

        ....
    }
}

And here if you want to use it in your BottomSheetDialogFragment. For example, you create a xml layout with name bottomsheet_sample.xml:

class SampleBottomSheetDialogFragment : BottomSheetDialogFragment() {

    private val binding: BottomsheetSampleBinding by viewBinding()

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        return binding.root //return root from binding delegation
    }

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

        binding.tvFragmentTitle.text = getString(R.string.sample_fragment_title)
        binding.btnClose.setOnClickListener {
            Toast.makeText(context, "Sample BottomSheetDialog Button Clicked", Toast.LENGTH_SHORT).show()
        }

        ....
    }
}

And here if you want to use it in your DialogFragment. For example, you create a xml layout with name dialog_sample.xml:

class SampleDialogFragment : DialogFragment() {

    private val binding: DialogSampleBinding by viewBinding()

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        return binding.root //return root from binding delegation
    }

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

        binding.tvTitle.text = getString(R.string.sample_fragment_title)
        binding.btnClose.setOnClickListener {
            Toast.makeText(context, "Sample Dialog Button Clicked", Toast.LENGTH_SHORT).show()
        }

        ....
    }
}

If you using proguard, add this line to your proguard-rules.pro.

#ViewBinding
-keep class * implements androidx.viewbinding.ViewBinding {
    public static *** bind(android.view.View);
    public static *** inflate(android.view.LayoutInflater);
}
Happy coding :)

android-viewbinding's People

Contributors

wiryadev avatar yogacp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

android-viewbinding's Issues

viewBinding Activity delegate - App Crash

This is my simple activity:

class MainActivity : AppCompatActivity() {

    private val binding by viewBinding<ActivityMainBinding>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        binding.button.text = "Some Text"
    }

}

And I always get an error when launch the app:

2021-03-29 09:21:23.487 15441-15441/? E/example.testap: Unknown bits set in runtime_flags: 0x8000
2021-03-29 09:21:23.996 15441-15441/com.example.testapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.testapp, PID: 15441
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.testapp/com.example.testapp.MainActivity}: java.lang.reflect.InvocationTargetException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at android.viewbinding.library.activity.ActivityViewBindingDelegate.getValue(ActivityBinding.kt:38)
at com.example.testapp.MainActivity.getBinding(Unknown Source:10)
at com.example.testapp.MainActivity.onCreate(MainActivity.kt:16)
at android.app.Activity.performCreate(Activity.java:7802)
at android.app.Activity.performCreate(Activity.java:7791)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409) 
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) 
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016) 
at android.os.Handler.dispatchMessage(Handler.java:107) 
at android.os.Looper.loop(Looper.java:214) 
at android.app.ActivityThread.main(ActivityThread.java:7356) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 
Caused by: android.view.InflateException: Binary XML file line #9 in com.example.testapp:layout/activity_main: Binary XML file line #9 in com.example.testapp:layout/activity_main: Error inflating class fragment
Caused by: android.view.InflateException: Binary XML file line #9 in com.example.testapp:layout/activity_main: Error inflating class fragment
Caused by: java.lang.IllegalArgumentException: Binary XML file line #9: Duplicate id 0x7f0a010f, tag null, or parent id 0xffffffff with another fragment for androidx.navigation.fragment.NavHostFragment
at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:116)
at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:135)
at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:356)
at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:335)
at android.view.LayoutInflater.tryCreateView(LayoutInflater.java:1069)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:997)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:961)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:1123)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084)
at android.view.LayoutInflater.inflate(LayoutInflater.java:682)
at android.view.LayoutInflater.inflate(LayoutInflater.java:534)
at com.example.testapp.databinding.ActivityMainBinding.inflate(ActivityMainBinding.java:43)
at com.example.testapp.databinding.ActivityMainBinding.inflate(ActivityMainBinding.java:37)
at java.lang.reflect.Method.invoke(Native Method)
at android.viewbinding.library.activity.ActivityViewBindingDelegate.getValue(ActivityBinding.kt:38)
at com.example.testapp.MainActivity.getBinding(Unknown Source:10)
at com.example.testapp.MainActivity.onCreate(MainActivity.kt:16)
at android.app.Activity.performCreate(Activity.java:7802)
at android.app.Activity.performCreate(Activity.java:7791)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
2021-03-29 09:21:23.997 15441-15441/com.example.testapp E/AndroidRuntime: at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

not return a View from onCreateView() or this was called before onCreateView().

I got these error

java.lang.IllegalStateException: Fragment ChooseLiftDialogFragment{fb1047b} (00f4882f-62df-43e0-8e64-d4926820a8b3 tag=ChooseLiftDialogFragment) did not return a View from onCreateView() or this was called before onCreateView().
at androidx.fragment.app.Fragment.requireView(Fragment.java:1964)
at android.viewbinding.library.fragment.FragmentViewBindingDelegate.getValue(FragmentBinding.kt:77)
at com.ivandlrapp.virtualenconder.ui.main.ChooseLiftDialogFragment.getBinding(ChooseLiftDialogFragment.kt:17)
at com.ivandlrapp.virtualenconder.ui.main.ChooseLiftDialogFragment.onCreateView(ChooseLiftDialogFragment.kt:24)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2963)
at androidx.fragment.app.DialogFragment.performCreateView(DialogFragment.java:489)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:518)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:524)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6810)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)

I dont know where I call binding before onCreateView and I return binding.root there

`class ChooseLiftDialogFragment : DialogFragment() {

private val binding: FragmentChooseLiftDialogBinding by viewBinding()

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

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setStyle(STYLE_NORMAL, R.style.DialogStyle)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    val squat = view.context.resources.getString(R.string.squat)
    val deadlidt = view.context.resources.getString(R.string.deadlift)

    binding.squatItem.setOnClickListener {
        ChooseModeDialogFragment().show(parentFragmentManager, "ChoseModeDialogFragment")
        PreferenceUtils.saveString(view.context, R.string.exercise_pref_key, squat)
        this.dismiss()
    }

    binding.deadliftItem.setOnClickListener {
        ChooseModeDialogFragment().show(parentFragmentManager, "ChoseModeDialogFragment")
        PreferenceUtils.saveString(view.context, R.string.exercise_pref_key, deadlidt)
        this.dismiss()
    }
}

}`

Thanks

Fatal Exception: java.lang.IllegalStateException

Hi, on some devices when open BottomSheetDialogFragment app got crashed with this exception:

Fatal Exception: java.lang.IllegalStateException
Can't access the Fragment View's LifecycleOwner when getView() is null i.e., before onCreateView() or after onDestroyView()

Exception is pointing to viewbindig method:
DoWorkoutFragment.getFragmentBinding (DoWorkoutFragment.kt:50)
DoWorkoutFragment.access$getFragmentBinding (DoWorkoutFragment.kt:38)
DoWorkoutFragment$setupDoWorkoutScreen$1.invokeSuspend (DoWorkoutFragment.kt:79)
kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33)
kotlinx.coroutines.DispatchedTask.run (DispatchedTask.kt:106)

Which is inside of view binding delegate. What do I need to do to avoid this?

setContentView not called if binding doesn't invoked

Hi there!
I liked your library and appreciate that, but I have a problem :

I saw you put setContentView() function inside getValue() method of delegation function; So if we don't want to access any property of binding variable like binding.root, etc, then setContentView() never calls and we don't see anything in the view when we launch app.

So my question is: Why didn't you call setContentView in init block like this? Did you do this for a reason?
Cause in this case it's not necessary to use any of binding properties to make sure setContentView function calls.

init {
        @Suppress("UNCHECKED_CAST")
        lifecycle.addObserver(object : DefaultLifecycleObserver {
            override fun onCreate(owner: LifecycleOwner) {

                /**
                 * inflate View class
                 */
                val inflateMethod = bindingClass.getMethod("inflate", LayoutInflater::class.java)

                /**
                 * Bind layout
                 */
                val invokeLayout = inflateMethod.invoke(null, activity.layoutInflater) as T

                /**
                 * Set the content view
                 */
                activity.setContentView(invokeLayout.root)

                binding = invokeLayout
            }
        })
    }

Thanks in advance.

Bug using `com.google.android.gms.maps.MapView`

This works except in that case that the view requires a method to be called in onDestroyView. The delegate nullifies the binding in onDestroy which is before onDestroyView.

For example com.google.android.gms.maps.MapView requires that calling fragments and activities forward the call to onDestroyView to the view itself. Doing this as described in the documentation here results in a crash on the bindling line

override fun onDestroyView() {
    binding.map.onDestroy()
    super.onDestroyView()
}

With the message:
Cannot access view bindings. View lifecycle is DESTROYED!

This is what is expected when looking at the code but the binding should be available until after onDestroyView, not onDestroy which is what the current implementation does.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.