因为是基于项目而不是一个小demo来介绍Fragment之间如何通信的,特此提醒。

你只需要关注以下几个地方:

1、宿主Activity是如何showFragment的(方式1和方式2有区别)

2、每个Fragment定义了什么接口行为,这些接口行为在哪里触发回调,是Fragment还是Activity实现了该回调,是Fragment之间互相设置回调(方式1)还是通过Activity来中转(方式2)

3、方式1其实是不建议这样去实现,只是为了形成与方式2的对比,因为两个Fragment之间是不建议直接进行通信的

4、为了重用Fragment UI 组件,在设计中你应该通过定义每一个fragemnt自己的layout和行为,让fragment的自包含和模块化。一旦你定义了这些可重用的Fragment,你可以通过Activity将它们关联起来并通过程序的逻辑代码将他们连接起来以实现整体组合的UI(这其实就是方式2的逻辑,完全由宿主Activity掌控)。

5、觉得有用的同学可以自己提取一下方式2的实现,自己搞一个小demo或者应用到项目中,实践出真知

6、除了这两种实现方式,还有别的更好的方法的朋友,欢迎指正。

入正题,因为项目代码比较长,我只是截取了与该课题相关的部分代码。

我们先来看第一种实现方式:

1、RecordActivity:

public class RecordActivity extends BaseActivity implements SoftKeyBoardStateListener{
    
    private static final String TAG = "LiveRecordsActivity";    ...
    private void showFragment() {
        hidenLoadingDialog();
        if(SDCardUtil.getSdcardAvailableSpace()< 50.0*1024*1024){
            ToastUtils.toast(this, R.string.space_not_enough);
            finish();
            return;
        };
        
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        recordPlayerFragment = new RecordPlayerFragment(mRoom, mType, facing);
        recordfragment = new RecordFragment(mRoom, mType, facing);
        //通过两者之间的回调进行通信
        recordPlayerFragment.setCallback(recordfragment);
        recordfragment.setCallback(recordPlayerFragment);
        //看这里
        transaction.add(R.id.rl_live_records_detail_content, recordPlayerFragment);
        transaction.add(R.id.rl_live_records_detail_content, recordfragment);
        
        transaction.commit();
        registerNetWorkReceiver();
    }
   ...
}

2、RecordFragment:

实现RecordPlayerCallback接口

public class RecordFragment extends LiveRecordsFragment implements RecordPlayerCallback{
    
    private static final String TAG = "RecordFragment";
    
    private int facing = Camera.CameraInfo.CAMERA_FACING_BACK; //前置摄像头还是后置摄像头
    
    private boolean canChangeCamera = false;
    
    private CameraChangeCallback callback;
    
    public void setCallback(CameraChangeCallback callback) {
        this.callback = callback;
    }


    public RecordFragment(LiveRoom room, LiveRecordsType type, int facing) {
        super(room, type);
        this.facing = facing;
    }
    
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
    
    @Override
    public void onPause() {
        super.onPause();
        if(isClosedAlready){
            return;
        }
        LogHelper.i(TAG, "whb --------------onPause() 2");
        //当页面不可见时,关闭房间
        leaveRoom(mRoomID);
        LogHelper.i(TAG, "whb --------------onPause() end");
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
    }
    
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        LogHelper.i(TAG, "-----------onCreateView");
        View rootView = super.onCreateView(inflater, container, savedInstanceState);
        initUI();
        return rootView;
    }
    
    
    private void initUI() {
        initCameras();
    }
    
    private void initCameras() {
        if (!CameraUtil.canSwitchCameras()) {
            changeCameraBtn.setVisibility(View.GONE);
        }
    }


    /**
     * 根据采集过程中出现的问题显示不同的loading
     * @see com.storm.durian.fragments.RecordPlayerFragment.RecordPlayerCallback#showLoadingViewCallback(int, int)
     */
    @Override
    public void showLoadingViewCallback(int loadTextStringId, int resId) {
        
        showLoadingView(loadTextStringId, resId);
    }


    /**
     * 停止采集的时候取消定时器
     * @see com.storm.durian.fragments.RecordPlayerFragment.RecordPlayerCallback#cancelTimerCallback()
     */
    @Override
    public void stopRecordCallback() {
        cancelTimer();
        
    }
    
    /**
     * 用户点击切换摄像头.
     * @see com.storm.durian.fragments.LiveRecordsFragment#changeCamera()
     */
    @Override
    protected void changeCamera() {
        super.changeCamera();
        LogHelper.e(TAG, "changeCamera  canChangeCamera = "+canChangeCamera);
        
            if (callback != null) {
                callback.changeCameraFace();
            }
         
    }

    /**
     * Function: 当点击切换摄像头时触发
     * date: 2015年9月18日 下午4:04:54
     */
    public interface CameraChangeCallback{
        public void changeCameraFace();
        
    }

}

