如何处理 ViewModel 中的配置更改

问题描述

我有简单的注册表单。当我输入数据并更改配置时,数据会丢失。我在我的项目中使用 viewmodel,官方文档说 viewmodel 可以自动处理方向变化,但它不会发生。我想如何使用 SaveState 存储数据或者我在 viewmodel 中犯了一个错误

my registration form

片段代码

class StartFragment : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?
    ): View? {
        val binding: StartFragmentBinding = DataBindingUtil.inflate(
            inflater,R.layout.start_fragment,container,false)
        val application = requireNotNull(this.activity).application

        val dataSource = UsersDatabase.getInstance(application).usersDatabaseDao
        val vm: SavedStateHandle by viewmodels()
        val viewmodelFactory = StartFragmentviewmodelFactory(dataSource,application)

        val startFragmentviewmodel =
            viewmodelProvider(
                this,viewmodelFactory).get(StartFragmentviewmodel::class.java)

        binding.startFragmentviewmodel = startFragmentviewmodel
        binding.lifecycleOwner = this

        binding.start.setonClickListener {
                findNavController().navigate(
                    StartFragmentDirections
                        .actionStartFragmentToWebViewFragment())
                startFragmentviewmodel.doneNavigation()
            }
        return binding.root
    }
}

视图模型

class StartFragmentviewmodel(
    val database: UsersDatabaseDao,application: Application
) : Androidviewmodel(application) {
    private var viewmodelJob = Job()

    override fun onCleared() {
        super.onCleared()
        viewmodelJob.cancel()
    }

    private val uiScope = Coroutinescope(dispatchers.Main + viewmodelJob)
    private var user1 = mutablelivedata<User?>()


    private val _navigatetoWebView = mutablelivedata<User>()
    val navigatetoWebView: LiveData<User>
        get() = _navigatetoWebView

    fun doneNavigation() {
        _navigatetoWebView.value = null
        uiScope.launch {
            val user = User()
            insert(user)
        }
    }

    private suspend fun insert(user: User) {
        withContext(dispatchers.IO) {
            database.insert(user)
        }
    }
}

视图模型工厂

class StartFragmentviewmodelFactory (
    private val dataSource: UsersDatabaseDao,private val application: Application
) : viewmodelProvider.Factory {
        @Suppress("unchecked_cast")
        override fun <T : viewmodel?> create(modelClass: Class<T>): T {
            if (modelClass.isAssignableFrom(StartFragmentviewmodel::class.java)) {
                return StartFragmentviewmodel(dataSource,application) as T
            }
            throw IllegalArgumentException("UnkNown viewmodel class")
        }
}

enter image description here

start_fragment.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="startFragmentviewmodel"
            type="com.example.leadsdoittest.StartFragmentviewmodel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout

        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/margin_start"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:orientation="vertical"
            app:layout_constraintGuide_begin="16dp" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/margin_end"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:orientation="vertical"
            app:layout_constraintGuide_end="16dp" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/margin_top"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:orientation="horizontal"
            app:layout_constraintGuide_percent="0.3" />

        <com.google.android.material.textfield.TextInputLayout
            android:id="@+id/input_name"
            style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            app:layout_constraintEnd_toEndOf="@id/margin_end"
            app:layout_constraintStart_toStartOf="@id/margin_start"
            app:layout_constraintTop_toTopOf="@id/margin_top">

            <com.google.android.material.textfield.TextInputEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/name" />
        </com.google.android.material.textfield.TextInputLayout>

        <com.google.android.material.textfield.TextInputLayout
            android:id="@+id/input_phone"
            style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            app:layout_constraintEnd_toEndOf="@id/margin_end"
            app:layout_constraintStart_toStartOf="@id/margin_start"
            app:layout_constraintTop_toBottomOf="@id/input_name">

            <com.google.android.material.textfield.TextInputEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:inputType="phone"
                android:hint="@string/phone_number" />
        </com.google.android.material.textfield.TextInputLayout>

        <com.google.android.material.textfield.TextInputLayout
            android:id="@+id/input_email"
            style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            app:layout_constraintEnd_toEndOf="@id/margin_end"
            app:layout_constraintStart_toStartOf="@id/margin_start"
            app:layout_constraintTop_toBottomOf="@id/input_phone">

            <com.google.android.material.textfield.TextInputEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/email" />
        </com.google.android.material.textfield.TextInputLayout>

        <com.google.android.material.button.MaterialButton
            android:id="@+id/start"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="50dp"
            android:text="@string/start"
            android:textColor="@android:color/white"
            app:layout_constraintEnd_toEndOf="@id/margin_end"
            app:layout_constraintStart_toStartOf="@id/margin_start"
            app:layout_constraintTop_toBottomOf="@+id/input_email" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

解决方法

视图状态由框架处理,因此您无需自己实现。但是,保存的状态取决于每个视图的唯一 ID,因此请尝试为每个 TextInputEditText 添加一个 ID。

,

使用实例变量在旋转后恢复数据。看:

   class StartFragment  : Fragment() {

    //private lateinit var homeViewModel: HomeViewModel
    var name = ""
    var email = ""
    var phone = ""
    override fun onCreateView(
        inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?
    ): View {
        val binding = FragmentHomeBinding.inflate(inflater)

        binding.etName.doOnTextChanged { text,start,before,count ->
            name = text.toString()
        }
        binding.etPhone.doOnTextChanged { text,count ->
            phone = text.toString()
        }
        binding.etEmail.doOnTextChanged { text,count ->
            email = text.toString()
        }
        binding.etName.setText(name)
        binding.etEmail.setText(email)
        binding.etPhone.setText(phone)
        return binding.root
    }
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...