(6)Fragment与Activity通信

来源:互联网 发布:家居设计用什么软件 编辑:程序博客网 时间:2024/06/05 15:55

1.归纳

因为所有的Fragment都是依附于Activity的,所以通信起来并不复杂,大概归纳为:
a、如果你Activity中包含自己管理的Fragment的引用,可以通过引用直接访问所有的Fragment的public方法
b、如果Activity中未保存任何Fragment的引用,那么没关系,每个Fragment都有一个唯一的TAG或者ID,可以通过getFragmentManager.findFragmentByTag()或者findFragmentById()获得任何Fragment实例,然后进行操作。
c、在Fragment中可以通过getActivity得到当前绑定的Activity的实例,然后进行操作。
注:如果在Fragment中需要Context,可以通过调用getActivity(),如果该Context需要在Activity被销毁后还存在,则使用getActivity().getApplicationContext()。

2.实践

因为要考虑Fragment的重复使用,所以必须降低Fragment与Activity的耦合,而且Fragment更不应该直接操作别的Fragment,毕竟Fragment操作应该由它的管理者Activity来决定。
下面我通过两种方式的代码,分别重构,FragmentOne和FragmentTwo的点击事件,以及Activity对点击事件的响应:
首先看FragmentOne
package xzy.com.myfragmentdemo.communication;import android.app.Fragment;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.Button;import xzy.com.myfragmentdemo.R;/** * A simple {@link Fragment} subclass. */public class FragmentOne extends Fragment implements View.OnClickListener {    private Button mButton1;    public FragmentOne() {    }    /**     * 设置按钮点击的回调     */    public interface FOneBtnClickListener {        void fOneBtnClick();    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        View view = inflater.inflate(R.layout.fragment_fragment_one, container, false);        mButton1 = (Button) view.findViewById(R.id.btn_goto_fragment2);        mButton1.setOnClickListener(this);        return view;    }    /**     * 交给宿主处理     *     * @param v     */    @Override    public void onClick(View v) {        if (getActivity() instanceof FOneBtnClickListener) {            ((FOneBtnClickListener) getActivity()).fOneBtnClick();        }    }}
可以看到现在的FragmentOne不和任何Activity耦合,任何Activity都可以使用;并且我们声明了一个接口,来回调其点击事件,想要管理其点击事件的Activity实现此接口就即可。可以看到我们在onClick中首先判断了当前绑定的Activity是否实现了该接口,如果实现了则调用。
再看FragmentTwo
package xzy.com.myfragmentdemo.communication;import android.app.Fragment;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.Button;import xzy.com.myfragmentdemo.R;/** * A simple {@link Fragment} subclass. */public class FragmentTwo extends Fragment implements View.OnClickListener {    private Button mButton2;    public FragmentTwo() {    }    private FTwoBtnClickListener fTwoBtnClickListener;    public interface FTwoBtnClickListener {        void onFTwoBtnClick();    }    //设置回调接口    public void setfTwoBtnClickListener(FTwoBtnClickListener fTwoBtnClickListener) {        this.fTwoBtnClickListener = fTwoBtnClickListener;    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        // Inflate the layout for this fragment        View view = inflater.inflate(R.layout.fragment_fragment_two, container, false);        mButton2 = (Button)view.findViewById(R.id.btn_goto_fragment3);        mButton2.setOnClickListener(this);        return view;    }    @Override    public void onClick(View v) {        if (fTwoBtnClickListener != null) {            fTwoBtnClickListener.onFTwoBtnClick();        }    }}
与FragmentOne极其类似,但是我们提供了setListener这样的方法,意味着Activity不仅需要实现该接口,还必须显示调用mFTwo.setfTwoBtnClickListener(this)。
最后看Activity :

package xzy.com.myfragmentdemo.communication;import android.app.Activity;import android.app.FragmentManager;import android.app.FragmentTransaction;import android.content.Context;import android.content.Intent;import android.os.Bundle;import xzy.com.myfragmentdemo.R;public class FragmentCommunicationActivity extends Activity implements FragmentOne.FOneBtnClickListener, FragmentTwo.FTwoBtnClickListener {    private FragmentOne mFragmentOne;    private FragmentTwo mFragmentTwo;    private FragmentThree mFragmentThree;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_fragment_communication);        initPage();    }    public void initPage() {        mFragmentOne = new FragmentOne();        FragmentManager fragmentManager = getFragmentManager();        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();        fragmentTransaction.add(R.id.fl_content, mFragmentOne);        fragmentTransaction.commit();    }    public static void startActivity(Context context) {        Intent intent = new Intent(context, FragmentCommunicationActivity.class);        context.startActivity(intent);    }    /**     * FragmentOne按钮点击时回调     */    @Override    public void fOneBtnClick() {        if (mFragmentTwo == null) {            mFragmentTwo = new FragmentTwo();            mFragmentTwo.setfTwoBtnClickListener(this);        }        android.app.FragmentTransaction ft = getFragmentManager().beginTransaction();        ft.replace(R.id.fl_content, mFragmentTwo);        ft.addToBackStack(null);//添加到回退栈        ft.commit();    }    /**     * FragmentTwo按钮点击时回调     */    @Override    public void onFTwoBtnClick() {        if (mFragmentThree == null) {            mFragmentThree = new FragmentThree();        }        android.app.FragmentTransaction ft = getFragmentManager().beginTransaction();        ft.hide(mFragmentTwo);        ft.add(R.id.fl_content, mFragmentThree);        //ft.replace(R.id.fl_content,fragmentThree);        ft.addToBackStack(null);//添加到回退栈        ft.commit();    }}
代码重构结束,与开始的效果一模一样。上面两种通信方式都是值得推荐的,随便选择一种自己喜欢的。这里再提一下:虽然Fragment和Activity可以通过getActivity与findFragmentByTag或者findFragmentById,进行任何操作,甚至在Fragment里面操作另外的Fragment,但是没有特殊理由是绝对不提倡的。Activity担任的是Fragment间类似总线一样的角色,应当由它决定Fragment如何操作。另外虽然Fragment不能响应Intent打开,但是Activity可以,Activity可以接收Intent,然后根据参数判断显示哪个Fragment。

本文转载自http://blog.csdn.net/lmj623565791/article/details/37992017