【问题标题】:Activity And Fragment InteractionActivity 和 Fragment 交互
【发布时间】:2013-07-01 17:58:59
【问题描述】:

我有一个 Activity 和多个 Fragments。我想显示DialogFragment 或从Fragments 之一打开另一个Fragment。我知道Activity 应该是负责打开Fragments 的人,所以我尝试了几件事。

第一
我尝试使用getActivity() 并对其进行强制转换,以便我可以在Activity 中调用一个方法来显示Fragment 但这会在Fragment 中创建一个与Activity 的依赖关系,我想避免添加一个尽可能依赖。

第二次
接下来我尝试了一个监听器来通知Activity 它应该显示Fragment。所以我在Activity中创建了一个类来实现监听接口。但是我遇到了问题,因为我必须使用New MyActivity().new Listener();,当我尝试使用getSupportFragmentManager() 时它会抛出Exception,因为Activity 的这个实例没有被初始化。

THIRD
然后我尝试让Activity 直接实现监听器,因为这样我只创建了一个与监听器而不是活动的依赖关系。但是,现在我的 Activity 将实现 2 到 4 个不同的接口,这让我犹豫不决,因为它会严重降低凝聚力。

所以我尝试过的任何方式似乎都遇到了砖墙并创建了我不确定是否需要创建的依赖项。我搞砸了,必须选择其中一种吗?如果是这样,哪个选项最好?非常感谢任何帮助或建议。

【问题讨论】:

  • 有很多方法可以做到这一点,我更喜欢尽可能解耦的东西,为此我喜欢事件总线。参见 otto,例如:square.github.io/otto。 (让您摆脱所有接口/侦听器的麻烦。传递数据,使用强类型,以清晰简洁的方式进行。)
  • 看起来很有希望。我得去看看。感谢您的提示。

标签: android oop android-fragments listener


【解决方案1】:

创建界面

public interface ListenFromActivity {
    void doSomethingInFragment();
}

Activity类保持ListenFromActivity接口的引用

 public ListenFromActivity activityListener;   

公开方法设置监听器

 public void setActivityListener(ListenFromActivity activityListener) {
        this.activityListener = activityListener;
    }

在activity类中添加一些触发点,这里我使用了用户交互

    @Override
    public void onUserInteraction() {
        super.onUserInteraction();

        if (null != activityListener) {
            activityListener.doSomethingInFragment();
        }
    }

现在在片段类

让你的片段实现接口类

public class SomeFragment extends Fragment implements ListenFromActivity

Android Studio 会提示你在 Fragment 中实现接口的方法

 void doSomethingInFragment()
{//Add your code here 
}

片段onCreate方法中这样的活动的最后部分监听器实例

((ListnerActivity) getActivity()).setActivityListener(SomeFragment.this);

完成!!。现在您可以从活动中调用片段方法。

