【Android】Activity与Fragment的数据传递

上一篇文章学到了碎片的创建与生命周期,接下来学习碎片的常用操作,其中会用到上一篇文章的三个碎片,就做一个简单的说明吧:LeftFragment(包含一个按钮)、RightFragment4(以粉色为背景的文本,并在这个碎片中写了所有的回调方法)、AnotherRightFragment(以紫色为背景的文本)

FragementManager

每一个Activity都有一个Fragement Manager,用来管理它所包含的Fragement,在使用支持库的时候,使用getSupport-FragmentManager方法来访问Fragement Manager

添加Fragement到Activity中

知识点部分

Fragment的添加

在上一篇当中提到动态地添加碎片,使用是replace()方法,但它其实是碎片的替换方法替换当前的 Fragment 为一个新的 Fragment。真正的添加方法为add()。在一个容器当中可以添加多个Fragment,它们依次盖在上面,类似于FrameLayout。

Fragment的查找

删除与替换的前提都是这个碎片先找到,此时我们使用fragmentManager.findFragmentById(R.id.fcv)fragmentManager.findFragmentByTag("hhh"),根据这两个方法查找到最上面的一个,如果没有,则从BackStack里找,并返回最先添加的一个,如果没有,返回null

Fragment的移除

fragmentTransaction.remove(fragment).commit()方法移除,依次移除当前容器最上面的一个Fragment,但只是将其从容器中移除,backStack里仍然存在,使用查找方法仍可以找到,只不过它的状态是不可见的,需要按下返回键才能彻底移除

Fragment的替换

fragmentTransaction.replace(R.id.fcv, LeftFragment.class, null)当没有addToBackStack会将容器上的所有碎片进行移除,添加新的Fragment。此时BackStack里的Fragment仍然存在,按下返回键依然会响应到BackStack,即弹出BackStack里的Fragment,此时我们看到的是替换的碎片,但是看着好像什么都没有发生。

Fragment的显示与隐藏

show、hide:只是把Fragment显示/隐藏,Fragment的生命周期不发生变化,相当于View的显示/隐藏

attach、detach:把Fragment从容器中移除/装载,Fragment的生命周期发生变化,执行到onDestroyView,其View被销毁,但Fragment仍存在

体验

接下来就体验一下吧:

首先我们创建一个新的活动,其中我们在布局里面放入一个碎片容器以及各种操作的按钮,布局文件代码:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".FragmentAdd"><androidx.fragment.app.FragmentContainerViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="10dp"android:id="@+id/fcv"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:id="@+id/add1"android:text="add1"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:id="@+id/add2"android:text="add2"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:id="@+id/remove1"android:text="remove1"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:id="@+id/remove2"android:text="remove2"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:id="@+id/replace"android:text="replace"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:id="@+id/show"android:text="show"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:id="@+id/hide"android:text="hide"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:id="@+id/attach"android:text="attach"/><Buttonandroid:id="@+id/detach"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="detach" /></LinearLayout>

主要是在主活动里的代码:

