在片段寻呼机适配器中恢复片段
Restore Fragment within a Fragment Pager Adapter
我有一个 Fragment Pager Adapter
,有 5 个片段和一个 RecyclerView
,除了最后一个片段外,其他片段都一样,它有一个按钮来改变内容,当我按下这个按钮时,它会打开一个 Dialog Fragment
将替换 RecyclerView
的所有内容。
只有当我在 Dialog Fragment
打开时将应用程序发送到后台时,我的问题才会出现,当我恢复应用程序并提交更改时,应用程序崩溃显示 RecyclerView
为空。
恢复后如何恢复片段的完整状态。
通过记录生命周期,我可以看到在恢复后 OnCreate, OnCreateView & OnActivityCreated
是 运行,但是我的方法 setUpCustomPatternsRecyclerView
报告 RecyclerView
为空。
下面是我的片段的代码(非常简单)
重要提示:仅当我在我的 phone 中尝试时,应用程序才会崩溃,在 4 个不同的模拟器中,应用程序不会崩溃。
是不是我的phone中的UI没有完全画好?
如果是这样,我怎样才能收到它已完全绘制的通知?
片段:
public static FragmentCustomPatterns newInstance(ArrayList<PatternArrays> patternArrays, String fragmentTitle, int patternSelectedMode) {
FragmentCustomPatterns patterns = new FragmentCustomPatterns();
Bundle args = new Bundle();
args.putParcelableArrayList(CUSTOM_PATTERNS, patternArrays);
args.putInt(PATTERN_SELECTED_MODE, patternSelectedMode);
args.putString(TITLE, fragmentTitle);
patterns.setArguments(args);
return patterns;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
patternSelectedMode = getArguments().getInt(PATTERN_SELECTED_MODE);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
openCustomCoordinatesFragment = (OpenCustomCoordinatesFragment) getActivity();
View view = inflater.inflate(R.layout.fragment_custom_patterns, container, false);
FloatingActionButton floatingActionButton = view.findViewById(R.id.fab_custom_patterns);
floatingActionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openCustomCoordinatesFragment.openCoordinatesDialog();
}
});
recyclerFlag = false;
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
activityPatternSelector = (ActivityPatternSelector) getActivity();
setUpCustomPatternsRecyclerView();
}
public void setUpCustomPatternsRecyclerView() {
recyclerPatternsView = getView().findViewById(R.id.custom_pattern_recycler_view);
adapter = new PatternCoordinatesAdapter(getActivity(),activityPatternSelector.getCustomPatternArrays(), patternSelectedMode);
recyclerPatternsView.setAdapter(adapter);
Utilities utilities = new Utilities(getActivity(), R.layout.item_coordinates_pattern_cardview);
GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), utilities.calculateNoOfColumns());
recyclerPatternsView.setLayoutManager(gridLayoutManager);
recyclerPatternsView.setItemAnimator(new DefaultItemAnimator());
if (!recyclerFlag) {
recyclerPatternsView.addItemDecoration(new GridSpacing(utilities.calculateSpacing()));
recyclerFlag = true;
}
}
public interface OpenCustomCoordinatesFragment {
void openCoordinatesDialog();
}
LifeCycle 的模拟器(API22 和 API26)logcat 重新创建错误:
E/TESTING ACT: onPause:
D/TESTING FRAG: onPause:
E/TESTING ACT: onSaveInstanceState:
D/TESTING FRAG: onSaveInstanceState:
D/TESTING FRAG: onResume:
Phone Logcat(API25) logcat LifeCycle 重现错误:
E/TESTING ACT: onPause:
D/TESTING FRAG: onPause:
E/TESTING ACT: onSaveInstanceState:
D/TESTING FRAG: onSaveInstanceState:
E/TESTING ACT: onCreate:
D/TESTING FRAG: onCreate:
E/TESTING ACT: onCreate: Array Size 25
D/TESTING FRAG: onCreateView:
D/TESTING FRAG: onActivityCreated:
D/TESTING FRAG: onActivityCreated: Array Size 25
D/TESTING FRAG: onResume:
两者完全不同 我将按照 phone logcat 的方式在 OnSaveInstanceState
中创建一个 Bundle。请注意,在模拟器上 OnResume
在 OnSavedInstanceState
之后被调用,而在 phone 上在 OnActivityCreated
和 none 之后被调用。
谁能解释一下物理设备和模拟器之间的生命周期差异?
更新:
我找不到解决这个问题的办法。 运行 在 activity 中托管 FragmentPagerAdapter
也启动 DialogFragment
:
final FragmentCustomPatterns myTempFrag = (FragmentCustomPatterns) patternsPagerAdapter.getItem(4);
System.out.println("TESTING: Added " + myTempFrag.isAdded() + " Visible " + myTempFrag.isVisible() + " In Layout " + myTempFrag.isInLayout() + " Resumed " + myTempFrag.isResumed() + " Count " + patternsPagerAdapter.getCount());
正常情况下returns:
TESTING: 'Added' true 'Visible' true 'In Layout' false 'Resumed' true Count 5
在对话框片段打开的情况下将应用程序发送到后台,然后再次返回应用程序后,returns:
TESTING: 'Added' false 'Visible' false 'In Layout' false 'Resumed' false Count 5
我认为这就是我得到的原因:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.swapAdapter(android.support.v7.widget.RecyclerView$Adapter, boolean)' on a null object reference
这是否意味着该片段不存在?,
我如何解释最后一条消息?
如何将 'Added' 修复为 true?
部分修复:
我有一个 "Restart Activity" 方法,我正在用它来解决 "fix" 我的问题,但作为新手,我认为这不是正确的答案。
在 onCreateView
上设置 RecyclerView
,恢复应该会自动进行。
关于生命周期:存在差异是因为您的模拟器不会破坏您的 activity / 片段,而您的设备会破坏,可能是因为模拟器有更多内存。
如果您在重新打开自己的应用程序之前在模拟器上打开了更多的应用程序,那么您也会遇到同样的情况。或者,如果您在模拟器上打开开发人员选项 "don't keep activities",这会模仿这种行为:设备会立即破坏您的活动和片段,因为它想在别处使用内存。
所以任何 device/emulator 都可以走你看到的两条路线中的任何一条。你应该支持两者。
我有一个 Fragment Pager Adapter
,有 5 个片段和一个 RecyclerView
,除了最后一个片段外,其他片段都一样,它有一个按钮来改变内容,当我按下这个按钮时,它会打开一个 Dialog Fragment
将替换 RecyclerView
的所有内容。
只有当我在 Dialog Fragment
打开时将应用程序发送到后台时,我的问题才会出现,当我恢复应用程序并提交更改时,应用程序崩溃显示 RecyclerView
为空。
恢复后如何恢复片段的完整状态。
通过记录生命周期,我可以看到在恢复后 OnCreate, OnCreateView & OnActivityCreated
是 运行,但是我的方法 setUpCustomPatternsRecyclerView
报告 RecyclerView
为空。
下面是我的片段的代码(非常简单)
重要提示:仅当我在我的 phone 中尝试时,应用程序才会崩溃,在 4 个不同的模拟器中,应用程序不会崩溃。
是不是我的phone中的UI没有完全画好?
如果是这样,我怎样才能收到它已完全绘制的通知?
片段:
public static FragmentCustomPatterns newInstance(ArrayList<PatternArrays> patternArrays, String fragmentTitle, int patternSelectedMode) {
FragmentCustomPatterns patterns = new FragmentCustomPatterns();
Bundle args = new Bundle();
args.putParcelableArrayList(CUSTOM_PATTERNS, patternArrays);
args.putInt(PATTERN_SELECTED_MODE, patternSelectedMode);
args.putString(TITLE, fragmentTitle);
patterns.setArguments(args);
return patterns;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
patternSelectedMode = getArguments().getInt(PATTERN_SELECTED_MODE);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
openCustomCoordinatesFragment = (OpenCustomCoordinatesFragment) getActivity();
View view = inflater.inflate(R.layout.fragment_custom_patterns, container, false);
FloatingActionButton floatingActionButton = view.findViewById(R.id.fab_custom_patterns);
floatingActionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openCustomCoordinatesFragment.openCoordinatesDialog();
}
});
recyclerFlag = false;
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
activityPatternSelector = (ActivityPatternSelector) getActivity();
setUpCustomPatternsRecyclerView();
}
public void setUpCustomPatternsRecyclerView() {
recyclerPatternsView = getView().findViewById(R.id.custom_pattern_recycler_view);
adapter = new PatternCoordinatesAdapter(getActivity(),activityPatternSelector.getCustomPatternArrays(), patternSelectedMode);
recyclerPatternsView.setAdapter(adapter);
Utilities utilities = new Utilities(getActivity(), R.layout.item_coordinates_pattern_cardview);
GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), utilities.calculateNoOfColumns());
recyclerPatternsView.setLayoutManager(gridLayoutManager);
recyclerPatternsView.setItemAnimator(new DefaultItemAnimator());
if (!recyclerFlag) {
recyclerPatternsView.addItemDecoration(new GridSpacing(utilities.calculateSpacing()));
recyclerFlag = true;
}
}
public interface OpenCustomCoordinatesFragment {
void openCoordinatesDialog();
}
LifeCycle 的模拟器(API22 和 API26)logcat 重新创建错误:
E/TESTING ACT: onPause:
D/TESTING FRAG: onPause:
E/TESTING ACT: onSaveInstanceState:
D/TESTING FRAG: onSaveInstanceState:
D/TESTING FRAG: onResume:
Phone Logcat(API25) logcat LifeCycle 重现错误:
E/TESTING ACT: onPause:
D/TESTING FRAG: onPause:
E/TESTING ACT: onSaveInstanceState:
D/TESTING FRAG: onSaveInstanceState:
E/TESTING ACT: onCreate:
D/TESTING FRAG: onCreate:
E/TESTING ACT: onCreate: Array Size 25
D/TESTING FRAG: onCreateView:
D/TESTING FRAG: onActivityCreated:
D/TESTING FRAG: onActivityCreated: Array Size 25
D/TESTING FRAG: onResume:
两者完全不同 我将按照 phone logcat 的方式在 OnSaveInstanceState
中创建一个 Bundle。请注意,在模拟器上 OnResume
在 OnSavedInstanceState
之后被调用,而在 phone 上在 OnActivityCreated
和 none 之后被调用。
谁能解释一下物理设备和模拟器之间的生命周期差异?
更新:
我找不到解决这个问题的办法。 运行 在 activity 中托管 FragmentPagerAdapter
也启动 DialogFragment
:
final FragmentCustomPatterns myTempFrag = (FragmentCustomPatterns) patternsPagerAdapter.getItem(4);
System.out.println("TESTING: Added " + myTempFrag.isAdded() + " Visible " + myTempFrag.isVisible() + " In Layout " + myTempFrag.isInLayout() + " Resumed " + myTempFrag.isResumed() + " Count " + patternsPagerAdapter.getCount());
正常情况下returns:
TESTING: 'Added' true 'Visible' true 'In Layout' false 'Resumed' true Count 5
在对话框片段打开的情况下将应用程序发送到后台,然后再次返回应用程序后,returns:
TESTING: 'Added' false 'Visible' false 'In Layout' false 'Resumed' false Count 5
我认为这就是我得到的原因:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.swapAdapter(android.support.v7.widget.RecyclerView$Adapter, boolean)' on a null object reference
这是否意味着该片段不存在?, 我如何解释最后一条消息? 如何将 'Added' 修复为 true?
部分修复:
我有一个 "Restart Activity" 方法,我正在用它来解决 "fix" 我的问题,但作为新手,我认为这不是正确的答案。
在 onCreateView
上设置 RecyclerView
,恢复应该会自动进行。
关于生命周期:存在差异是因为您的模拟器不会破坏您的 activity / 片段,而您的设备会破坏,可能是因为模拟器有更多内存。
如果您在重新打开自己的应用程序之前在模拟器上打开了更多的应用程序,那么您也会遇到同样的情况。或者,如果您在模拟器上打开开发人员选项 "don't keep activities",这会模仿这种行为:设备会立即破坏您的活动和片段,因为它想在别处使用内存。
所以任何 device/emulator 都可以走你看到的两条路线中的任何一条。你应该支持两者。