Home > Software engineering >  Android checkbox disabled but says enabled
Android checkbox disabled but says enabled

Time:09-30

I didn't want to create a question for this, but I can't figure out what's happening.

I have a checkbox where the enabled state is bound to a variable, checkboxEnabled in a ViewModel. This variable is set to true, but the checkbox is somehow disabled.

Debugging steps:

  • When I get the enabled state of the checkbox view from my fragment in OnResume, it also says true, even though the checkbox is clearly disabled.
  • When I get the enabled state of the checkbox view in an onClickListener of another view, it does say false. However, the checkboxEnabled variable in my ViewModel is still true here.
  • If I enable the checkbox in onViewCreated, it is still disabled.
  • I've tried working with different bindings between the xml and MyViewModel, none of which seem to work, so it might be an issue with the databinding.

Why is my checkbox disabled if I don't set checkboxEnabled to false anywhere in my code? Could it just be an issue linking the view model with the xml?

fragment_my.xml:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MyFragment">
    
    <data>
        <variable
            name="viewModel"
            type=".MyViewModel" />
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingStart="@dimen/activity_horizontal_margin"
        android:paddingEnd="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin" >

        <CheckBox
            android:id="@ id/checkbox"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:checked="@={viewModel.checkboxChecked}"
            android:enabled="@{viewModel.checkboxEnabled}"
            android:text="This is a checkbox" />

         <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Start"
            android:id="@ id/start_button"
            android:layout_below="@id/checkbox" />

    </RelativeLayout>
</layout>

MyFragment.kt:

class MyFragment() : Fragment() {

    private lateinit var viewModel: MyViewModel

    private var _binding: FragmentMyBinding? = null
    private val binding get() = _binding!!

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

        viewModel = ViewModelProvider(this).get(MyViewModel::class.java )
    }

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

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

        val checkbox = view.findViewById<CheckBox>(R.id.checkbox)
        checkbox.isEnabled = true // doesn't stay enabled

        startButton = view.findViewById(R.id.start_button)

        startButton.setOnClickListener {
            Log.d("Checkbox enabled", "${checkbox.isEnabled}") // logs `false`
            Log.d("ViewModel checkbox enabled", "${viewModel.checkboxEnabled}") // logs `true`
        }
    }

    override fun onResume() {
        super.onResume()
        val checkbox = activity?.findViewById<CheckBox>(R.id.checkbox)
        Log.d("Resumed", "${checkbox?.isEnabled}") // logs `true`
    }
}

And MyViewModel.kt:

class SensorGnssFragmentViewModel(application: Application) : AndroidViewModel(application) {

    var checkboxChecked = false
    var checkboxEnabled = true

    ...
}

CodePudding user response:

I think you have forgotten to pass the viewModel object to the layout with data binding like that _binding.viewModel = viewModel

Also, I'm confused with using onCreate and onCreateView, you can unify them to guarantee that viewModel is initialized and passed to the layout. So, update the onCreateView to be like that..

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        viewModel = ViewModelProvider(this).get(MyViewModel::class.java )
        _binding = FragmentMyBinding.inflate(inflater, container, false)
        _binding.viewModel = viewModel 
        return binding.root
    }

Another trick can help.. Try to replace the Boolean variables in the viewModel with ObservableBoolean to be: val checkboxEnabled : ObservableBoolean = ObservableBoolean()

So, If you want to change check/enable the check box, just set and unset the observable object like that..

    override fun onResume() {
        super.onResume()
        viewModel.checkboxEnabled.set(true)
    }
  • Related