public class FragmentAdd extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);EdgeToEdge.enable(this);setContentView(R.layout.activity_fragment_add);ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);return insets;});Button buttonadd1 = (Button) findViewById(R.id.add1);buttonadd1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {addFragment1(FragmentAdd.this.getCurrentFocus());}});Button buttonadd2 = (Button) findViewById(R.id.add2);buttonadd2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {addFragment2(FragmentAdd.this.getCurrentFocus());}});Button buttonremove1 = (Button) findViewById(R.id.remove1);buttonremove1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {removefragment1(FragmentAdd.this.getCurrentFocus());}});Button buttonremove2 = (Button) findViewById(R.id.remove2);buttonremove2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {removefragment2(FragmentAdd.this.getCurrentFocus());}});Button buttonreplace = (Button) findViewById(R.id.replace);buttonreplace.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {replacefragment(FragmentAdd.this.getCurrentFocus());}});Button buttonshow = (Button) findViewById(R.id.show);buttonshow.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {showfragment(FragmentAdd.this.getCurrentFocus());}});Button buttonhide = (Button) findViewById(R.id.hide);buttonhide.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {hidefragment(FragmentAdd.this.getCurrentFocus());}});Button buttonattach = (Button) findViewById(R.id.attach);buttonattach.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {attachfragment(FragmentAdd.this.getCurrentFocus());}});Button buttondetach = (Button) findViewById(R.id.detach);buttondetach.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {detachfragment(FragmentAdd.this.getCurrentFocus());}});}public void addFragment1 (View view) {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();fragmentTransaction.add(R.id.fcv, RightFragment4.class, null, "添加碎片").addToBackStack("hhh").setReorderingAllowed(true).commit();}public void addFragment2 (View view) {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();AnotherRightFragment anotherRightFragment = new AnotherRightFragment();fragmentTransaction.add(R.id.fcv, anotherRightFragment).commit();}public void removefragment1 (View view) {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();Fragment fragment = fragmentManager.findFragmentById(R.id.fcv);Log.d("查找碎片", "查找的顶端碎片" + fragment.toString());fragmentTransaction.remove(fragment).commit();}public void removefragment2 (View view) {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();Fragment fragment = fragmentManager.findFragmentByTag("添加碎片");Log.d("查找碎片", "根据Tag查早的碎片" + fragment.toString());fragmentTransaction.remove(fragment).commit();}public void replacefragment(View view) {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();fragmentTransaction.replace(R.id.fcv, LeftFragment.class, null).commit();}public void showfragment(View view) {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();Fragment fragment = fragmentManager.findFragmentById(R.id.fcv);if (fragment != null) {fragmentTransaction.show(fragment).commit();}}public void hidefragment(View view) {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();Fragment fragment = fragmentManager.findFragmentById(R.id.fcv);if (fragment != null) {fragmentTransaction.hide(fragment).commit();}}Fragment fragmenthh;public void attachfragment(View view) {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();/*Fragment fragment = fragmentManager.findFragmentById(R.id.fcv);*/if (fragmenthh != null) {fragmentTransaction.attach(fragmenthh).commit();}}public void detachfragment(View view) {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();fragmenthh = fragmentManager.findFragmentById(R.id.fcv);if (fragmenthh != null) {fragmentTransaction.detach(fragmenthh).commit();}}
}

添加:为所有的按钮注册了点击事件,两种不同的添加方式,第一种我们添加进去粉色底色的文本,按下第二个按钮就会添加进去一个紫色的文本,两种添加方式也不同,第一个添加方式采用上一篇内容的模拟返回栈内容,当你按下第一个按钮会看到这样的界面:

在这里插入图片描述

此时按下add2按钮,采用第二种方式添加碎片,界面发生了变化:

在这里插入图片描述

此时我们只能看到第二个碎片,碎片的添加方式是叠加的,此时查看到底有多少个碎片:

在这里插入图片描述

就可以看到此时共有两个碎片,在返回栈当中只有一个碎片,因为只有第一个按钮是将添加的碎片也加入到返回栈当中,此时按下Back按钮会看到页面没有发生任何的变化,此时是将返回栈当中的第一个碎片取出来,再次按下Back键,就会退出这个活动。

思考一下,如果我再次按下第一个按钮,将第一个碎片再次加入到活动当中,此时按下Back键会发生什么,按多少次Back按钮才会退出这个活动呢?

此时我们明白,返回栈当中有两个粉色的碎片,当第一次按下Back按钮,最上面的粉色碎片就会从返回栈当中移除,此时界面为紫色,之后返回栈当中就只剩下一个碎片了与上面的情况一样。因此我们一共需要按3次Back按钮才会退出活动。

**查找与删除:**我们依次添加四个碎片,此时有两个进入了栈里面,此时页面为紫色碎片的样子

在这里插入图片描述

此时按下第一个移除键,删除的是活动顶部的碎片,紫色碎片被移除,页面为粉色的碎片,查看日志的打印信息:

在这里插入图片描述

可以看到删除的就是顶部的碎片,此时按下remove2,会页面没有发生变化,但我们知道是因为有两个一样的碎片,再次按下remove2,会看到页面变回了紫色,此时查看打印日志:

在这里插入图片描述

再次按下remove1,我们知道碎片已经移除完毕了,此时页面没有任何的碎片,再次按下删除键,此时不会进行移除操作,但会去返回栈寻找最底部即第一次添加的碎片。

**替换:**重新运行程序,添加几个碎片到活动当中,此时查看含有的碎片:
在这里插入图片描述

按下replace按钮,被替换成了另一个含有按钮的碎片:

在这里插入图片描述

此时查看有多少个碎片:
在这里插入图片描述

