【问题标题】:Comunicattion between fragments片段之间的通信
【发布时间】:2015-01-24 04:57:02
【问题描述】:

我正在创建一个应用程序,但我对如何在片段之间进行通信有疑问,我知道我必须与父 Activity 进行通信等等,我的问题更倾向于最佳实践。我的应用程序由一个带有导航抽屉的 MainActivity 组成,它根据选择调用一个片段并将其放在主屏幕上。 我有 2 个片段,需要通过一个按钮调用另一个片段(我可以毫无问题地将其转换为活动)打开相机扫描条形码(BarScanFragment)(https://github.com/dm77/barcodescanner)。

我的问题是可以知道哪个片段称为 BarScanFragment,以便我可以将参数发送到正确的片段,以及如何实现它。

BarScanFragment.java

public class BarScanFragment extends Fragment implements  ZXingScannerView.ResultHandler{
    private ZXingScannerView mScannerView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mScannerView = new ZXingScannerView(getActivity());
        return mScannerView;
    }

    @Override
    public void onResume() {
        super.onResume();
        mScannerView.setResultHandler(this);
        mScannerView.startCamera();
    }

    @Override
    public void onPause() {
        super.onPause();
        mScannerView.stopCamera();

    }

    @Override
    public void handleResult(Result result) {
        Log.i("TAG", result.getText());
        Bundle args = new Bundle();
        args.putString("barcodeScan", result.getText());
    }

FragmentA.java

…… ......

barcodeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Fragment content = new BarScanFragment();
                FragmentManager fragmentManager = getFragmentManager();
                fragmentManager.beginTransaction()
                        .replace(R.id.flFragmentContainer, content).addToBackStack("TRADEIN")
                        .commit();
                /*Intent intent = new Intent(rootView.getContext(), BarcodeScannerActivity.class);
                startActivity(intent);*/
            }
        });

片段 b.java

.....
.....
 barcodeButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Fragment content = new BarScanFragment();
                    FragmentManager fragmentManager = getFragmentManager();
                    fragmentManager.beginTransaction()
                            .replace(R.id.flFragmentContainer, content).addToBackStack("INFOPRODUCT")
                            .commit();
                    /*Intent intent = new Intent(rootView.getContext(), BarcodeScannerActivity.class);
                    startActivity(intent);*/
                }
            });

【问题讨论】:

  • 您使用的是android.app.Fragment 而不是android.app.supportv4.Fragment?很有趣。
  • 该项目是针对非常特定的设备,所以我的目标是 minSdkVersion=14,我不需要使用支持库
  • 按钮监听器是否知道哪个片段正在创建 BarScanFragment?
  • @user3249477,每个片段都有自己的按钮和自己的按钮监听器

标签: android android-fragments


【解决方案1】:

看看setTargetFragmentgetTargetFragment。这是片段之间来回通信的最简单方法。 这里有一个小例子https://github.com/alexfu/TargetFragmentExample

【讨论】:

  • 这比回调更容易实现,您的答案和 Oleg Osipenko 的答案中是否有任何性能优缺点
  • 我会接受这个答案,因为它更容易实现,奥列格的答案也很有效。谢谢。
  • Oleg Osipenko 的回答也很好。因此,Fragment 并不总是与单个 Activity 相关;因此,对于每个使用 Fragment 的 Activity,您必须实现这两个接口。相反,set/getTargetFragment 方法属于 Android 框架,需要用于此方法。有了它们,您不必重新发明*。
【解决方案2】:

你可以给BarScanFragment的构造函数添加一个参数:

public BarScanFragment(int creatorFragment) {
    // Do something with creatorFragment
}

在您的活动中保存“creatorFragment”值:

public static final int FRAGMENT_1 = 0;
public static final int FRAGMENT_2 = 1;

然后在您的按钮侦听器中创建具有特定值的 BarScanFragment:

Fragment content = new BarScanFragment(MainActivity.FRAGMENT_1);

Fragment content = new BarScanFragment(MainActivity.FRAGMENT_2);

【讨论】:

    【解决方案3】:

    在您的活动中声明回调并使用这些回调从另一个片段调用方法

    public interface Callback1 {
        void callbackMethod1();
    }
    
    public interface Callback2 {
        void callbackMethod2();
    }
    
    public class Activity extends ActionBarActivity implements Callback1, Callback2 {
    
        Fragment1 mFragment1;
        Fragment2 mFragment2;
    
        @Override
        public void callbackMethod1() {
            mFragment2.method2();
        }
    
        @Override
        public void callbackMethod2() {
            mFragment1.method1();
        }
    }
    
    public class Fragment1 extends Fragment {
        Callback1 callback;
    
        @Override
        public void onAttach(android.app.Activity activity) {
            super.onAttach(activity);
            callback = (Callback1) getActivity();
        }
    
        void callMethodOfFragment1() {
            callback.callbackMethod1();
        }
    
        @Override
        public void onDetach() {
            super.onDetach();
            callback = null;
        }
    
        public void method1() {
            do_sth_in_fr2();
        }
    }
    
    public class Fragment2 extends Fragment {
        Callback2 callback;
    
        @Override
        public void onAttach(android.app.Activity activity) {
            super.onAttach(activity);
            callback = (Callback2) getActivity();
        }
    
        void callMethodOfFragment2() {
            callback.callbackMethod2();
        }
    
        @Override
        public void onDetach() {
            super.onDetach();
            callback = null;
        }
    
        public void method2() {
            do_sth_in_fr1();
        }
    }
    

    【讨论】:

    • 如果您仔细查看您的示例和我的代码,您会发现两个活动都实现了一个接口,并且片段调用该接口的方法以从片段到活动进行通信。所以这就是区别,这就是为什么不赞成我的答案?
    • @OlegOsipenko 嗨,您能否详细说明一下活动必须如何响应,因为 mFragment2.method 没有告诉我任何信息,我不知道如何知道要响应哪个片段,因为2 个片段可以调用同一个扫描片段,并且所有内容都在同一个片段容器中。
    • 我刚刚编辑了我的答案,因此两个片段之间可以通过 Kristy Welsh 建议的接口通过活动进行通信
    • @OlegOsipenko 您的回答效果很好,我赞成,我已经尝试过 Dekra 的回答,它也可以工作,而且实施起来更容易一些,在 2 中是否有任何性能优点或缺点你和 Dekra 的方法?