【问题标题】:Why is the savedInstanceState Bundle I pass to my Android Fragment empty on arrival?为什么我传递给我的 Android Fragment 的 savedInstanceState Bundle 在到达时是空的?
【发布时间】: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


【解决方案1】:

我找不到满意的答案,所以我调整了我的架构,以便从它们自己的服务中加载模型并存储在它们自己的服务中,并作为我的 MainActivity 中的伴随对象的一部分进行访问,而不是尝试使用 Fragment 架构将数据传递到 Fragment。无论文档建议如何,尚不清楚后者是否可行。

【讨论】:

    猜你喜欢
    • 2017-03-13
    • 1970-01-01
    • 1970-01-01
    • 2014-11-12
    • 1970-01-01
    • 1970-01-01
    • 2012-06-04
    • 2012-10-22
    • 1970-01-01
    相关资源
    最近更新 更多