此时可以看到活动内所有的碎片都被去除,由新的碎片替代,我们看到栈当中并未有任何的改变,栈内只能由Back键进行操作,此时活动只剩下这一个碎片。

显示与隐藏:

在上篇文章中提到我们给RightFragment4添加了回调方法,因此此处使用这个碎片,此时按下hide按钮,我们看到页面发生了变化,由粉色变为了紫色,此时打印日志并没有发生任何的变化。再次按下show按钮,粉色显示出来了,此时打印日志还是没有发生任何的变化。

接下来按下detach按钮,页面与按下hide按钮的效果相同,此时的打印日志:

在这里插入图片描述

当我们attach()的时候这个碎片必须是已经创建好的,但是未与活动创建联系,我们这里将detach的碎片记录下来,这个碎片经过detach()方法与活动解除了联系,再调用attach()方法此时刚才的碎片又显示出来了

碎片和活动之间进行通信

Activity向Fragment

通过方法传递

构造方法

首先使其自动创建一个Fragment,修改对应的布局文件,加上id,修改字体大小:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".datapass1.fragment.DataPassFragment"><TextViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:textSize="25sp"android:gravity="center"android:id="@+id/tv_content"android:text="@string/hello_blank_fragment" /></FrameLayout>

在Fragment类中进行修改,我们要通过构造方法使其传递数据,在Fragment当中有本身的无参构造,进行修改加入有参构造,并修改所对应的onViewCreated()碎片与视图建立联系的时候调用的方法,先得到视图里的TextView,再对内容进行修改,此时代码如下:

public class DataPassFragment extends Fragment {private static final String ARG_PARAM1 = "param1";private static final String ARG_PARAM2 = "param2";private String mParam1;private String mParam2;//新建要得到才对其中的内容进行修改private TextView mTextView;//加入的构造方法public DataPassFragment(String data) {mParam1 = data;}public DataPassFragment() {;}public static DataPassFragment newInstance(String param1, String param2) {DataPassFragment fragment = new DataPassFragment();Bundle args = new Bundle();args.putString(ARG_PARAM1, param1);args.putString(ARG_PARAM2, param2);fragment.setArguments(args);return fragment;}@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (getArguments() != null) {mParam1 = getArguments().getString(ARG_PARAM1);mParam2 = getArguments().getString(ARG_PARAM2)}}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {return inflater.inflate(R.layout.fragment_data_pass, container, false);}@Overridepublic void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);mTextView = view.findViewById(R.id.tv_content);if (!TextUtils.isEmpty(mParam1)) { //判断字符串不是空mTextView.setText(mParam1);}}
}

注意:我们需要在设置文字之前判断字符串是不是空的,否则无论如何都会执行修改文本的操作,当我们传入的数据为空的时候,就会出现空白的情况。碎片就修改完毕了,就需要对主活动的按钮注册点击事件了。

首先创建一个活动来存放你所要放的碎片以及你所要执行的方法的控件,此时我们需要使用构造方法传递数据

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/main"android:layout_width="match_parent"android:orientation="vertical"android:layout_height="match_parent"tools:context=".datapass1.DataPassActivity"><androidx.fragment.app.FragmentContainerViewandroid:layout_width="match_parent"android:layout_height="300dp"android:id="@+id/fcv"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:id="@+id/construct"android:text="通过构造方法传递数据"/></LinearLayout>

修改主活动的代码,记得将碎片添加进来,为按钮注册点击事件:

public class DataPassActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);EdgeToEdge.enable(this);setContentView(R.layout.activity_data_pass);ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);return insets;});//添加Fragment到布局当中getSupportFragmentManager().beginTransaction().replace(R.id.fcv, DataPassFragment.class, null).commit();Button buttonconstruct = (Button) findViewById(R.id.construct);buttonconstruct.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {passDataByConstruct(DataPassActivity.this.getCurrentFocus());}});}//通过构造方法传递数据public void passDataByConstruct (View view) {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();DataPassFragment dataPassFragment = new DataPassFragment("这是构造方法传递的数据");fragmentTransaction.replace(R.id.fcv, dataPassFragment).commit();}
}

此时页面为一开始自动创建的碎片:

在这里插入图片描述

此时运行程序,按下按钮,文本内容转换成了我们所传入的数据,对碎片进行了替换。

运行程序:

