最新Androidx Fragment的前世今生系列(三)之Fragment与Acivity的通信

753 阅读3分钟

背景

前两篇文章,我们已经了解了Fragment的基本使用以及Fragment生命周期,今天我们来看一下Fragment与Activity之间是如何通信,其中包括Activity向Fragment发消息,以及Fragment如何向Activity发消息。通信的方式有很多种,包括广播,Eventbus等,我们今天就介绍其中用的最为广泛的两种方式。

Activity向Fragment传递消息。

在我们使用Fragment进行初始化的时候可能需要传递参数,从而使用带参的构造函数,然而这是一件十分危险的事情,官网的说法如下

All subclasses of Fragment must include a public no-argument constructor. The framework will often re-instantiate a fragment class when needed, in particular during state restore, and needs to be able to find this constructor to instantiate it. If the no-argument constructor is not available, a runtime exception will occur in some cases during state restore.

当Fragment由于某些原因,比如说屏幕翻转,导致Fragment被销毁需要重建的时候,会调用onCreate()方法获取之前的状态,然后调用无参的构造函数取重建Fragment,所以如果没有无参的构造函数就会发生异常。可以使用getArguments通过Bundle去避免这个问题。

我们还是使用之前的例子如下图 其中中间是一个FrameLayout,下面是两个按钮,分别控制FragmentOne和FragmentTwo,两个Fragment中都有一个textiew,现在我们需要Activity将文本传递给Fragment并在textiew显示。 关键代码如下

  FragmentTransaction transaction = fm.beginTransaction();
                Bundle bundle = new Bundle();
                bundle.putString("message", "这是Activity传递给FragmentOne的消息!!!");
                FragmentOne fragmentOne = new FragmentOne();
                fragmentOne.setArguments(bundle);
                transaction.replace(R.id.content, fragmentOne);
                transaction.addToBackStack(null);
                transaction.commit();

首先创建Bundle,然后加入数据,最后通过setArguments()方法将bundle传递给Fragment。 然后在Fragment onCreate()中通过getArguments获取bundle,关键代码如下

 @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       if(getArguments() != null) {
           string = getArguments().getString("message");
       }
    }

效果如图

Fragment 向Activity传递消息

Fragment向Activity传递消息可以通过回调来实现,我们在之前的例子中修改,在FragmentOne中增加一个editText 和一个button,通过button将editText的内容传递给Acitivity,然后显示在Actionbar上。

FragmentOne代码如下

public class FragmentOne extends Fragment {
    private String string;
    private EditText editText;
    private Button button;
    private CallBack callBack;
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_one, container, false);
        editText = view.findViewById(R.id.et);
        button = view.findViewById(R.id.button3);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String s = editText.getText().toString();
                callBack.changTitle(s);
            }
        });
        return view;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if(context instanceof CallBack) this.callBack = (CallBack) context;
    }
}

 interface CallBack{
    void changTitle(String string);
}

首先建立一个Callback的接口,在Fragment中声明,在onAttach中实例化callback,监听button,获取EditText的值传给changeTitle。然后在Activity中实现这个接口,重写changitle方法,Activity代码如下

public class MainActivity extends AppCompatActivity implements CallBack{
    private FragmentManager fm;
    private String string;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("TEST","Activity creating");
        setContentView(R.layout.activity_main2);
        fm = getSupportFragmentManager();


        fm = getSupportFragmentManager();
        FragmentTransaction transaction = fm.beginTransaction();
        transaction.add(R.id.content, new FragmentOne());
        transaction.addToBackStack(null);
        transaction.commit();
    }

    @Override
    public void changTitle(String string) {
        ActionBar actionBar = getSupportActionBar();
        actionBar.setTitle(string);
    }
}

在changTitle中获取从Fragment传过来的字符串然后设置标题。 效果如下

最后

Fragment与Fragment可以通过上述方法结合实现,也可以通过ViewModel实现,这个在以后JetPack的专栏文章在详细介绍。