上述观点寻呼机显示对话框具有嵌套片段寻呼机、嵌套、对话框、片段

2023-09-05 04:19:31 作者:你阿凡达个雷迪嘎嘎的,

我已经建立了一个非常简单的测试项目 https://github.com/ArtworkAD/ViewPagerDialogTest 以评估以下情况:主要活动有一个采用支持片段管理器,它承载一个片段视图寻呼机:

 公共类MainActivity扩展AppCompatActivity {

    // ...

    @覆盖
    保护无效的onCreate(包savedInstanceState){
        // ...
        viewPager.setAdapter(新ViewPagerAdapter(getSupportFragmentManager()));
        // ...
        tabLayout.setupWithViewPager(viewPager);
    }

    @覆盖
    保护无效onResume(){
        super.onResume();

        MainActivity.CustomDialog对话框=(MainActivity.CustomDialog)getSupportFragmentManager()findFragmentByTag(MainActivity.CustomDialog.TAG)。

        如果(对话== NULL){
            新MainActivity.CustomDialog()秀(getSupportFragmentManager()的BeginTransaction(),MainActivity.CustomDialog.TAG。);
        }
    }
    // ...
}
 

在活动恢复对话片段显示在主要活动中。

视图寻呼机内的单个片段的定义是这样的:

 公共类RootFragment扩展片段{

    @Nullable
    @覆盖
    公共查看onCreateView(LayoutInflater充气,容器的ViewGroup,捆绑savedInstanceState){
        查看根= inflater.inflate(R.layout.root_fragment,集装箱,假);
        如果(savedInstanceState == NULL){
            。getFragmentManager()的BeginTransaction()加(R.id.root_frame,新FirstLevelFragment(),ROOT)提交()。
        }
        返回根;
    }
}
 

这根片段让我们可以堆叠其他碎片上的root_frame。因此,我们堆栈其它一个又一个:

 公共类FirstLevelFragment扩展片段{

    @Nullable
    @覆盖
    公共查看onCreateView(LayoutInflater充气,容器的ViewGroup,捆绑savedInstanceState){
        setRetainInstance(真正的);
        查看根= inflater.inflate(R.layout.first_level_fragment,集装箱,假);
        root.findViewById(R.id.btn).setOnClickListener(新View.OnClickListener(){
            @覆盖
            公共无效的onClick(视图v){
                SecondLevelFragment F =(SecondLevelFragment)getActivity()getSupportFragmentManager()findFragmentByTag(嵌套)。;
                如果(F == NULL){
                    。getActivity()getSupportFragmentManager()的BeginTransaction()加(R.id.root_frame,新SecondLevelFragment(),嵌套)addToBackStack(空).commit()。;
                }
            }
        });
        返回根;
    }

    公共静态类SecondLevelFragment扩展片段{

        @Nullable
        @覆盖
        公共查看onCreateView(LayoutInflater充气,容器的ViewGroup,捆绑savedInstanceState){
            setRetainInstance(真正的);
            返回inflater.inflate(R.layout.second_level_fragment,集装箱,假);
        }
    }
}
 
电脑里打开腾讯有对话框

这个伟大的工程!该堆叠的想法是从 http://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嵌套}

     

