从活动导航到片段后,DataBinding行为中断

时间:2018-09-11 10:18:44

标签: android android-databinding android-architecture-components

最近,我正在使用Android Architecture Component和Data Binding库,并且遇到了一个非常奇怪的案例,在网络上搜索并尝试了几天后,我决定来这里寻求帮助。

我在一个活动中有一个片段,并且我对片段的绑定进行了setLifeCycleOwner(fragment),这使绑定的生命周期有了知觉。片段中有一个复选框和一个按钮,其中:
Checkbox的文本应根据检查状态进行更改
Button回调通过statrActivityForResult

启动活动B

我面临的问题是从活动B返回时,复选框显示的文本不再更新。
我已经检查了复选框的回调(onCheckedChanged),该回调工作正常,用于显示文本的模型也已更新。 以某种方式数据绑定未接收到字段更改事件,因此用户界面未更新。

有人有这个问题吗?还是我错过的任何检查?
如果我需要提供任何信息,请告诉我。非常感谢您的帮助!


以下是涉及此案的示例:

activity.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <FrameLayout
        android:id="@+id/main_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</layout>

fragment_test.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:bind="http://schemas.android.com/tools">

    <data>

        <variable
            name="viewModel"
            type="za.co.travelstart.flapp.activities.test.TestViewModel" />
    </data>

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <include
            layout="@layout/section_test"
            bind:viewModel="@{viewModel}" />
    </android.support.constraint.ConstraintLayout>
</layout>

section_test.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="viewModel"
            type="za.co.travelstart.flapp.activities.test.TestViewModel" />
    </data>

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <CheckBox
            android:id="@+id/checkBox"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onCheckedChanged="@{(compoundButton, isChecked) -> viewModel.onCheckBoxCheckedChanged(isChecked)}"
            android:text="@{viewModel.testModel.checkBoxText}"
            app:layout_constraintTop_toTopOf="parent" />

        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="@{(v) -> viewModel.onButtonClicked()}"
            android:text="Start Test B"
            app:layout_constraintTop_toBottomOf="@id/checkBox" />
    </android.support.constraint.ConstraintLayout>
</layout>

TestActivity.kt

class TestActivity : ParentActivity() {

    // View Model
    private lateinit var mViewModel: TestViewModel

    /* ------------------------------- Life Cycle */

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // init view model
        initViewModel()
        // init binding
        initBinding()
        // observe data
        observeData()
        // init fragment utils
        initFragmentUtils()
        // display fragment
        displayFragment()
    }

    override fun onActivityResult(requestCode: Int,
                                  resultCode: Int,
                                  data: Intent?) {
        when (requestCode) {
            1337 -> {
                // do nothing
            }
        }
    }

    /* ------------------------------- Methods */

    /**
     * Init view model
     */
    private fun initViewModel() {
        mViewModel = ViewModelProviders
                .of(this)
                .get(TestViewModel::class.java)
    }

    /**
     * Init binding
     */
    private fun initBinding() {
        DataBindingUtil.setContentView<ActivityTestBinding>(
                this, R.layout.activity_test).apply {
            setLifecycleOwner(this@TestActivity)
        }
    }

    /**
     * Observe the data in view model
     */
    private fun observeData() {
        mViewModel.buttonTriggerLiveData.observe(this, Observer {
            // navigate to test b
            navigateToTestB()
        })
    }

    /**
     * Display test fragment
     */
    private fun displayFragment() {
        fragmentUtils.displayTest()
    }

    /**
     * Navigate to test B
     */
    private fun navigateToTestB() {
        startActivityForResult(Intent(this, TestActivityB::class.java), 1337)
    }
}

TestFragment.kt

class TestFragment : Fragment() {

    // View Model
    private lateinit var mViewModel: TestViewModel

    // Binding
    private lateinit var mBinding: FragmentTestBinding

    /* ------------------------------ Instance Factory */

    companion object {

        /**
         * Instance factory
         */
        fun newInstance() = TestFragment()
    }

    /* ------------------------------ Life Cycle */

    override fun onCreateView(inflater: LayoutInflater,
                              container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        // init view model
        initViewModel()
        // init data binding
        initBinding(inflater, container)
        // return binding root view
        return mBinding.root
    }

    /* ------------------------------ Methods */

    /**
     * Init view model
     */
    private fun initViewModel() {
        activity?.also {
            mViewModel = ViewModelProviders
                    .of(it)
                    .get(TestViewModel::class.java)
        }
    }

    /**
     * Init binding
     */
    private fun initBinding(inflater: LayoutInflater,
                            container: ViewGroup?) {
        mBinding = DataBindingUtil.inflate(
                inflater, R.layout.fragment_test, container, false)
        mBinding.apply {
            viewModel = mViewModel
            setLifecycleOwner(this@TestFragment)
        }
    }
}

TestViewModel.kt

class TestViewModel : ViewModel() {

    // Data
    val testModel: MutableLiveData<TestModel> = MutableLiveData()

    // Button callback trigger
    val buttonTriggerLiveData: MutableLiveData<Boolean> = MutableLiveData()

    init {
        testModel.value = TestModel()
    }

    /**
     * Callback for checkbox
     */
    fun onCheckBoxCheckedChanged(isChecked: Boolean) {
        testModel.value?.checkBoxText = if (isChecked) "checked" else "unchecked"
    }

    /**
     * Callback for button
     */
    fun onButtonClicked() {
        buttonTriggerLiveData.value = true
    }
}

TestModel.kt

class TestModel : BaseObservable() {
    var checkBoxText = "unclicked"
        @Bindable get() = field
        set(value) {
            field = value
            notifyPropertyChanged(BR.checkBoxText)
        }
}

0 个答案:

没有答案