Joshua George
Joshua George

Reputation: 38

Data binding behaving unexpected between fragments and activity

So I'm trying to figure out why I can't override a data bound property mainActivity.toolbarViewConfig.title.value = "help me please". The property seems to be set only once and this will either work in my activity or in Fragment A. If I try to give the property a value in Fragment B, that would not work. If I try to override the property by setting a click-listener for a button in the activity, that would not work. So obviously there seems to be something strange going on with the binding. All kind of suggestions would be appreciated. I have been sitting scratching my head 4 days in a row. Please help me not become bald.

Activity:

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


    val binding = ActivityMainBinding.inflate(layoutInflater)
    binding.toolbarViewConfig = toolbarViewConfig
    setContentView(binding.root)


    window.setFlags(
        WindowManager.LayoutParams.FLAG_FULLSCREEN,
        WindowManager.LayoutParams.FLAG_FULLSCREEN)

    val navController = findNavController(R.id.nav_host_fragment)
    val appBarConfiguration = AppBarConfiguration(navController.graph)
    findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbar).setupWithNavController(navController,appBarConfiguration)}

Fragment A:

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {

    val mainActivity = activity!! as MainActivity
    mainActivity.toolbarViewConfig.title.value = "This works!" //Works fine. 

    return inflater.inflate(R.layout.fragment_home, container, false)
}

Fragment B:

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?
{
    val viewModel = ViewModelProvider(this).get(GoOnlineViewModel::class.java)

    val binding = DataBindingUtil.inflate<FragmentSellerGoOnlineBinding>(
        inflater, R.layout.fragment_seller_go_online,
        container, false
    ).apply {
        this.lifecycleOwner = viewLifecycleOwner
        this.viewModel = viewModel}

    val mainActivity = activity!! as MainActivity
    mainActivity.toolbarViewConfig.title.value = "This does not work" //When I navigate from Fragment A to B this will not be set

    viewModel.navigationCommand.observe(viewLifecycleOwner, Observer {
        when(it) {
            is NavigationCommand.To ->
                Navigation.findNavController(requireView()).navigate(it.directions)
        }
    })


    return binding.root
}

ToolbarViewConfig:

class ToolbarViewConfig(
var title: MutableLiveData<String> = MutableLiveData(""))

activity_main.xml:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">

<data>
    <import type="android.view.View"/>

    <variable
        name="toolbarViewConfig"
        type="my.app.willow.models.ToolbarViewConfig" />
</data>

<androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:background="@color/white"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{toolbarViewConfig.title}"
            android:layout_gravity="center"
            android:id="@+id/toolbar_title"/>

    </androidx.appcompat.widget.Toolbar>

    <fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/toolbar"
        app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>

Upvotes: 1

Views: 567

Answers (1)

Maciej Ciemięga
Maciej Ciemięga

Reputation: 10715

You forgot to assign a lifecycleOwner in your ActivityMainBinding. Without it, your Activity will never listen for changes and will just read the current value once.

I believe that FragmentA creates it's view and sets the title during ActivityMainBinding.inflate(layoutInflater). So in the next line when you set up toolbarViewConfig in your ActivityMainBinding, it can already read the initial value of the title LiveData (set by FragmentA), but will never react to any later changes done in FragmentB.

Upvotes: 1

Related Questions