在这里插入图片描述

public方法

就是先通过查找方法找到此时的碎片,再通过调用碎片里的为字符串进行修改的方法,对其进行修改,先在主活动中注册点击事件:

Button buttoncommon = (Button) findViewById(R.id.common);
buttoncommon.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {                passDataByCommon(DataPassActivity.this.getCurrentFocus());}
});

在主活动写对应的方法:

public void passDataByCommon (View view) {FragmentManager fragmentManager = getSupportFragmentManager();Fragment fragment = fragmentManager.findFragmentById(R.id.fcv);if (fragment != null) {((DataPassFragment)fragment).setParam1("这是普通public传递的数据");}
}

此时我们调用的是碎片类里的方法setParam1(),此时需要将碎片进行强转,对应的碎片里的代码进行修改,加入以下内容:

public void setParam1 (String s) {this.mParam1 = s;if (!TextUtils.isEmpty(mParam1)) { //判断字符串不是空mTextView.setText(mParam1);}
}

之后运行程序,得到的结果为:
在这里插入图片描述

通过Argument

这是Android本身为我们提供的向Fragment传递数据的方式,可用来一次性传递复杂、大量数据。他就是将你所要传入的数据进行打包,同样的在主活动中为按钮注册点击事件,此处代码与上面一样,对于方法里的代码:

public void passDataByargument1 (View view) {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();DataPassFragment dataPassFragment = new DataPassFragment("这是argument传递的数据");Bundle bundle = new Bundle();bundle.putString("data", "这是argument传递的数据");bundle.putInt("int_data", 100);dataPassFragment.setArguments(bundle);fragmentTransaction.replace(R.id.fcv, dataPassFragment).commit();
}

我们使用bundle对所传入的数据进行打包,以键值对的形式,使用setArguments()将数据发送过去,此时在碎片类里面本身就有对应的getArguments()方法,我们根据这个与键值对对其进行数据的接收,此时需要修改对应的代码:

@Override
public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (getArguments() != null) {mParam1 = getArguments().getString(ARG_PARAM1);mParam2 = getArguments().getString(ARG_PARAM2);mData = getArguments().getString("data");mintData = getArguments().getInt("int_data");}
}

此时我们得到了所要传输的数据,这个是在第一次被创建的时候得到,之后会经历onViewCreated()碎片与视图建立联系的时候调用,因此要将代码放在此时的代码里面:

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);mTextView = view.findViewById(R.id.tv_content);if (!TextUtils.isEmpty(mParam1)) { //判断字符串不是空mTextView.setText(mParam1);}if (!TextUtils.isEmpty(mData)) {mTextView.setText(mData + mintData);}
}

其中接收传入数据的两个变量在不同的方法里面调用,因此在全局变量部分声明。运行程序,按下通过argument传递数据的按钮,此时界面变为:
在这里插入图片描述

通过接口

是一种基于编程语言自身性质的数据通信方式。当数据由A传到B的时候,A就为被观察者,B为观察者,此时我们向有一个角色可以将A所发生的变化告诉B,这个角色就为接口所承担。一般情况下,谁被观察就写在谁的内部。

同样地我们在主活动的界面对按钮进行点击事件的注册,主活动的代码修改如下:

public void passDataByInterface (View view) {mDataChangeListener.onDataChange("这是通过接口传递的数据");
}private onDataChangeListener mDataChangeListener;public void setmDataChangeListener(onDataChangeListener DataChangeListener) {mDataChangeListener = DataChangeListener;
}//这个就是数据传输的接口
public interface onDataChangeListener {void onDataChange(String data);
}

定义接口(Interface)onDataChangeListener 是一个接口,它定义了一个方法 onDataChange(String data)

接口成员变量mDataChangeListener 是一个接口类型的成员变量,用于存储实现了 onDataChangeListener 接口的对象的引用。

设置接口的引用setmDataChangeListener 是一个公共方法,它接受一个实现了 onDataChangeListener 接口的对象作为参数,并将这个对象赋值给 mDataChangeListener 变量。

调用接口方法passDataByInterface 方法通过调用 mDataChangeListeneronDataChange 方法来传递数据。

