15

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

首先
,我尝试使用getActivity()并转换它,以便我可以在 中调用一个方法Activity来显示 a ,Fragment但是这会在Fragmentwith 中创建一个依赖关系,Activity如果可能的话,我想避免添加依赖关系。

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


Activity直接实现侦听器,因为那时我只创建与侦听器而不是活动的依赖关系。但是现在我已经到了Activity要实现 2 到 4 个不同接口的地步,这让我犹豫不决,因为它会严重降低凝聚力。

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

4

7 回答 7

16

创建接口

public interface ListenFromActivity {
    void doSomethingInFragment();
}

Activity类中保持ListenFromActivity接口的引用

 public ListenFromActivity activityListener;   

公开方法来设置监听器

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

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

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

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

于 2016-11-21T07:12:25.983 回答
11

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

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

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

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

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

于 2013-07-03T21:56:01.233 回答
4

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

有关如何在此处执行此操作的更多信息 与其他片段的通信

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

首先,这样定义片段 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 其位置。显然你可以用任意数量或类型的参数来改变你的接口,在这个例子中我们只是传入我们的整数位置。希望这能澄清一点,祝你好运。

于 2013-07-03T21:58:30.803 回答
2

我认为你的第二个选择是在正确的轨道上。

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

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

让活动实现接口:

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

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

于 2013-07-03T21:29:37.730 回答
0

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

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

于 2013-11-21T13:00:45.190 回答
0

您是否尝试过这样的事情(来自片段):

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

让我知道,干杯。

于 2013-07-03T21:57:17.863 回答
0

只需遵循文档

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
    }
}
于 2018-11-24T13:09:30.090 回答