3、RecordPlayerFragment

实现CamerChangeCallback接口

public class RecordPlayerFragment extends BaseFragment implements RenderListen,CameraChangeCallback {
    
    private static final String TAG = "RecordPlayerFragment";
    
    private RecordPlayerCallback callback;
    
    public void setCallback(RecordPlayerCallback callback) {
        this.callback = callback;
    }

    public RecordPlayerFragment(LiveRoom room, LiveRecordsType type, int facing) {
        this.facing = facing;
        this.mRoom = room;
    }
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        LogHelper.i(TAG, "-----------onCreateView");
        View rootView = inflater.inflate(R.layout.fragment_record_player, null);
        //initView(rootView);
        initUI(rootView);
        return rootView;
    }
    
    /**
     * 开始采集
     */
    public void startRecord(){
    ... 
    }

    /**
     * 停止采集
     */
    public void stopRecord(){
        // 停止机器人策略和录播的时间
        if (callback != null) {
            callback.stopRecordCallback();
        }
    ...
    }
    
    public void endPlayAndCapture(){
        stopRecord();
    }
    
    
    private void restartRecord(){
        ToastUtils.toastDebug(getActivity(), "重新启动采集");
        stopRecord();
        startRecord();
    }
    
    private void onCaptureError(int MsgId, String info){
        ToastUtils.toastDebug(getActivity(), "采集错误 "+info);
        if (callback != null) {
            callback.showLoadingViewCallback(R.string.p2p_start_fail, R.drawable.ic_net_error);
        }
        stopRecord();
    }
    
    private void onUploadInfo(int upload_info, int time) {
        String strInfo;
        int erroInfoId = R.string.p2p_upload_fail;
        switch (upload_info) {
        
        }
        ToastUtils.toastDebug(getActivity(), strInfo);
        if (callback != null) {
            callback.showLoadingViewCallback(erroInfoId, R.drawable.ic_net_error);
        }
        // stop
        stopRecord();
    }
   
    /**
     * 当点击切换摄像头时触发
     * @see com.storm.durian.fragments.RecordFragment.CameraChangeCallback#changeCameraFace()
     */
    @Override
    public void changeCameraFace() {
        if(canChangeCamera){
            int otherFacing = facing;
            if (facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                otherFacing = Camera.CameraInfo.CAMERA_FACING_FRONT;
            } else {
                otherFacing = Camera.CameraInfo.CAMERA_FACING_BACK;
            }

            CameraSettings settings = CameraUtil.getCameraSettingsByFacing(otherFacing);
            if (settings == null) {
                return;
            }
            capturePlayer.switchCamera(settings.getCameraId());
            facing = otherFacing;
            canChangeCamera = false;
        }        
    }
    
    
    /**
     * Function: 需要回调到RecordFragment中的方法
     * date: 2015年9月18日 下午4:08:18
     */
    public interface RecordPlayerCallback{
        //根据采集过程中出现的问题显示不同的loading
        public void showLoadingViewCallback(int loadTextStringId, int resId);
        //停止采集
        public void stopRecordCallback();
        
    }
    
}

总结一下第一种实现方式吧

第一步:创建出RecordFragment和RecordPlayerFragment的实例,然后分别设置对方为自己的回调对象

即:

//通过两者之间的回调进行通信
        recordPlayerFragment.setCallback(recordfragment);
        recordfragment.setCallback(recordPlayerFragment);

第二步:在RecordFragment中定义自己的行为接口

即:当我们触发CamerChangeCallback回调的时候通过changeCameraFace()方法告诉RecordPlayerFragment收到回调应该做什么事

public interface CameraChangeCallback{
        public void changeCameraFace();
        
    }