碎片类的代码修改:

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);mTextView = view.findViewById(R.id.tv_content);if (!TextUtils.isEmpty(mParam1)) { //判断字符串不是空mTextView.setText(mParam1);}if (!TextUtils.isEmpty(mData)) {mTextView.setText(mData + mintData);}((DataPassActivity)getActivity()).setmDataChangeListener(new DataPassActivity.onDataChangeListener() {@Overridepublic void onDataChange(String data) {if (!TextUtils.isEmpty(data)) {mTextView.setText(data);}}});
}

在碎片当中就有自己的方法得到所在的活动getActivity(),我们要用活动里的其他方法,因此先对其进行强转,之后的操作与Button按钮注册点击事件一样,重写里面所对应的方法。

此时运行程序:

在这里插入图片描述

Fragment向Activity

通过getActivity

每个Fragment都可以通过getActivity()方法获取承载它的活动对象,从而调用活动的方法向活动传递数据。因此我们可以在碎片里面获取到活动,从而使用活动里的方法为活动传入数据,在活动当中设置一个TextView,用来显示传入的数据:

<TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:textAllCaps="false"android:textSize="20sp"android:text="还没有传入数据!!!"android:gravity="center"android:id="@+id/tv_reveive"/>

主活动当中写为TextView设置文本内容的方法:

public void setReceive (String data) {tvreceive.setText(data);
}

接下来就需要在碎片里面设置一个按钮用来触发发送数据,并获取活动使用活动的setReceive()方法对他的内容进行修改:

<Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:id="@+id/Bygetactivity"android:text="通过getActivity传递数据"/>
buttongetactivity = view.findViewById(R.id.Bygetactivity);
buttongetactivity.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {((DataPassActivity) getActivity()).setReceive("这是Fragment向活动传入的数据");}
});

重新运行程序,一开始的界面为:
在这里插入图片描述

从之前的布局可以知道,上面是一个碎片,给碎片加入了一个点击按钮用来触发通过getActivity()向活动传入数据,下面即为活动的TextView控件,当我们点击按钮:

在这里插入图片描述

此时就将数据传输到了活动,并显示在TextView当中。

通过接口

上面提到了通过接口从Activity向Fragment传递数据,从Fragment向Activity传递数据也是类似的,Fragment成为了被观察者,我们需要在Fragment里面写接口。

同样的,我们先在Fragment里设置发送数据的按钮,的代码:

<Buttonandroid:id="@+id/ByinterfaceActivity"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:layout_marginTop="50dp"android:text="通过接口传递数据" />

Fragment的点击事件的注册:

//在onViewCreated()方法里面进行按钮的实现
buttonbyinterface = (Button) view.findViewById(R.id.ByinterfaceActivity);
buttonbyinterface.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (monFragmentDataChangeListener != null) {monFragmentDataChangeListener.onFragmentDataChange("这是Fragment通过接口向activity传入的数据");}}
});

碎片A的接口定义:

private OnFragmentDataChangeListener monFragmentDataChangeListener;public void setFragmentDataChangeListener (OnFragmentDataChangeListener monFragmentDataChangeListener) {this.monFragmentDataChangeListener = monFragmentDataChangeListener;
}public interface OnFragmentDataChangeListener {void onFragmentDataChange (String data);
}

在承载碎片的活动对接口的实现:

Fragment fra = fragmentManager.findFragmentById(R.id.fcv);
if (fra != null) {((DataPassFragment)fra).setFragmentDataChangeListener(new DataPassFragment.OnFragmentDataChangeListener() {@Overridepublic void onFragmentDataChange(String data) {tvreceive.setText(data);});
}

我们运行程序发现按下按钮并没有显示出我们传递的数据,将提交事务改变为commitNow()

//添加Fragment到布局当中
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fcv, DataPassFragment.class, null).commitNow();

此时运行程序,数据就传输并显示出来了:
在这里插入图片描述