E / AndroidRuntime:java.lang.IllegalArgumentException异常:由没有造成人员   查看发现的ID 0x7f0c0083   (de.azzoft.viewpagerdialogtest:ID / root_frame)的片段   SecondLevelFragment {15c0db38#0 ID = 0x7f0c0083嵌套}

完整的堆栈跟踪: https://github.com/ArtworkAD/ViewPagerDialogTest/ BLOB /主/ README.md

没有出现的一切对话的伟大工程。您可以通过下载该测试项目来测试它。

看来,对话,这实际上是一个片段,打乱了片段的层次结构时,它被添加到该活动。任何想法如何解决这一问题?

重要的是,第二个片段被保留

解决方案

 无景观发现ID 0x7f0c0083(de.azzoft.viewpagerdialogtest:ID / root_frame)的片段SecondLevelFragment
 

活动重现上旋转,在活动FragmentManger 尝试添加 SecondLevelFragment R.id.root_frame 。但 root_frame 的观点是不活动的布局,它在 FirstLevelFragment 的布局。这就是为什么该应用程序崩溃。

您必须做出两处修改来解决这个问题。

添加 FirstLevelFragment RootFragment 使用 getChildFragmentManager

  getChildFragmentManager()的BeginTransaction()加(R.id.root_frame,新FirstLevelFragment(),ROOT)提交()。;
 

添加 SecondLevelFragment 使用 FragmentManager

  getFragmentManager()的BeginTransaction()加(R.id.root_frame,新SecondLevelFragment(),嵌套)addToBackStack(空).commit()。;
 

最后删除 setRetainInstance FirstLevelFragment SecondLevelFragment 嵌套的片段并不需要设置保留。

如果你需要弹回,你需要通过后面的preSS的事件RootFragment和回栈中弹出的 SecondLevelFragment 背preSS。

覆盖上的活动背后preSS

  @覆盖
公共无效onBack pressed(){
    片段片段= getSupportFragmentManager()findFragmentById(R.id.viewpager)。
    如果(片段的instanceof RootFragment){
        布尔处理=((RootFragment)片段).onBack pressed();
        如果(处理){
            返回;
        }
    }
    super.onBack pressed();
}
 

和处理回preSS对 RootFragment

 公共布尔onBack pressed(){
    诠释计数= getChildFragmentManager()getBackStackEntryCount()。
    如果(计数大于0){
        。getChildFragmentManager()popBackStackImmediate();
        返回true;
    }
    返回false;
}
 

我创建了一个拉请求你的资料库。请检查 https://github.com/ArtworkAD/ViewPagerDialogTest/pull/1

让我知道,如果有任何问题。

I have setup a very simple test project https://github.com/ArtworkAD/ViewPagerDialogTest to evaluate following situation: the main activity has a view pager which hosts a single fragment using support fragment manager:

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);
        }
    }
    // ...
}

When the activity is resumed a dialog fragment is shown inside the main activity.

The single fragment inside the view pager is defined like this:

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;
    }
}

This root fragment allows us to stack other fragments on the "root_frame". So we stack another and another:

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);
        }
    }
}

This works great! The stacking idea is taken from http://stackoverflow.com/a/21453571/401025 . However when dialog is shown and the users goes to the second level fragment and rotates the screen I get following exception:

E/AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{de.azzoft.viewpagerdialogtest/de.azzoft.viewpagerdialogtest.MainActivity}: java.lang.IllegalArgumentException: No view found for id 0x7f0c0083 (de.azzoft.viewpagerdialogtest:id/root_frame) for fragment SecondLevelFragment{15c0db38 #0 id=0x7f0c0083 NESTED}

E/AndroidRuntime: Caused by: java.lang.IllegalArgumentException: No view found for id 0x7f0c0083 (de.azzoft.viewpagerdialogtest:id/root_frame) for fragment SecondLevelFragment{15c0db38 #0 id=0x7f0c0083 NESTED}

Full stack trace: https://github.com/ArtworkAD/ViewPagerDialogTest/blob/master/README.md

Without the dialog appearing everything works great. You can test it by downloading the test project.

It seems that the dialog, which is actually a fragment, messes up fragment hierarchy when it is added to the activity. Any ideas how to fix this?

It is important that the second fragment is retained.

解决方案

No view found for id 0x7f0c0083 (de.azzoft.viewpagerdialogtest:id/root_frame) for fragment SecondLevelFragment

When Activity recreates on rotate, the Activity FragmentManger tries to add the SecondLevelFragment into R.id.root_frame . But the root_frame view is not in Activity layout, its in FirstLevelFragment layout. Thats why the app crashes.

You have to make two changes to fix this issue.

Add the FirstLevelFragment into the RootFragment using the getChildFragmentManager

getChildFragmentManager().beginTransaction().add(R.id.root_frame, new FirstLevelFragment(), "ROOT").commit();

Add the SecondLevelFragment using FragmentManager

getFragmentManager().beginTransaction().add(R.id.root_frame, new SecondLevelFragment(), "NESTED").addToBackStack(null).commit();

Finally remove the setRetainInstance from FirstLevelFragment and SecondLevelFragment as nested fragments doesn't required to set retain.

If you need to pop back the SecondLevelFragment on back press you need to pass the back press the event to RootFragment and pop from back stack.

Override the back press on activity

@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();
}

And handle the back press on RootFragment

public boolean onBackPressed() {
    int count = getChildFragmentManager().getBackStackEntryCount();
    if(count > 0){
        getChildFragmentManager().popBackStackImmediate();
        return true;
    }
    return false;
} 

I created a Pull request to your repository . please check https://github.com/ArtworkAD/ViewPagerDialogTest/pull/1

Let me know if any questions.