第三步:在RecordPlayerFragment中定义自己的行为接口

即:当我们触发RecordPlayerCallback回调的时候通过showLoadingViewCallBack()方法和stopRecordCallback()方法告诉RecordFragment收到回调应该做什么事

public interface RecordPlayerCallback{
        //根据采集过程中出现的问题显示不同的loading
        public void showLoadingViewCallback(int loadTextStringId, int resId);
        //停止采集
        public void stopRecordCallback();
        
    }

第四步:分别让RecordFragment实现RecordPlayerCallback接口以及让RecordPlayerFragment实现CameraChangeCallback接口


第五步:在各自的回调当中分别处理各自的事情

第二种实现方式

还是在RecordActivity中:

private void showFragment() {      
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        recordPlayerFragment = new RecordPlayerFragment(mRoom, mType, facing);
        recordfragment = new RecordFragment(mRoom, mType, facing);
        //通过两者之间的回调进行通信
        //recordPlayerFragment.setCallback(recordfragment);
        //recordfragment.setCallback(recordPlayerFragment);
        
        transaction.add(R.id.rl_live_records_detail_content, recordPlayerFragment,"record_player_fragment");
        transaction.add(R.id.rl_live_records_detail_content, recordfragment,"record_fragment");
        
        transaction.commit();
        registerNetWorkReceiver();
    }

这里我们给RecordFragment和RecordPlayerFragment分别打上了标签,即record_fragment和record_player_fragment,方便之后通过findFragmentByTag找到相应的Fragment,如果你的实现方式可以通过id区分,也可以通过使用findFragmentById

这里我们允许Fragment与它所Attach的Activity进行通信,我们在RecordFragment和RecordPlayerFragment定义的接口在Activity中实现,Fragment在onAttach()回调函数中获取接口的具体实现的对象,然后,fragment就可以调用接口中的方法实现与Activity的通信

public class RecordActivity extends BaseActivity implements RecordFragment.CameraChangeCallback,RecordPlayerFragment.RecordPlayerCallback{
    
    private RecordFragment recordfragment;
    
    private RecordPlayerFragment recordPlayerFragment;

    
    private void showFragment() {
       
    }

    /**
     * 当点击切换摄像头时触发
     * @see com.storm.durian.fragments.RecordFragment.CameraChangeCallback#changeCameraFace()
     */
    @Override
    public void changeCameraFace() {
        RecordPlayerFragment recordPlayerFrag = (RecordPlayerFragment)
                getSupportFragmentManager().findFragmentByTag("record_player_fragment");
        if(recordPlayerFrag != null){
            recordPlayerFrag.changeCameraFace();
        }
    }

    /**
     * 根据采集过程中出现的问题显示不同的loading
     * @see com.storm.durian.fragments.RecordPlayerFragment.RecordPlayerCallback#showLoadingViewCallback(int, int)
     */
    @Override
    public void showLoadingViewCallback(int loadTextStringId, int resId) {
        RecordFragment recordFrag = (RecordFragment)
                getSupportFragmentManager().findFragmentByTag("record_fragment");
        if(recordFrag != null){
            recordFrag.showLoadingViews(loadTextStringId, resId);
        }
    }

    /**
     * TODO 停止采集的时候取消定时器.
     * @see com.storm.durian.fragments.RecordPlayerFragment.RecordPlayerCallback#stopRecordCallback()
     */
    @Override
    public void stopRecordCallback() {
        RecordFragment recordFrag = (RecordFragment)
                getSupportFragmentManager().findFragmentByTag("record_fragment");
        if(recordFrag != null){
            recordFrag.stopRecord();
        }
    }
}

宿主Activity可以通过调用findFragmentByTag方法获取Fragment实例,然后直接调用Fragment的公有方法,将消息传递给Fragment。


public class RecordFragment extends LiveRecordsFragment{
    
    private static final String TAG = "RecordFragment";
    
    private int facing = Camera.CameraInfo.CAMERA_FACING_BACK; //前置摄像头还是后置摄像头
    
    private boolean canChangeCamera = false;
    
    private CameraChangeCallback mCallback;
    
    public void setCallback(CameraChangeCallback callback) {
        this.mCallback = callback;
    }