commitNow()commit()方法的区别:

  1. 异步与同步
    • commit(): 这个方法是异步的。当你调用commit()时,它会将事务放入一个队列中,然后返回。这意味着事务的执行是延迟的,不会立即执行。这有助于提高应用的响应性,因为它允许其他UI操作在事务执行之前继续进行。
    • commitNow(): 这个方法是同步的。当你调用commitNow()时,它会立即执行事务,而不是将其放入队列中。这意味着事务会立即完成,不会等待其他UI操作。
  2. 执行时机
    • commit(): 由于是异步执行,事务会在稍后的时间点执行,通常是在下一个UI绘制循环中。这使得在事务提交后立即进行其他UI操作成为可能,而不会导致阻塞。
    • commitNow(): 事务会立即执行,因此在执行期间,UI会暂时冻结,直到事务完成。这可能会导致用户界面在事务执行期间变得无响应。
  3. 适用场景
    • commit(): 通常用于需要提高应用响应性的场景,尤其是在事务执行期间需要进行其他UI操作的情况下。例如,在一个复杂的用户界面中,你可能需要同时进行多个UI操作,使用commit()可以避免阻塞UI。
    • commitNow(): 通常用于需要立即执行事务的场景,尤其是在事务执行后需要立即进行某些操作的情况下。例如,如果你需要在事务执行后立即检查某些条件或执行某些操作,使用commitNow()可以确保这些操作在事务完成后立即执行。

Fragment之间传递数据

通过Activity中转

此时我们是让两个碎片之间进行数据传递,新设立两个碎片,各自的碎片当中都设立一个TextView来展现所接收的数据,设置一个按钮用来发送数据,碎片A的布局文件为:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:background="#f0a1a8"tools:context=".datapass1.fragment.FragmentPassA"><TextViewandroid:paddingTop="20dp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="25sp"android:text="此时还未进行数据传递"android:id="@+id/tv_a_receive"android:layout_gravity="center"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:text="通过活动传递数据给碎片B"android:id="@+id/passDataByActivityA"/></LinearLayout>

我们将碎片A的背景设置为粉色,碎片B与碎片A的布局是相同的,为了区分将碎片B的背景颜色设置为蓝色,将两个碎片放在一个活动当中进行数据的传递,承载碎片的活动的布局文件与将碎片放进活动当中的代码为:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".datapass1.fragmentPassBetween"><androidx.fragment.app.FragmentContainerViewandroid:layout_width="match_parent"android:layout_height="200dp"android:id="@+id/fcv_a"/><Viewandroid:layout_width="match_parent"android:layout_height="2dp"android:background="@color/black"/><androidx.fragment.app.FragmentContainerViewandroid:layout_width="match_parent"android:layout_height="200dp"android:id="@+id/fcv_b"/></LinearLayout>
public class fragmentPassBetween extends AppCompatActivity {private FragmentPassA fragmentPassA;private FragmentPassB fragmentPassB;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);EdgeToEdge.enable(this);setContentView(R.layout.activity_fragment_pass_between);ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);return insets;});fragmentPassA = new FragmentPassA();fragmentPassB = new FragmentPassB();getSupportFragmentManager().beginTransaction().replace(R.id.fcv_a, fragmentPassA).commit();getSupportFragmentManager().beginTransaction().replace(R.id.fcv_b, fragmentPassB).commit();}
}

此时运行程序活动界面为:
在这里插入图片描述

准备工作就完成了,先来看看从碎片A传数据到碎片B吧!

在前面的学习当中我们了解到根据碎片可以得到它所在的活动,进一步我们就可以根据所得到的活动来获取它的另一个碎片,即我们所要将数据传递的接收者碎片B,调用碎片B里的方法就可以对碎片B的TextView进行文本的重新修改,显示出我们所要传递的数据。因此在碎片A与B当中我们需要先获取它们的按钮与TextView,在碎片B当中写将接收到的数据展示在文本框:

public void setmDataB (String data) {mData = data;textViewB.setText(mData);
}

对于碎片A需要对按钮注册点击事件,上面已经提到了碎片A向B的传递思路,代码如下:

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);textViewA = view.findViewById(R.id.tv_a_receive);buttonpassA = view.findViewById(R.id.passDataByActivityA);buttonpassA.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//向碎片B传递数据Fragment fragmentB = ((fragmentPassBetween)getActivity()).getSupportFragmentManager().findFragmentById(R.id.fcv_b);if (fragmentB != null) {((FragmentPassB)fragmentB).setmDataB("这是FragmentA传来的数据");}}});
}

此时运行程序,按下碎片A里的按钮:

在这里插入图片描述

通过接口

在两个碎片当中都各自添加一个按钮,它们的点击事件就为通过接口实现数据传递,与此同时我们需要对两个碎片的按钮进行加载并注册点击事件。还是给大家展示从碎片A传递数据给碎片B吧,此时A就为被观察者,在A的内部定义接口:

