【发布时间】:2020-04-18 14:11:13
【问题描述】:
在我正在开发的 Android 应用程序中,我有一个列表片段,其中显示了 RecyclerView 的列表项。我们第一次打开片段时,它会从 url 检索列表,但它不会频繁更改以保持重新加载它,所以我想保留数据。据我所知,Android 的方法是使用 savedInstanceState 作为片段,如下所示:
class ItemListFragment() {
private var itemCards: RecyclerView? = null;
public val Items: ArrayList<Item> = ArrayList<Item>()
override fun onViewStateRestored(savedInstanceState: Bundle?) {
super.onViewStateRestored(savedInstanceState)
if ( Items.size == 0 && savedInstanceState != null && savedInstanceState.containsKey("items")) {
val arrayType = object: TypeToken<Array<Item>>() {}.type
val tempItems: Array<Item> = Gson().fromJson(savedInstanceState.getString("items"), arrayType)
Items.addAll(tempItems)
}
}
}
然后我像这样管理MainActivity 中的状态:
class MainActivity : AppCompatActivity() {
private lateinit var restoreBundle: HashMap<String, Bundle>
private var currentFragment = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
restoreBundle = HashMap<String, Bundle>()
setContentView(R.layout.activity_main)
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
// Handle navigation view item clicks here.
drawFragment(item.itemId)
}
private fun drawFragment(position:Int) {
val fragMan: FragmentManager = getSupportFragmentManager()
val fragmentName = getFragmentName(position)
val bundle:Bundle = restoreBundle.get(fragmentName) ?: Bundle()
var fragment: Fragment? = fragMan.getFragment(bundle, fragmentName)
if ( fragment == null ) {
fragment = ItemListFragment() as Fragment
}
val current = fragMan.findFragmentByTag(currentFragment)
if (current != null) {
val frag = getFragmentName(current.id)
val recover : Bundle = restoreBundle.get(frag) ?: Bundle()
current.onSaveInstanceState(recover)
restoreBundle.set(frag, recover);
}
if (fragmentSet) {
fragMan.beginTransaction()
.replace(R.id.main_content_fragment, fragment!!, fragmentName).commit()
} else {
fragMan.beginTransaction()
.add(R.id.main_content_fragment, fragment!!, fragmentName).commit()
}
currentFragment = fragmentName
}
}
这两个示例都已精简到我认为相关的部分,但代码可能不是我想要做的问题。基本上,当我切换片段几次并调用fragMan.getFragment(bundle, fragmentName) 时,bundle 包含正确的保存实例状态,但是当我进入ItemListFragment.onViewStateRestored 时(据我所知,这是下一个可以放置断点的地方) savedInstanceState 捆绑包为空。
为什么我传入的包与正在检索的包不同或将实例状态传递给我的片段的正确方法是什么?
【问题讨论】:
-
你应该使用viewmodel来保存数据而不是onrestoreinstncestate(),对数据有限制,在这种情况下,如果超过数据限制,它会抛出transactiontoolarge异常
-
@akashzincle 这只是我现在存放在片段包中的一些视图模型 - 有没有更好的方法在片段实例化时将其传递?
-
好吧,我建议的改变可能是一个更大的改变,你可以做的是,采用 Activity Level ViewModel,在这个 ViewModel 中,保留每个片段在第一次 API 调用时所需的数据,现在每当再次附加片段时,您不需要传递任何内容,只需从片段中的活动视图模型中提取数据,因为所有附加到活动的片段都可以直接访问其活动视图模型,我认为首先您应该阅读更多关于viewmodels ,最好从头开始。
-
@akashzincle 正如我所说,我使用的是视图模型,但理想情况下,我更愿意将仅与片段中的特定片段相关的数据保留在片段中 - 我想将其保留在活动中一切都是多余的,但碎片似乎没有办法维持自己的状态。如果我需要在其他地方处理它,那么服务可能是有意义的,但如果有用于管理它的内置系统,我不想构建那个脚手架。
标签: android android-fragments kotlin android-activity