【讨论】:

    【解决方案2】:

    我个人认为片段应该被认为是可重用和模块化的组件。因此,为了提供这种可重用性,片段不应该对它们的父活动了解太多。但作为回报,活动必须知道他们持有的碎片。

    因此,我认为永远不应该考虑第一个选项,因为您提到的依赖原因会导致非常高度耦合的代码。

    关于第二个选项,片段可以将任何应用程序流程或 UI 相关决策(显示新片段、决定触发片段特定事件时的操作等)委托给它们的父活动。所以你的监听器/回调应该是片段特定的,因此它们应该在片段中声明。而持有这些片段的活动应该实现这些接口并决定做什么。

    所以对我来说,第三个选项更有意义。我相信活动在特定回调中所持有的内容和所做的事情更具可读性。但是,是的,您是对的,您的活动可能会成为上帝的对象。

    如果您不想实现多个接口,也许可以查看 Square 的 Otto 项目。它基本上是一个事件总线。

    【讨论】:

    • 感谢您和@Charlie Collins 将我指向 Otto 库。这似乎非常有希望,并且似乎它将完成我正在寻找的东西。感谢大家的帮助。
    【解决方案3】:

    您需要将数据从 Fragment X 传递到 FragmentActivity,FragmentActivity 会将这些数据传递到 Fragment Y。您可以通过片段类中定义的接口来执行此操作,并实例化 onAttach 中定义的回调()。

    有关如何在此处执行此操作的更多信息 Communication With other Fragments

    快速示例,考虑 Fragment A 和 Fragment B。Fragment A 是一个列表片段,无论何时选择一个项目,它都会改变 Fragment B 中显示的内容。够简单吧?

    首先,这样定义Fragment A。

     public class FragmentA extends ListFragment{
    
       //onCreateView blah blah blah
    
    }
    

    这是片段 B

    public class FragmentB extends Fragment{
    
     //onCreateView blah blah blah
    
    }
    

    这是我的 FragmentActivity 将同时管理它们

    public class MainActivity extends FragmentActivity{
    
    //onCreate 
    //set up your fragments
    
    }
    

    大概你已经有了类似的东西,现在这里是你将如何更改 FragmentA(我们需要从中获取一些数据的列表片段)。

        public class FragmentA extends ListFragment implements onListItemSelectedListener, onItemClickListener{
    
    OnListItemSelectedListener mListener;
    
       //onCreateView blah blah blah
    
    
    
     // Container Activity must implement this interface
        public interface OnListItemSelectedListener {
        public void onListItemSelected(int position);
    }
    
    
    }
    
    
      @Override
      public void onAttach(Activity activity) {
        super.onAttach(activity);
    
        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            mListener = (OnListItemSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnListItemSelectedListener");
        }
    }
    
    
      @Override 
     public void onItemClick(AdapterView<?> parent, View view, int position, long id){
    
    
     //Here's where you would get the position of the item selected in the list, and  pass    that position(and whatever other data you need to) up to the activity 
    //by way of the interface you defined in onAttach
    
      mListener.onListItemSelected(position);
    
    
    }
    

    这里最重要的考虑是你的父Activity实现了这个接口,否则你会得到一个异常。如果成功实施,每次选择列表片段中的项目时,都会通知您的 Activity 其位置。显然,您可以使用任意数量或类型的参数来更改接口,在此示例中,我们只是传入整数位置。希望这能澄清一点,祝你好运。

    【讨论】:

      【解决方案4】:

      我认为您的第二个选择是正确的。

      在您的片段中,定义监听器接口:

      class MyFragment ...
      {
          public interface IMyFragmentListenerInterface
          {
              void DoSomething();
          }
      }
      

      让活动实现接口:

      class MyActivity
      {
          class MyListener1 implements IMyFragmentListenerInterface { ... }
      }
      

      将监听器传递给片段。我喜欢在 Fragment 的构造函数中执行此操作,但这只有在您完全自己管理 Fragment 时才有效。您可以将 setListener 方法添加到您的片段中。

      【讨论】:

      • setListener 方法存在一个问题:如果 Fragment 被操作系统销毁并重新创建(使用默认的空白构造函数),则对侦听器的引用将丢失。实现这一点的最佳方法是将代码放入onAttach 方法中,以将片段的父活动挂接到作为侦听器,并在运行时检查它是否支持所需的接口。请参阅developer.android.com/guide/components/fragments.html:“为 Activity 创建事件回调”。
      【解决方案5】:

      你有没有尝试过这样的事情(来自片段):

      FragmentTransaction ft = 
          getActivity().getSupportFragmentManager().beginTransaction();
      Fragment prev = 
          getActivity().getSupportFragmentManager().findFragmentByTag("some_name");
      if (prev != null) {
          ft.remove(prev);
      }
      ft.addToBackStack(null);
      
      DialogFragment dialogFragment = DialogFragmentClass.newInstance();
      dialogFragment.show(ft, "some_name");
      

      告诉我,干杯。

      【讨论】:

        【解决方案6】:

        要获得最大的松散耦合,您可以使用事件总线,例如 Square 的 OTTO 或 GreenRobot 的 EventBus。 您的片段可以触发由您的活动处理的事件,反之亦然。很酷的一点是组件(活动、片段)彼此之间没有任何关系,您不需要声明任何接口或回调。

        我在所有项目中都使用它,它很健壮,对性能的影响很小甚至没有影响(在正常情况下)。

        【讨论】:

          【解决方案7】:

          follow the documentation

          Fragment:

          public class HeadlinesFragment extends Fragment {
          
              // Container Activity must implement this interface
              public interface OnHeadlineSelectedListener {
                  public void onArticleSelected(int position);
              }
          
              OnHeadlineSelectedListener mCallback;
          
              // "Bind" to the Activity where this Fragment lives
              public void setOnHeadlineSelectedListener(Activity activity) {
                  mCallback = (OnHeadlineSelectedListener) activity;
              }
          
              // ...
          
              // This will send info to the Activity where the Fragment lives
              private void someOtherFunctionOrListener(int position) {
                  mCallback.onArticleSelected(position); // pass info into Activity
              }
          }
          

          Activity:

          public static class MainActivity extends Activity
                  implements HeadlinesFragment.OnHeadlineSelectedListener{
              // ...
          
              @Override
              public void onAttachFragment(Fragment fragment) {
                  if (fragment instanceof HeadlinesFragment) {
                      HeadlinesFragment headlinesFragment = (HeadlinesFragment) fragment;
                      headlinesFragment.setOnHeadlineSelectedListener(this);
                  }
              }
          
              @Override
              public void onArticleSelected(int position) {
                  // Call received from Fragment
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-05-11
            • 1970-01-01
            • 2018-04-14
            • 1970-01-01
            相关资源
            最近更新 更多