private OnFragmentAChangeLiatener monFragmentAChangeLiatener;public void setOnFragmentAChangeLiatener(OnFragmentAChangeLiatener onFragmentAChangeLiatener) {monFragmentAChangeLiatener = onFragmentAChangeLiatener;
}public interface OnFragmentAChangeLiatener {void onFragementAChange(String data);
}

碎片A的点击事件:

buttoninterfacaA = (Button) view.findViewById(R.id.passDataByInterfacaA);
buttoninterfacaA.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (monFragmentAChangeLiatener != null) {monFragmentAChangeLiatener.onFragementAChange("这是通过接口来自FragmentA的数据");}}
});

在碎片B当中实现这个接口:

//先获取FragmentPassA
FragmentPassA fragmentPassA = (FragmentPassA) ((fragmentPassBetween)getActivity()).getSupportFragmentManager().findFragmentById(R.id.fcv_a);
//当它不为空的时候即找到了FragmentPassA,并调用FragmentPassA的、setOnFragmentAChangeLiatener方法并实现接口
if (fragmentPassA != null) {fragmentPassA.setOnFragmentAChangeLiatener(new FragmentPassA.OnFragmentAChangeLiatener() {@Overridepublic void onFragementAChange(String data) {textViewB.setText(data);}});
}

此时运行程序,按下按钮碎片B就接收到了来自碎片A的数据:

在这里插入图片描述

到这里就结束了!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/48946.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

408专业课130|零基础五个月速成攻略

计算机考研&#xff0c;有两个选择&#xff0c;一个是自命题&#xff0c;一个是408。如果你只是考一个普通院校&#xff0c;可以选择考自命题院校&#xff0c;容易上岸&#xff0c;但是如果考985/211/这类院校&#xff0c;最好还是选择408&#xff0c;因为408的考风险能力很强&…

Apollo部署与简易架构梳理

文章目录 apollo 安装apollo的基本架构组件机制component编译与加载 节点通讯数据的传输消息读写的实现消息的写端消息读端 常用术语ComponentChannelTaskNodeReader/WriterService/ClientParameter服务发现CRoutineSchedulerMessageDag文件Launch文件Record文件Mainboard Moni…

在图神经网络(GNN)上进行关系推理的新架构

开发能够学习推理的模型是一个众所周知的具有挑战性的问题&#xff0c;在这个领域中&#xff0c;使用图神经网络&#xff08;GNNs&#xff09;似乎是一个自然的选择。然而&#xff0c;以往关于使用GNNs进行推理的工作表明&#xff0c;当这些模型面对需要比训练时更长推理链的测…

(leetcode学习)236. 二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为一个节点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&#xff08;一个节点也可以是它自己的祖…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第五十一章 添加设备树节点

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

linux禁用root

linux禁用root 1. 禁止普通用户切换到root1.1 sudo -i和sudo -s的区别1.2 sudo -i和直接登录root账号的区别1.3 禁止sudo -i切换root1.4 禁止su - root切换root 2. 禁止root远程登录2.1 ssh禁止root登录2.2 禁止远程桌面登录 本文主要介绍&#xff1a; 如何禁止普通用户切换到r…

Java---后端事务管理

代码世界聚眸光&#xff0c;昼夜敲盘思绪长。 算法心间精构建&#xff0c;编程路上细思量。 屏前架构乾坤定&#xff0c;键上飞驰智慧扬。 默默耕耘成果现&#xff0c;创新科技铸辉煌。 目录 一&#xff0c;概念 二&#xff0c;Spring事务管理 三&#xff0c;rollbackFor事务回…

运维锅总浅析Kubernetes之Ceph

Ceph 的核心组件有哪些&#xff1f;Ceph读写数据流程及故障自愈是怎样的&#xff1f;如何对Ceph部署架构进行调优&#xff1f;如何用Ceph集成到kubernetes&#xff1f;希望本文能帮您解答这些疑惑&#xff01; 一、Ceph简介 Ceph 是一个开源的分布式存储系统&#xff0c;旨在…

PySide(PyQt)使用QPropertyAnimation制作动态界面

主脚本&#xff1a; # encoding: utf-8 import os import sysfrom PySide6.QtCore import QPropertyAnimation, QEasingCurvefrom UIS import *# 主画面类 class MainWindow(QMainWindow, animationButton_ui.Ui_MainWindow):def __init__(self):super().__init__()self.setup…

