Android Fragments基本原理:为什么?这在概念上是错的吗?

时间:2015-06-11 10:53:20

标签: android interface fragment communication

我对Android中的“正确编程”有疑问。

我目前正在使用片段开发应用。它涉及动态添加的片段到Activity,从XML膨胀的片段,从XML嵌套的片段或动态添加。我们只想说一点。

这个问题关注的概念是与片段有关的沟通过程。所以,我已经阅读了文档,这不是我第一次尝试使用片段。

常识(和文档)告诉我们,如果Fragment想要说话或与其活动进行交流,我们应该使用界面。

示例:

TestFragment

public class TestFragment extends Fragment {

  private TestFragmentInterface listener; 

  public interface TestFragmentInterface {

      void actionMethod();

  }


  @Override
  public void onViewCreated(View view, Bundle savedInstanceState) {

      if (getActivity() instanceof TestFragmentInterface) {
          listener = (TestFragmentInterface) getActivity();
      }

      // sending the event
      if (listener != null) listener.actionMethod();
  }

}

测试活动

public class Test implements TestFragmentInterface {

  @Override
  public void actionMethod() {
    ..
  }
}

这里一切都很好。

这提高了可重用性,因为我的TestFragment可以与任何类型的Activity交互,因为Activity实现了我声明的接口。

反过来说,Activity可以通过持有引用并调用其公共方法来与片段交互。这也是使用Activity作为桥梁进行片段到片段通信的建议方法。

这很酷,但有时感觉就像使用接口这只是有点“太多”。

问题A

在场景中,我附加的片段具有非常集中的角色,这意味着它们是针对该特定活动完成的,否则将不会被使用,忽略接口实现在概念上是错误的,只是执​​行类似

的操作。
((TestActivity) getActivity().myCustomMethod();

这也适用于这样的情况(不是我的情况,只是把它当作“最坏的情况”)我的活动必须处理各种各样的这些不同的片段,这意味着它应该为每个片段实现一种方法它应该处理。这使得代码变成了一堆“可能不需要的行”。

继续前进:仍然使用“聚焦”片段,旨在仅以某种方式工作,使用嵌套片段是什么?

一样添加了它们
public class TestFragment extends Fragment {


  private void myTestMethod() {

    NestedFragment nested = new NestedFragment();

    getChildFragmentManager()
      .beginTransaction()
      .add(R.id.container, nested)
      .commit();
  }

}

这会将NestedFragment绑定到TestFragment。我再说一次,就像TestFragment一样,NestedFragment只能以这种方式使用,否则没有任何意义。

回到问题,我应该如何处理这种情况?

问题B

1)我应该在NestedFragment中提供一个接口,并使TestFragments实现NestedFragmentInterface吗?在这种情况下,我将采取以下行动

NestedFragment

public class NestedFragment extends Fragment {

  private NestedFragmentInterface listener; 

  public interface NestedFragmentInterface {

      void actionMethodNested();

  }


  @Override
  public void onViewCreated(View view, Bundle savedInstanceState) {

      if (getParentFragment() instanceof NestedFragmentInterface) {
          listener = (NestedFragmentInterface) getParentFragment();
      }

      // sending the event
      if (listener != null) listener.actionMethodNested();
  }

}

2)我应该(或可能)忽略接口,只需调用

getParentFragment().publicParentMethod();

3)我应该在NestedFragment中创建界面,但让活动实现它,以便活动将调用TestFragment?

问题C

关于使用Activity作为片段之间的桥梁的想法,我相信它是为了正确处理所有这些对象的生命周期。在尝试手动处理系统可能引发的异常时,是否仍然可以直接进行片段到片段(使用接口或直接调用公共方法)?

2 个答案:

答案 0 :(得分:10)

我会尽力回答这里的文字墙:)

问题A:

片段设计为可重复使用的模块,可以插入和播放任何活动。因此,与活动交互的唯一正确方法是让活动从片段理解的接口继承。

public class MapFragment extends Fragment {

  private MapFragmentInterface listener; 

  public interface MapFragmentInterface {

      //All methods to interface with an activity

  }


  @Override
  public void onViewCreated(View view, Bundle savedInstanceState) {
      // sending the event
      if (listener != null) listener.anyMethodInTheAboveInterface();
  }

}

然后让活动实现接口

public class MainActivity extends Activity implement MapFragmentInterface{

//All methods need to be implemented here
}

只要活动实现此接口,这就允许您的片段与任何活动一起使用。您需要此接口的原因是因为片段可以与任何活动一起使用。调用类似

的方法
((TestActivity) getActivity().myCustomMethod();

依赖于这样一个事实,即您的片段只能在测试活动中工作,因此会“破坏”片段的规则。

问题B和C:

假设您遵循正确的片段准则并且它们是独立的模块。那么你应该永远不会有片段需要彼此了解的情况。 99%的时间人们认为他们需要片段来直接沟通,他们可以通过使用MVC模式或类似的东西将他们的问题重新考虑到我上面给出的情况。让活动像控制器一样,在需要更新时告诉碎片,然后创建一个单独的数据存储。

答案 1 :(得分:4)

我会尽力清除它。

首先,考虑一下为片段设置监听器的方法。在onViewCreated方法中设置监听器并不好,因为它会导致过多的重置监听器创建任何碎片。将其设置为onAttach方法就足够了。

我讲过代码行。请注意,最好让BaseFragment在您的应用程序中实现常见行为,因为设置FragmentListener从资源创建视图。

除了减少代码行和获得部分代码重用之外,您还可以在BaseFragment中使用泛型。请看下一个代码段:

public abstract BaseFragment<T extends BaseFragmentListener> extends Fragment {

  T mListener;

  public void onAttach(Activity activity) {
    super.onAttach(activity);
    if (Activity instanceof T)
      mListener = (T) activity; 
  }

  abstract int getLayoutResourceId();

  @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View layout = inflater.inflate(getLayoutResourceId(), null);
        // you can use some view injected tools here, mb ButterKnife 
        return layout;
    }
}

答案A(对于问题A):

如果你只有一个活动片段,你需要决定:“你真的需要在这里使用Fragment吗?”。但是mb最好是为一个活动准备片段以从活动中提取一些视图逻辑并清除基本逻辑。但是为了清除应用程序的基础架构逻辑,请使用Listeners。这将使其他开发人员的生活更轻松

答案B: 对于您需要解决的嵌套片段,他们需要使用精确活动或仅使用片段,并将其用作其他系统的桥梁。如果你知道嵌套片段将一直嵌套,你需要将父片段声明为监听器,否则你必须使用其他方法。

注意: 作为App的差异部分之间进行通信的基本方法,您可以使用事件,例如,尝试查看事件总线。它为您提供了通用的通信方法,您可以提取调用自定义侦听器方法的逻辑,以及所有逻辑将处理事件,您将拥有一个中介系统进行协作。

答案C: 我部分解释了片段之间合作的方法之一。使用一个事件调度程序可以避免为所有不同的通信提供许多侦听器。有时候这是非常有利可图的。

或者我认为使用Activity或其他类存在于Activity中更适用于Fragments合作的中介,因为在处理和系统的生命周期中存在许多碎片发生变化的情况。它将所有这些逻辑集中在一个地方,使您的代码更加清晰。

希望我的考虑对你有帮助。