我已经设置了一个非常简单的测试项目https://github.com/ArtworkAD/ViewPagerDialogTest来评估以下情况:主要活动有一个视图寻呼机,它使用支持片段管理器来托管单个片段:
public class MainActivity extends AppCompatActivity {
// ...
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager()));
// ...
tabLayout.setupWithViewPager(viewPager);
}
@Override
protected void onResume() {
super.onResume();
MainActivity.CustomDialog dialog = (MainActivity.CustomDialog) getSupportFragmentManager().findFragmentByTag(MainActivity.CustomDialog.TAG);
if (dialog == null) {
new MainActivity.CustomDialog().show(getSupportFragmentManager().beginTransaction(), MainActivity.CustomDialog.TAG);
}
}
// ...
}
当活动恢复时,主要活动内会显示一个对话框片段。
视图寻呼机内的单个片段定义如下:
public class RootFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.root_fragment, container, false);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction().add(R.id.root_frame, new FirstLevelFragment(), "ROOT").commit();
}
return root;
}
}
这个根片段允许我们在" root_frame"上堆叠其他片段。所以我们堆叠另一个和另一个:
public class FirstLevelFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setRetainInstance(true);
View root = inflater.inflate(R.layout.first_level_fragment, container, false);
root.findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SecondLevelFragment f = (SecondLevelFragment) getActivity().getSupportFragmentManager().findFragmentByTag("NESTED");
if (f == null) {
getActivity().getSupportFragmentManager().beginTransaction().add(R.id.root_frame, new SecondLevelFragment(), "NESTED").addToBackStack(null).commit();
}
}
});
return root;
}
public static class SecondLevelFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setRetainInstance(true);
return inflater.inflate(R.layout.second_level_fragment, container, false);
}
}
}
这很棒!堆叠的想法取自https://stackoverflow.com/a/21453571/401025。但是,当显示对话框并且用户转到第二级片段并旋转屏幕时,我得到以下异常:
E / AndroidRuntime:java.lang.RuntimeException:无法启动活动 ComponentInfo {de.azzoft.viewpagerdialogtest / de.azzoft.viewpagerdialogtest.MainActivity}: java.lang.IllegalArgumentException:找不到id 0x7f0c0083的视图 (de.azzoft.viewpagerdialogtest:id / root_frame)片段 SecondLevelFragment {15c0db38#0 id = 0x7f0c0083 NESTED}
E / AndroidRuntime:引起:java.lang.IllegalArgumentException:不 找到的内容id为0x7f0c0083 (de.azzoft.viewpagerdialogtest:id / root_frame)片段 SecondLevelFragment {15c0db38#0 id = 0x7f0c0083 NESTED}
完整堆栈跟踪:https://github.com/ArtworkAD/ViewPagerDialogTest/blob/master/README.md
如果没有出现对话框,一切都很有效。您可以通过下载测试项目来测试它。
似乎对话框实际上是一个片段,当它被添加到活动时会破坏片段层次结构。任何想法如何解决这个问题?
保留第二个片段非常重要。
答案 0 :(得分:1)
如果覆盖onDismiss,则解决崩溃问题。享受它。
@Override
protected void onResume() {
super.onResume();
DialogFragment dialog = (DialogFragment) getSupportFragmentManager().findFragmentByTag(TAG);
if(dialog == null){
CustomDialog.newInstance().show(getSupportFragmentManager(), TAG);
}
}
public static class CustomDialog extends DialogFragment {
public static CustomDialog newInstance() {
CustomDialog d = new CustomDialog();
return d;
}
@Override
public void onDismiss(DialogInterface dialog) {
// super.onDismiss(dialog);
Toast.makeText(getActivity(), "onDismiss", Toast.LENGTH_LONG).show();
}
@Override
public void onCancel(DialogInterface dialog) {
// super.onCancel(dialog);
Toast.makeText(getActivity(), "onCancel", Toast.LENGTH_LONG).show();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Dialog");
builder.setMessage("This is a message!");
builder.setPositiveButton("Okay", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Toast.makeText(getActivity(), "onClick", Toast.LENGTH_LONG).show();
}
});
builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Toast.makeText(getActivity(), "onClick", Toast.LENGTH_LONG).show();
}
});
return builder.show();
}
}
答案 1 :(得分:1)
No view found for id 0x7f0c0083 (de.azzoft.viewpagerdialogtest:id/root_frame) for fragment SecondLevelFragment
当Activity
在轮播时重新创建时,Activity FragmentManger
会尝试将SecondLevelFragment
添加到R.id.root_frame
。但是root_frame
视图不在“活动”布局中,而是在FirstLevelFragment
布局中。这就是应用程序崩溃的原因。
您必须进行两项更改才能解决此问题。
使用FirstLevelFragment
RootFragment
添加到getChildFragmentManager
getChildFragmentManager().beginTransaction().add(R.id.root_frame, new FirstLevelFragment(), "ROOT").commit();
使用SecondLevelFragment
FragmentManager
getFragmentManager().beginTransaction().add(R.id.root_frame, new SecondLevelFragment(), "NESTED").addToBackStack(null).commit();
最后从setRetainInstance
和FirstLevelFragment
移除SecondLevelFragment
,因为嵌套片段并不需要设置保留。
如果你需要在背面弹回SecondLevelFragment
,你需要传递背面按事件到RootFragment并从后面堆栈弹出。
覆盖活动背面按
@Override
public void onBackPressed() {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.viewpager);
if(fragment instanceof RootFragment){
boolean handled = ((RootFragment)fragment).onBackPressed();
if(handled){
return;
}
}
super.onBackPressed();
}
并处理RootFragment
public boolean onBackPressed() {
int count = getChildFragmentManager().getBackStackEntryCount();
if(count > 0){
getChildFragmentManager().popBackStackImmediate();
return true;
}
return false;
}
我为您的存储库创建了一个Pull请求。请检查 https://github.com/ArtworkAD/ViewPagerDialogTest/pull/1
如果有任何问题,请告诉我。
答案 2 :(得分:0)
如果您希望保持状态 Fragments
,则应使用FragmentStatePagerAdapter。
来自文档:
使用Fragment管理每个的PagerAdapter的实现 页。该类还处理片段的保存和恢复 状态。
如果您使用此功能,还可以删除setRetainInstance(true)
来电。
答案 3 :(得分:0)
好吧,我已经下载了你的测试应用程序,似乎我已经解决了这个问题。
在FirstLevelFragment
课程中,请注释以下内容
//if (nestedNestedFragment == null) {
getActivity().getSupportFragmentManager().beginTransaction().add(R.id.root_frame, new SecondLevelFragment(), "NESTED").addToBackStack(null).commit();
//}
和
setRetainInstance(true);
SecondLevelFragment
答案 4 :(得分:0)
我认为您错过setContentView()
活动中的onCreate()
。如果没有View层次结构,则无法添加片段。您的片段由活动托管。因此,您需要先将内容设置为活动。
希望这有助于, 感谢。