韩顺平0基础学Java——第37天

p736-758 MySQL三层结构 1.所谓安装Mysql数据库&#xff0c;就是在主机安装一个数据库管理系统(DBMS)&#xff0c;这个管理程序可以管理多个数据库。DBMS(database manage system) 2.一个数据库中可以创建多个表,以保存数据(信息)。 3.数据库管理系统(DBMS)、数据库和表的关系…

Android 性能之刷新率设置和管理

目录 1. 刷新率和帧率 2. 多种刷新率 3. 基本原理 3.1 屏幕 & 显示控制器 3.2 Composer Service 4. Framework 策略 4.1基本架构 4.2 刷新率设置项的定义 4.2.1 最低刷新率 4.2.2 默认刷新率 & 默认的用户设置刷新率 4.2.2.1 设置入口 4.2.2.2 设置场景 4…

从零开始:在linux系统安装MongoDB数据完整指南 新手常用命令

1 前言 MongoDB 是为快速开发互联网应用而设计的数据库系统。MongoDB 的设计目标是极简、灵活、作为 Web 应用栈的一部分。MongoDB 的数据模型是面向文档的&#xff0c;所谓文档是一种类似于json的结构。 官网教程&#xff1a;https://www.mongodb.com/docs/manual/ 2 安装部…

【接口自动化_11课_框架实战:基于封装的框架进行实战演练-下】

目标&#xff1a; 在原有基础上进行框架优化&#xff0c;本内容不做强制要求&#xff0c;了解即可。 1. Faker&#xff08;伪造器&#xff09;模块生成数据 2. 实战&#xff1a;结合框架动态生成请求数据 3. 实战&#xff1a;响应进行动态断言处理 一、 Faker&#xff…

LoFTR关键点特征匹配算法环境构建与图像匹配测试Demo

0&#xff0c;LoFTR CVPR 2021论文《LoFTR: Detector-Free Local Feature Matching with Transformers》开源代码 1&#xff0c;项目主页 LoFTR: Detector-Free Local Feature Matching with Transformers 2&#xff0c;GItHub主页 GitHub - zju3dv/LoFTR: Code for "…

微软蓝屏事件对企业数字化转型有什么影响?

引言&#xff1a;从北京时间2024年7月19日&#xff08;周五&#xff09;下午2点多开始&#xff0c;全球大量Windows用户出现电脑崩溃、蓝屏死机、无法重启等情况。事发后&#xff0c;网络安全公司CrowdStrike称&#xff0c;收到大量关于Windows电脑出现蓝屏报告&#xff0c;公司…

畅游时空|虚拟世界初体验,元宇宙游戏如何开发?

在元宇宙中&#xff0c;用户可以通过虚拟身份进行互动、社交、工作和娱乐&#xff0c;体验与现实世界平行的生活和活动。元宇宙不仅仅是一个虚拟空间&#xff0c;更是一个融合了虚拟和现实的生态系统&#xff0c;具有巨大的发展潜力和应用前景。 在不断发展的数字环境中&#x…

简单几步,教你使用scikit-learn做分类和回归预测

前言 scikit-learn是基于Python的一个机器学习库&#xff0c;你可以在scikit-learn库中选择合适的模型&#xff0c;使用它训练数据集并对新数据集作出预测。 对于初学者来说&#xff0c;有一个共同的困惑&#xff1a; 怎么使用scikit-learn库中的模型做预测&#xff1f; 本文…

IOS微软语音转文本,lame压缩音频

在IOS开发中&#xff0c;用微软进行语音转文本操作&#xff0c;并将录音文件压缩后返回 项目中遇到了利用微软SDK进行实时录音转文本操作&#xff0c;如果操作失败&#xff0c;那么就利用原始音频文件通过网络请求操作&#xff0c;最终这份文件上传到阿里云保存&#xff0c;考…

MongoDB教程(十五):MongoDB原子操作

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、MongoD…

11 深度推荐模型演化中的“范式替换“灵活组合

上一课时&#xff0c;我们介绍了 DIEN 模型添加了 RNN中 的 GRU&#xff0c;使模型获得了对序列数据的建模能力&#xff1b;而 DSIN 模型不仅使用了 RNN 中的 bi-LSTM&#xff0c;还使用了 Transformer 组件。 由此可见&#xff0c;在新的演化模型中&#xff0c;根据场景和数据…