android - Android中嵌套 fragment 之间的通信

标签 android android-fragments

我最近了解到how to make nested fragments in Android .不过,我不知道应该如何进行交流。

enter image description here

从阅读 fragment communication documentation我知道

All Fragment-to-Fragment communication is done through the associated Activity. Two Fragments should never communicate directly.

这对于 Activity 中的兄弟 Fragment 是有意义的,但对于父子 Fragment 通信而言意义不大。我是否需要一直到 Activity 才能让子 fragment 与父 fragment 交谈?如果答案是简单的"is",那么我可以做到。如果是“否”,那么代码设计会是什么样子?

我在 Nested Fragment documentation 中看到可以使用getParentFragment()获取对父 fragment 的引用。那么这是否意味着 child 应该直接与 parent 沟通呢?这似乎与正常 fragment 与父 Activity 通信所鼓励的相反。

最佳答案

按照 Rahul Sharma 在评论中的建议,我使用接口(interface)回调从子 fragment 到父 fragment 和 Activity 进行通信。我也是submitted this answer to Code Review .我认为那里没有答案(在撰写本文时)表明这种设计模式没有重大问题。在我看来,这与官方 fragment communication docs 中给出的一般指导一致。 .

示例项目

以下示例项目扩展了问题中给出的示例。它具有启动从 Fragment 到 Activity 以及从 Child Fragment 到 Parent Fragment 的向上通信的按钮。

我这样设置项目布局:

enter image description here

主要 Activity

Activity 实现了两个 fragment 的监听器,以便可以从它们获取消息。

可选 TODO:如果 Activity 想要启动与 Fragment 的通信,它可以直接获取对它们的引用,然后调用它们的公共(public)方法之一。

import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends AppCompatActivity implements ParentFragment.OnFragmentInteractionListener, ChildFragment.OnChildFragmentToActivityInteractionListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.parent_fragment_container, new ParentFragment());
        ft.commit();
    }

    @Override
    public void messageFromParentFragmentToActivity(String myString) {
        Log.i("TAG", myString);
    }

    @Override
    public void messageFromChildFragmentToActivity(String myString) {
        Log.i("TAG", myString);
    }
}

父 fragment

Parent Fragment 从 Child Fragment 实现监听器,以便它可以接收来自它的消息。

可选 TODO:如果父 Fragment 想要启动与子 Fragment 的通信,它可以直接获取对它的引用,然后调用其公共(public)方法之一。

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;


public class ParentFragment extends Fragment implements View.OnClickListener, ChildFragment.OnChildFragmentInteractionListener {


    // **************** start interesting part ************************

    private OnFragmentInteractionListener mListener;


    @Override
    public void onClick(View v) {
        mListener.messageFromParentFragmentToActivity("I am the parent fragment.");
    }

    @Override
    public void messageFromChildToParent(String myString) {
        Log.i("TAG", myString);
    }

    public interface OnFragmentInteractionListener {
        void messageFromParentFragmentToActivity(String myString);
    }

    // **************** end interesting part ************************



    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnFragmentInteractionListener) {
            mListener = (OnFragmentInteractionListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_parent, container, false);
        view.findViewById(R.id.parent_fragment_button).setOnClickListener(this);
        return view;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        Fragment childFragment = new ChildFragment();
        FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
        transaction.replace(R.id.child_fragment_container, childFragment).commit();
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }

}

子 fragment

Child Fragment 为 Activity 和 Parent Fragment 定义了监听器接口(interface)。如果 Child Fragment 只需要与其中一个进行通信,则可以删除另一个接口(interface)。

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;


public class ChildFragment extends Fragment implements View.OnClickListener {


    // **************** start interesting part ************************

    private OnChildFragmentToActivityInteractionListener mActivityListener;
    private OnChildFragmentInteractionListener mParentListener;

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.child_fragment_contact_activity_button:
                mActivityListener.messageFromChildFragmentToActivity("Hello, Activity. I am the child fragment.");
                break;
            case R.id.child_fragment_contact_parent_button:
                mParentListener.messageFromChildToParent("Hello, parent. I am your child.");
                break;
        }
    }

    public interface OnChildFragmentToActivityInteractionListener {
        void messageFromChildFragmentToActivity(String myString);
    }

    public interface OnChildFragmentInteractionListener {
        void messageFromChildToParent(String myString);
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        // check if Activity implements listener
        if (context instanceof OnChildFragmentToActivityInteractionListener) {
            mActivityListener = (OnChildFragmentToActivityInteractionListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnChildFragmentToActivityInteractionListener");
        }

        // check if parent Fragment implements listener
        if (getParentFragment() instanceof OnChildFragmentInteractionListener) {
            mParentListener = (OnChildFragmentInteractionListener) getParentFragment();
        } else {
            throw new RuntimeException("The parent fragment must implement OnChildFragmentInteractionListener");
        }
    }

    // **************** end interesting part ************************



    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_child, container, false);
        view.findViewById(R.id.child_fragment_contact_activity_button).setOnClickListener(this);
        view.findViewById(R.id.child_fragment_contact_parent_button).setOnClickListener(this);
        return view;
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mActivityListener = null;
        mParentListener = null;
    }

}

关于android - Android中嵌套 fragment 之间的通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39491655/

相关文章:

java - 在 fragment 中转换 Activity 以调用父 Activity 中的方法是否安全?

android - Android 中的对话框和弹出窗口

android - 在 Marshmallow 上以编程方式安装 APK

android - 无法从 View 转换到复选框

android - 在 Fragment 中锁定屏幕时应用程序崩溃

android - SwipeRefreshLayout Got Action_Move 卡住 View

android - 在不弹出的情况下清除 Android Fragment 返回堆栈?

android - 添加媒体路由器转换按钮时出错

android - 如何从 <include> 布局文件中访问元素,该文件不是 Activity 而是 fragment ?

android-layout - 影响工具栏样式和定位的抽屉导航片段