    public RecordFragment(LiveRoom room, LiveRecordsType type, int facing) {
        super(room, type);
        this.facing = facing;
    }
    
    
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
     // 这是为了保证Activity容器实现了用以回调的接口。如果没有,它会抛出一个异常。
        try {
            mCallback = (CameraChangeCallback) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement CameraChangeCallback");
        }
    }
   


    /**
     * 根据采集过程中出现的问题显示不同的loading
     */
    public void showLoadingViews(int loadTextStringId, int resId) {
        
        showLoadingView(loadTextStringId, resId);
    }


    /**
     * 停止采集的时候取消定时器
     */
    public void stopRecord() {
        cancelTimer();
        
    }
    
    /**
     * 用户点击切换摄像头.
     */
    @Override
    protected void changeCamera() {
        super.changeCamera();
        LogHelper.e(TAG, "changeCamera  canChangeCamera = "+canChangeCamera);
        
            if (mCallback != null) {
                mCallback.changeCameraFace();
            }
         
    }

    /**
     * Function: 当点击切换摄像头时触发
     * date: 2015年9月18日 下午4:04:54
     */
    public interface CameraChangeCallback{
        public void changeCameraFace();
        
    }

}
public class RecordPlayerFragment extends BaseFragment implements RenderListen{
    
    private static final String TAG = "RecordPlayerFragment";
    
    private RecordPlayerCallback mCallback;
    
    public void setCallback(RecordPlayerCallback callback) {
        this.mCallback = callback;
    }

    public RecordPlayerFragment(LiveRoom room, LiveRecordsType type, int facing) {
        this.facing = facing;
        this.mRoom = room;
    }
    
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
     // 这是为了保证Activity容器实现了用以回调的接口。如果没有,它会抛出一个异常。
        try {
            mCallback = (RecordPlayerCallback) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement RecordPlayerCallback");
        }
    }
    
    @Override
   
    public void stopRecord(){
        // 停止机器人策略和录播的时间
        if (mCallback != null) {
            mCallback.stopRecordCallback();
        }
        capturePlayer.captureDone();
        canChangeCamera = false;
        LogHelper.e(TAG, "LiveHandler  canChangeCamera = "+canChangeCamera);
    }
  
    private void onCaptureError(int MsgId, String info){
        ToastUtils.toastDebug(getActivity(), "采集错误 "+info);
       // showLoadingView(R.string.p2p_start_fail, R.drawable.ic_net_error);
        if (mCallback != null) {
            mCallback.showLoadingViewCallback(R.string.p2p_start_fail, R.drawable.ic_net_error);
        }
        stopRecord();
    }
    
    private void onUploadInfo(int upload_info, int time) {
        String strInfo;
        int erroInfoId = R.string.p2p_upload_fail;
        switch (upload_info) {}
        ToastUtils.toastDebug(getActivity(), strInfo);
        if (mCallback != null) {
            mCallback.showLoadingViewCallback(erroInfoId, R.drawable.ic_net_error);
        }
        // stop
        stopRecord();
    }
    

    /**
     * 当点击切换摄像头时触发
     */
    public void changeCameraFace() {
        if(canChangeCamera){
            int otherFacing = facing;
            if (facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                otherFacing = Camera.CameraInfo.CAMERA_FACING_FRONT;
            } else {
                otherFacing = Camera.CameraInfo.CAMERA_FACING_BACK;
            }

            CameraSettings settings = CameraUtil.getCameraSettingsByFacing(otherFacing);
            if (settings == null) {
                return;
            }
            capturePlayer.switchCamera(settings.getCameraId());
            facing = otherFacing;
            canChangeCamera = false;
        }        
    }
    
    
    /**
     * Function: 需要回调到RecordFragment中的方法
     * date: 2015年9月18日 下午4:08:18
     */
    public interface RecordPlayerCallback{
        //根据采集过程中出现的问题显示不同的loading
        public void showLoadingViewCallback(int loadTextStringId, int resId);
        //停止采集
        public void stopRecordCallback();
        
    }
    
}

整体看来,第二种方式将所有的控制都交给了宿主Activity,通过Activity实现Fragment当中定义的各种接口,然后通过回调的方式来处理Activity与Fragment之间的通信,以及通过Activity获取Fragment实例并调用Fragment共有方法的方式实现Fragment之间的通信