Android优雅地管理活动中的碎片

neo*_*ion 9 android android-fragments

我想要完成的描述: 我有一个应用程序使用FragmentActivity和LinearLayout作为片段的容器.我单击FragmentActivity UI上的不同按钮,并在FragmentActivity中的容器中添加和删除Fragments.除了单击FragmentActivity UI上的按钮之外,每个Fragment还有可以单击的按钮,这些按钮将删除当前片段并在其位置添加不同的片段.

Android的操作方式我理解它: 我一直在阅读如何做到这一点,据我所知,"正确"的做法是使用FragmentActivity作为中继站的一种,并拥有每个片段对FragmentActivity进行回调以传达事件并处理它们.

场景: 让我们说FragmentActivity正在显示Fragment A,当用户点击FragmentA中的一个按钮时,我想停止显示FragmentA并开始显示FragmentB.为此,我在FragmentA中创建了一个名为AListener的接口.在FragmentA的onAttach()方法中,我使用建议的方法来检查FragmentActivity是否实现了AListener.当单击FragmentA中的按钮时,我使用AListener中的一个回调方法将click事件传递给FragmentActivity.在FragmentActivity中,我创建了FragmentB的一个实例,并将其添加到FragmentActivity中的容器中.然后,如果FragmentB中发生了某些事件,我使用相同的方案将事件传递给FragmentActivity并做一些有趣的事情.

所以有什么问题? 对于我的应用程序,我发现这种方案让Fragments回调FragmentActivity然后让FragmentActivity创建一个新的片段或调用前向和现有的片段非常麻烦.我有很多片段需要由FragmentActivity显示,因此我为每种需要显示的片段实现了一个接口(每个片段都不同,所以每个片段都有自己的接口).当我有两个具有相同方法签名的接口并且我被迫重命名其中一个方法时,这会导致冲突.

例如,如果我想使用片段的onAttach()方法将侦听器附加到片段,那么我的FragmentActivity必须实现该接口.我找到了几个实例,其中我有相同名称的回调方法(或者由于名称空间冲突,我不得不将它们命名为类似但不同的东西).对此的一个解决方案是使用匿名类作为回调而不是让FragmentActivity实现接口.这看起来效果不错,但与Android文档中关于使用onAttach()方法设置监听器的内容相反.

有没有优雅的方法来解决这个问题? 在我看来,权衡的是你要么强制FragmentActivity为你想要在其中显示的每个Fragment实现一个接口,并且有注意方法签名冲突的有趣问题,要么你反对Android文档并使用Anonymous用于处理回调的类(不确定其含义).

我对Java很新,觉得我可能会错过一个可以解决我的问题的概念.任何人都可以直截了当地说明如何优雅地解决这个问题?

neo*_*ion 3

我的一位同事想出了一个我认为解决这个问题的优雅解决方案。

请记住,我们试图实现的是一种让片段回调父活动而不需要活动实现该接口的方法。此外,如果活动被销毁然后重新创建,我们需要能够自动再次设置侦听器。

Activity 有一个名为 onAttachFragment(Fragmentfragment) 的生命周期回调,每当将片段附加到 Activity 时就会调用该回调。因此,例如,当在活动中创建新片段时,就会调用它。如果先前被销毁的活动被重新创建,它也会被调用。您可以做的是使用接口或匿名类在 onAttachFragment 中的新片段上设置侦听器,如下所示:

@Override
public void onAttachFragment(Fragment fragment) {
    super.onAttachFragment(fragment);

    //Determine which fragment this is by checking its tag 
    if(fragment.getTag().contains(TextFrag.FRAG_TAG)){
        //set a listener on this fragment using an anonymous class or interface
        ((TextFrag)fragment).setListener(new TextFragButtonListener() {
            @Override
            public void onButtonClicked() {
                count++;
                counterTV.setText(String.valueOf(count));
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

使用这种技术,我们能够避免活动必须实现回调接口,从而避免与回调方法的任何命名冲突。此外,如果活动被销毁,一旦重新创建,侦听器将自动重置,因此我们的回调仍然有效。

可能还有很多其他方法可以做到这一点,我很乐意在这里提出任何人对此技术的批评以及对任何其他技术的建议。