活动和片段交互

时间:2013-07-03 21:16:05

标签: android oop android-fragments listener

我有ActivityFragment个。{我想显示DialogFragment或从其中一个Fragment打开另一个Fragment。我知道Activity应该是开放Fragment的任务,所以我尝试了几件事。

第一
我尝试使用getActivity()并投了它,以便我可以调用Activity中的方法来显示Fragment但是这会在Fragment中创建一个依赖关系{{1}如果可能的话,我想避免添加依赖项。

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

THIRD
然后我尝试让Activity直接实现监听器,这是有效的,因为那时我只是用监听器创建依赖,而不是活动。但是现在我已经到了Activity将要实现2-4个不同界面的地步,这让我犹豫不决,因为它会严重降低凝聚力。

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

7 个答案:

答案 0 :(得分:11)

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

因此,在我看来,第一个选项永远不应该考虑你提到的导致高度耦合代码的依赖性原因。

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

所以对我来说第三种选择更有意义。我相信,就他们持有的特定回调而言,活动更具可读性。但是,你是对的,你的活动可能成为一个神的对象。

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

答案 1 :(得分:10)

创建界面

public interface ListenFromActivity {
    void doSomethingInFragment();
}

活动类中保持对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会提示你在片段

中实现接口方法
 void doSomethingInFragment()
{//Add your code here 
}

片段onCreate方法

中的活动的最终部件侦听器实例
((ListnerActivity) getActivity()).setActivityListener(SomeFragment.this);

DONE !!。现在你可以从活动中调用片段方法了。

答案 2 :(得分:3)

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

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

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

让活动实现界面:

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

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

答案 3 :(得分:3)

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

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

快速示例,考虑片段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实现了此接口,否则您将获得异常。如果成功实施,则每次选择列表片段中的项目时,系统都会通知您的活动位置。显然你可以用任何数量或类型的参数改变你的界面,在这个例子中我们只是传递我们的整数位置。希望这能澄清一点人,祝你好运。

答案 4 :(得分: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");

让我知道,欢呼。

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

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