在 Fragment Recreation 上恢复适配器
Restoring an Adapter on Fragment Recreation
我 运行 正在崩溃,如果 android OS 终止了一个进程,当应用程序试图从已保存的实例,我的 recyclerview 的适配器始终为空。
这是我的层次结构:
Parent Activity // destroyed when process is killed
Nested View Pager Fragment // view pager containing four recycler view fragments
Recycler Frag 1
Recycler Frag 2
Recycler Frag 3
Recycler Frag 4
这些回收器片段中的每一个都是完全相同的片段,除了当父 activity 创建它们的新实例时,我调用一个公开的 setter 方法来设置类型为 RecyclerView.Adapter(原因是这些碎片中的每一个都可能是一个分页回收器,但它显示的内容以及用户与之交互的方式可能会有所不同)示例代码来自父 activity:
RecyclerFrag feedFrag = RecyclerFrag.newInstance();
feedFrag.setAdapter(new myCustomAdapter());
现在,我的最终用户 运行 如果他们有这个 activity 后台,并且 OS 决定终止这个 activity 继续存在,它无法正常恢复自身。据我所见,还原时一切都在那里,除了适配器为空。然后代码尝试访问适配器接口并因 NPE 而崩溃。
我不明白为什么会这样。我也在努力全神贯注于恢复此类事件中的活动和片段。我已经阅读了一堆 posts 和关于状态恢复的文档,但仍然找不到解决方案。这是我尝试过的解决方案示例,也许有人可以指出我逻辑中的缺陷/差距。
将回收器碎片存储在 fragmentManager 中,并尝试在 onActivityCreated 方法调用中读取它。
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
getFragmentManager().putFragment(outState, "myFrag", this);
...
}
然后:
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if(savedInstanceState != null) {
getFragmentManager().getFragment(savedInstanceState, "myFrag");
...
}
}
对我来说,这感觉就像我错过了标记。片段获取对自身的引用然后尝试从中设置自身是没有意义的。更糟糕的是,片段 it returns 有一个空适配器。生活和学习。
接下来我尝试保存我在父 activity 中为 viewPager 实现创建的片段,然后尝试在父 onCreate 中恢复这些片段。父级 class 如下所示:
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getSupportFragmentManager().putFragment(outState, "frag1", frag1);
...
}
然后:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState != null) {
getSupportFragmentManager.getFragment(savedInstanceState, "myFrag);
...
}
}
关于此方法的有趣之处在于,当我在 onSaveInstance
方法中将片段保存到管理器时,我的 adpater 不为 null,这是有道理的。当我在 onCreate 方法中获取它时,该片段适配器现在为空。
这让我最后想到,也许恢复适配器效率不高,不应该这样做。再说一次,在 Recycler Fragment 中创建适配器对我来说没有意义,因为我希望此片段采用 RecyclerView.Adapter
类型的任何适配器实现。对于进一步的上下文,viewPager 实现的类型为 FragmentStatePagerAdapter
,它提供了最基本的方法来覆盖将其获取到 运行。据我了解,这正是您应该做的,父 FragmentStatePagerAdapter
将为您处理其余的恢复过程。我这个假设错了吗?
对于此事的任何意见,我将不胜感激。我尽力提供了尽可能多的信息,但是,如果您觉得在提供更多信息的情况下可以帮助我,我很乐意更新我的 post,只要您告诉我。谢谢!
最终编辑:
我最终采用了与标记为此 post 答案的解决方案类似的解决方案。我将在下面提供我的实际解决方案,以便将来如果有人发现此 post 对他们的情况有帮助。
- 删除 Recycler Fragments 界面中的 public setter 方法。鉴于我总是在初始化片段后立即调用 setter,这种方法有问题是有道理的,并且当未来的开发人员必须在代码中工作时容易出错。
- 创建枚举类型作为回收器中对象的数据抽象。鉴于某些隐含类型的数据需要不同的适配器,这似乎也是合适的。我的意思是我可能有一个汽车对象,但取决于我在用户旅程中所处的位置,该汽车对象可能需要一个不同的适配器,用
CAR_PREVIEW_SEARCH
或 CAR_PREVIEW_SELECTABLE
等枚举反映出来onCreateView
期间
如果不查看更多代码库,我无法自信地解决您的实际问题,但是下面这行有点令人担忧;
Each one of these recycler fragments is the exact same fragment
except, when the parent activity creates a new instance of them, I
call an exposed setter method that sets an adapter of type
RecyclerView.Adapter
我可以建议另一种设置类型的方法吗?
在您的 FragmentStatePagerAdapter
中创建各种片段类型的枚举;
public enum Page {
PAGE_ONE,
PAGE_TWO,
PAGE_THREE
}
那么在您的 getItem(int position)
实施中您将拥有;
@Override
public Fragment getItem(int position) {
CustomFragment fragment = CustomFragment();
Bundle bundle = new Bundle();
bundle.putInt(CustomFragment.INDEX, position); // You could swap this to whatever serialised information you need
fragment.setArguments(bundle);
return fragment;
}
在 CustomFragment 的 onCreateView
实现中,您可以像这样访问这个包;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.custom_fragment, container, false);
RecyclerView.Adapter adapter;
if(getArguments() != null) {
switch (FragmentStatePagerAdapter.Page.values()[getArguments().getInt(CustomFragment.INDEX)]) {
// Assign whatever adapter/values ect in here
}
} else {
// setup various default states here
adapter = SomeDefaultCustomFragmentAdapter()
}
// set adapters etc
return view;
}
以上内容确保您仅在确定拥有视图时才操作适配器。当系统重新创建片段时,一切都应该正常工作。
希望这至少能有所帮助。
我 运行 正在崩溃,如果 android OS 终止了一个进程,当应用程序试图从已保存的实例,我的 recyclerview 的适配器始终为空。
这是我的层次结构:
Parent Activity // destroyed when process is killed
Nested View Pager Fragment // view pager containing four recycler view fragments
Recycler Frag 1
Recycler Frag 2
Recycler Frag 3
Recycler Frag 4
这些回收器片段中的每一个都是完全相同的片段,除了当父 activity 创建它们的新实例时,我调用一个公开的 setter 方法来设置类型为 RecyclerView.Adapter(原因是这些碎片中的每一个都可能是一个分页回收器,但它显示的内容以及用户与之交互的方式可能会有所不同)示例代码来自父 activity:
RecyclerFrag feedFrag = RecyclerFrag.newInstance();
feedFrag.setAdapter(new myCustomAdapter());
现在,我的最终用户 运行 如果他们有这个 activity 后台,并且 OS 决定终止这个 activity 继续存在,它无法正常恢复自身。据我所见,还原时一切都在那里,除了适配器为空。然后代码尝试访问适配器接口并因 NPE 而崩溃。
我不明白为什么会这样。我也在努力全神贯注于恢复此类事件中的活动和片段。我已经阅读了一堆 posts 和关于状态恢复的文档,但仍然找不到解决方案。这是我尝试过的解决方案示例,也许有人可以指出我逻辑中的缺陷/差距。
将回收器碎片存储在 fragmentManager 中,并尝试在 onActivityCreated 方法调用中读取它。
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
getFragmentManager().putFragment(outState, "myFrag", this);
...
}
然后:
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if(savedInstanceState != null) {
getFragmentManager().getFragment(savedInstanceState, "myFrag");
...
}
}
对我来说,这感觉就像我错过了标记。片段获取对自身的引用然后尝试从中设置自身是没有意义的。更糟糕的是,片段 it returns 有一个空适配器。生活和学习。
接下来我尝试保存我在父 activity 中为 viewPager 实现创建的片段,然后尝试在父 onCreate 中恢复这些片段。父级 class 如下所示:
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getSupportFragmentManager().putFragment(outState, "frag1", frag1);
...
}
然后:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState != null) {
getSupportFragmentManager.getFragment(savedInstanceState, "myFrag);
...
}
}
关于此方法的有趣之处在于,当我在 onSaveInstance
方法中将片段保存到管理器时,我的 adpater 不为 null,这是有道理的。当我在 onCreate 方法中获取它时,该片段适配器现在为空。
这让我最后想到,也许恢复适配器效率不高,不应该这样做。再说一次,在 Recycler Fragment 中创建适配器对我来说没有意义,因为我希望此片段采用 RecyclerView.Adapter
类型的任何适配器实现。对于进一步的上下文,viewPager 实现的类型为 FragmentStatePagerAdapter
,它提供了最基本的方法来覆盖将其获取到 运行。据我了解,这正是您应该做的,父 FragmentStatePagerAdapter
将为您处理其余的恢复过程。我这个假设错了吗?
对于此事的任何意见,我将不胜感激。我尽力提供了尽可能多的信息,但是,如果您觉得在提供更多信息的情况下可以帮助我,我很乐意更新我的 post,只要您告诉我。谢谢!
最终编辑: 我最终采用了与标记为此 post 答案的解决方案类似的解决方案。我将在下面提供我的实际解决方案,以便将来如果有人发现此 post 对他们的情况有帮助。
- 删除 Recycler Fragments 界面中的 public setter 方法。鉴于我总是在初始化片段后立即调用 setter,这种方法有问题是有道理的,并且当未来的开发人员必须在代码中工作时容易出错。
- 创建枚举类型作为回收器中对象的数据抽象。鉴于某些隐含类型的数据需要不同的适配器,这似乎也是合适的。我的意思是我可能有一个汽车对象,但取决于我在用户旅程中所处的位置,该汽车对象可能需要一个不同的适配器,用
CAR_PREVIEW_SEARCH
或CAR_PREVIEW_SELECTABLE
等枚举反映出来onCreateView
期间
如果不查看更多代码库,我无法自信地解决您的实际问题,但是下面这行有点令人担忧;
Each one of these recycler fragments is the exact same fragment except, when the parent activity creates a new instance of them, I call an exposed setter method that sets an adapter of type RecyclerView.Adapter
我可以建议另一种设置类型的方法吗?
在您的 FragmentStatePagerAdapter
中创建各种片段类型的枚举;
public enum Page {
PAGE_ONE,
PAGE_TWO,
PAGE_THREE
}
那么在您的 getItem(int position)
实施中您将拥有;
@Override
public Fragment getItem(int position) {
CustomFragment fragment = CustomFragment();
Bundle bundle = new Bundle();
bundle.putInt(CustomFragment.INDEX, position); // You could swap this to whatever serialised information you need
fragment.setArguments(bundle);
return fragment;
}
在 CustomFragment 的 onCreateView
实现中,您可以像这样访问这个包;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.custom_fragment, container, false);
RecyclerView.Adapter adapter;
if(getArguments() != null) {
switch (FragmentStatePagerAdapter.Page.values()[getArguments().getInt(CustomFragment.INDEX)]) {
// Assign whatever adapter/values ect in here
}
} else {
// setup various default states here
adapter = SomeDefaultCustomFragmentAdapter()
}
// set adapters etc
return view;
}
以上内容确保您仅在确定拥有视图时才操作适配器。当系统重新创建片段时,一切都应该正常工作。
希望这至少能有所帮助。