我有一个应用程序,它有一个主要活动和 3 个片段。让我们将它们命名为 A、B 和 C,如下所示:
片段 A 有一个 RecyclerView。当我单击 RecyclerView 中的项目时,它会将安全参数中的 Account 对象传递给显示数据的 Fragment B。
在 Fragment B 中,用户可以按下编辑按钮来编辑 Account 对象,然后将他/她导航到 Fragment C。
在 Fragment C 中,用户既可以按返回键取消修改并返回 Fragment B,也可以修改并按保存返回 Fragment A。
这里的问题是,如果在按下编辑按钮后,用户进行了一些修改,然后按下后退按钮而不保存,它仍然会临时修改对象(暂时因为如果我关闭应用程序然后再次打开它,对象会重置恢复到原来的状态。)。
下面是我的代码(这是一个简单的代码,只是为了重现问题):
片段 A.kt
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/Layout_Fragment_Account"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/RecyclerView_Account"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="@{ViewModel.loadingStatus==List.LIST ? View.VISIBLE : View.GONE}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="gone" />
...
</androidx.constraintlayout.widget.ConstraintLayout>
片段 A.kt
private fun subscribeAccounts(accounts: List<Account>) {
val adapter = AccountAdapter(
/* The click listener to handle account on clicks */
AccountClickListener {
navigateTo(AccountFragmentDirections.actionFragmentAccountToFragmentViewAccount(it))
},
/* The click listener to handle popup menu for each accounts */
AccountOptionsClickListener { view, Account ->
//View Popup
}
)
binding.RecyclerViewAccount.apply {
/*
* State that layout size will not change for better performance
*/
setHasFixedSize(true)
/* Bind the layout manager */
layoutManager = LinearLayoutManager(requireContext())
/* Bind the adapter */
this.adapter = adapter
}
/* Submits the list for displaying */
adapter.submitList(accounts)
}
片段 B.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>
<variable
name="Account"
type="...Account" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/Layout_Credential_View"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/Account_Logo"
errorResource="@{@drawable/ic_account_placeholder}"
imageUrl="@{Account.logoUrl}"
loadingResource="@{@drawable/ic_image_loading}"
android:layout_width="100dp"
android:layout_height="100dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_account_placeholder" />
<TextView
android:id="@+id/Account_Name"
style="@style/Locky.Text.Title5.Name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="32dp"
android:text="@{Account.entryName}"
android:textAlignment="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/Account_Logo"
tools:text="This can be a very very very long title toooooo" />
...
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
片段 B.kt
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
/* Binds the UI */
_binding = FragmentViewAccountBinding.inflate(inflater, container, false)
/* Instantiate the view model */
_viewModel = ViewModelProvider(this).get(ViewAccountViewModel::class.java)
/* Bind lifecycle owner to this */
binding.lifecycleOwner = this
/*
* Fetch the account object from argument
* Then bind account object to layout
*/
val account = ViewAccountFragmentArgs.fromBundle(requireArguments()).accountToVIEW
binding.account = account
_account = account
/* Returns the root view */
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_credentials_actions, menu)
super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem) =
when (item.itemId) {
R.id.Action_Duplicate -> {
navigateTo(
ViewAccountFragmentDirections.actionFragmentViewAccountToFragmentAddAccount(
_account.apply {
this.id = 0
})
)
true
}
R.id.Action_Edit -> {
navigateTo(
ViewAccountFragmentDirections.actionFragmentViewAccountToFragmentAddAccount(
_account
)
)
true
}
else -> false
}
}
片段 C.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="...Constants" />
<variable
name="ViewModel"
type="...AddAccountViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingBottom="16dp">
...
<!--
**************** Require Text Fields ****************
-->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/Account_Name"
style="@style/Locky.TextBox.Default"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:hint="@string/field_account_name"
app:endIconMode="clear_text"
app:helperText="@string/label_required"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/Barrier_Logo"
app:startIconDrawable="@drawable/ic_profile">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textCapWords"
android:text="@={ViewModel.entryName}" />
</com.google.android.material.textfield.TextInputLayout>
...
</LinearLayout>
</layout>
片段 C.kt
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentAddAccountBinding.inflate(inflater, container, false)
/* Binds the UI */
_binding = FragmentAddAccountBinding.inflate(inflater, container, false)
/* Instantiate the view model */
_viewModel = ViewModelProvider(this).get(AddAccountViewModel::class.java)
/* Bind view model to layout */
binding.viewModel = viewModel
/* Bind lifecycle owner to this */
binding.lifecycleOwner = this
/*
* Fetch the account object from argument
* And set it to view model for two way binding
*/
val account = AddAccountFragmentArgs.fromBundle(requireArguments()).accountToADD
viewModel.setAccount(account)
/* Returns the root view */
return binding.root
}
片段 C 视图模型
class AddAccountViewModel(application: Application) : ObservableViewModel(application) {
/**
* Bindable two-way binding
**/
private lateinit var _account: Account
var entryName: String
@Bindable get() {
return _account.entryName
}
set(value) {
_account.entryName = value
notifyPropertyChanged(BR.entryName)
}
var logoUrl: String?
@Bindable get() {
return _account.logoUrl
}
set(value) {
_account.logoUrl = value ?: ""
notifyPropertyChanged(BR.logoUrl)
}
internal fun setAccount(account: Account?) {
this._account = account ?: Account()
}
}
导航.xml
<fragment
android:id="@+id/Fragment_A"
android:name="...AccountFragment"
android:label="Accounts"
tools:layout="@layout/fragment_account">
<action
android:id="@+id/action_Fragment_Account_to_BottomSheet_Fragment_Account_Filter"
app:destination="@id/BottomSheet_Fragment_Account_Filter" />
<action
android:id="@+id/action_Fragment_Account_to_Fragment_View_Account"
app:destination="@id/Fragment_View_Account" />
</fragment>
<fragment
android:id="@+id/Fragment_B"
android:name="...ViewAccountFragment"
android:label="View Account"
tools:layout="@layout/fragment_view_account">
<action
android:id="@+id/action_Fragment_View_Account_to_Fragment_Add_Account"
app:destination="@id/Fragment_Add_Account" />
<argument
android:name="ACCOUNT_toVIEW"
app:argType="....Account" />
</fragment>
<fragment
android:id="@+id/Fragment_C"
android:name="...AddAccountFragment"
android:label="Add Account"
tools:layout="@layout/fragment_add_account">
<action
android:id="@+id/action_Fragment_Add_Account_to_BottomSheet_Fragment_Account_Logo"
app:destination="@id/BottomSheet_Fragment_Account_Logo" />
<argument
android:name="ACCOUNT_ToADD"
app:argType="...Account" />
</fragment>
下面是该问题的演示:
我尝试了一种快速破解方法,我保存了一个未修改的帐户对象的实例,在用户离开片段之前,我通过分配每个变量来重置更改,但这并不高效。我认为我在这里使用安全参数做错了什么?
有人可以帮我吗。我实在想不通这个。谢谢