所谓进行通信,就是你使用我的数据和方法,你使用我的数据和方法。
主活动调用碎片中的方法
第一步:新建一个安卓项目,代码使用https://blog.youkuaiyun.com/jintingbo/article/details/104745290中的代码,即本实验是在那篇文章的基础上的继续。
第二步:新建一个碎片,随便取一个名字,比中叫左碎片LeftFragment;
第三步:在LeftFragment中新建一个自定义的方法比如叫myPring(String str);
public static final String TAG="LeftFragment";
public void myPrintln(String str){
Log.d(TAG,str);
}
第四步:在主活动中调用这个方法。
如何做呢?只需要在主活动中获取到主布局中的这个左碎片对象,然后用这个对象去调用它的myPring()方法即可以。
获取主布局中的碎片对象,不能用 findViewById(),而要用findFragmentById(); 代码如下:
//获取左碎片
LeftFragment lfFragment=(LeftFragment) getSupportFragmentManager()
.findFragmentById(R.id.left_fragment);
lfFragment.myPrintln("这是主Activity调用左碎片中方法的实例");
运行正确!
----------------------------------------------------------------------------------
碎片中使用主活动中的方法
第一步:在主活动中加一个自己的方法:
public static final String TAG="MainActivity";
//输出List中的数据
public void myPrList(List<String> list){
for(String s:list){
Log.d(TAG,s);
}
}
第二步:在左碎片中获取主活动,然后利用它将自己的List打印出来;程序要写在onCreateView之中
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View m= inflater.inflate(R.layout.fragment_left, container, false);
MainActivity ma=(MainActivity)getActivity();
List<String> strList= new ArrayList();
strList.add("中国");
strList.add("美国");
strList.add("俄罗斯");
ma.myPrList(strList);
return m;
}
运行搞定
---------------------------------------------------------
碎片中如何调用主活动中的数据?以数组为例
第一步:在主活动中设置一个成员数组:
public String[] tangShi={"春眠不觉晓\n","处处闻啼鸟\n","夜来风雨声\n","花落知多少\n"};
第二步:在左碎片中
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View m= inflater.inflate(R.layout.fragment_left, container, false);
MainActivity ma=(MainActivity)getActivity(); //获取主活动中的对象
String[] tangShi1=ma.tangShi; // 用一个字符串数组将主活动中的字符串数组接收下来;
for(int i=0;i<tangShi1.length;i++){
Log.d(TAG,tangShi1[i]);
}
return m;
}
运行搞定
----------------------------------------------------------------------
两个碎片之间进行通信方法一:
在B碎片要写A碎片的控件,B碎片调用A碎片中的函数来实现的
第一步:在主活动中有两个碎片 activity_main.xml
必须先有这个布局,不然第四步的public void setData(String str)会出错,因为活动中没有碎片,你是找不到控件ID的。
<fragment
android:id="@+id/af"
android:name="com.jintingbo.myapplication21.AFragment"
android:layout_width="match_parent"
android:layout_height="100dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:layout="@layout/fragment_a"
/>
<fragment
android:id="@+id/bf"
android:name="com.jintingbo.myapplication21.BFragment"
android:layout_width="match_parent"
android:layout_height="100dp"
app:layout_constraintTop_toBottomOf="@id/af"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:layout="@layout/fragment_b"
/>
第二步:A碎片和B碎片中的布局为:
fragment_a.txt
<TextView
android:id="@+id/at1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/hello_blank_fragment" />
fragment_b.txt
<TextView
android:id="@+id/bt1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hello_blank_fragment" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
第三步:B碎片中button的点击事件,把B碎片中的值写入到A碎片中的TextView之中
public class BFragment extends Fragment {
private List<String> mDatas= new ArrayList<>();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View bfragmentView=inflater.inflate(R.layout.fragment_b, container, false);
mDatas.add("aaaa");mDatas.add("bbbb");mDatas.add("cccc");
//这里是关键点:获得button必须是从碎片视图bfragmentView中去获取,不应该是getActivity();
Button button=(Button)bfragmentView.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//使用findFragentById()是重点。
AFragment af=(AFragment)getActivity().getSupportFragmentManager()
.findFragmentById(R.id.af);
af.setData(mDatas.get(2));
}
});
return bfragmentView;
}
}
第四步:在A碎片中写一个setData(String str)函数
public class AFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View fragmentView=inflater.inflate(R.layout.fragment_a, container, false);
return fragmentView;
}
public void setData(String str){
TextView tv1=(TextView)getActivity().findViewById(R.id.at1);
tv1.setText(str);
}
}
运行搞定。
-----------------------------------------------------
活动与碎片通信方法二:用接口
假设B碎片中有一个数据,现在Activity中想得到它,就可以在B碎片中设置一个接口和一个供Activity使用的getData()函数,执行B碎片中的点击事件后,它的数据就传到Activity了,然后由Activity传到其它的碎片中去。
B碎片代码如下:
public class BFragment extends Fragment {
//接口
public Binteface mListener;
//要传送的数据
public String data="xxxx";
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View bfragmentView=inflater.inflate(R.layout.fragment_b, container, false);
final Button button=(Button)bfragmentView.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mListener != null) {
mListener.setDate(data);
}
}
});
return bfragmentView;
}
//做一个接口
public interface Binteface {
public void setDate(String data);
}
//提供给别人使用的get函数
public void getData(Binteface mListener) {
this.mListener = mListener;
}
}
MainActivity.java的代码如下
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final BFragment bf=(BFragment)getSupportFragmentManager()
.findFragmentById(R.id.bf);
bf.getData(new BFragment.Binteface() {
@Override
public void setDate(String data) {
Log.d("MainActivity",data);
}
});
}
}
执行过程:
当主活动启动时,它执行bf.getData()函数,只是给B碎片中的mListener赋了值,此时并没有执行setDate()函数,
只有当B碎片中的点击事件发生后,它才去执行setDate()函数。
注意事项: activity_main.xml布局中必须先有那个碎片,否则
final BFragment bf=(BFragment)getSupportFragmentManager() .findFragmentById(R.id.bf);
会报错的,并且BFragment必须是final, 不然,也会报红。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="@+id/bf"
android:name="com.jintingbo.myapplication21.BFragment"
android:layout_width="match_parent"
android:layout_height="100dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:layout="@layout/fragment_b"
/>
</android.support.constraint.ConstraintLayout>
-----------------------------------------------------------
方法三:使用三方开源框架:
那么问题来了:EventBus是个啥东西???
简单来说,EventBus是一款针对Android优化的发布/订阅(publish/subscribe)事件总线。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,线程之间传递消息。简化了应用程序内各组件间、组件与后台线程间的通信。优点是开销小,代码更优雅,以及将发送者和接收者解耦。比如请求网络,等网络返回时通过Handler或Broadcast通知UI,两个Fragment之间需要通过Listener通信,这些需求都可以通过EventBus实现。
下面我们就用EventBus来实现以下Fragment之间的数据传递:
要使用EventBus必须在build.gradle(Module:app) 配置文件中包含
implementation 'org.greenrobot:eventbus:3.0.0'
第一步:新建一个项目,新建A碎片,B碎片,布局如下:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout 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:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <fragment android:id="@+id/af" android:name="com.jintingbo.myapplication21.AFragment" android:layout_width="match_parent" android:layout_height="100dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" tools:layout="@layout/fragment_a" /> <fragment android:id="@+id/bf" android:name="com.jintingbo.myapplication21.BFragment" android:layout_width="match_parent" android:layout_height="100dp" app:layout_constraintTop_toBottomOf="@id/af" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" tools:layout="@layout/fragment_b" /> </android.support.constraint.ConstraintLayout>
碎片A的布局是:
<?xml version="1.0" encoding="utf-8"?> <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:background="#ff0000" tools:context=".AFragment"> <!-- TODO: Update blank fragment layout --> <TextView android:id="@+id/at1" android:layout_width="match_parent" android:layout_height="match_parent" android:text="@string/hello_blank_fragment" /> </LinearLayout>
碎片B的布局是:
<?xml version="1.0" encoding="utf-8"?> <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="#00ff00" tools:context=".BFragment"> <!-- TODO: Update blank fragment layout --> <TextView android:id="@+id/bt1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/hello_blank_fragment" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button" /> </LinearLayout>
最后的目的是点击B碎片中的按钮,直接将B碎片中的count直接发送到A碎片的TextView之中。
第二步:MainActivity.java不要动, 这里让A碎片与B碎片直接通信;
B碎片中只需要准备数据和一个发送就可以了,不需要注册,解绑之类的
见代码中的public int count=50; 和 EventBus.getDefault().post(Integer.valueOf(count));
B碎片完整代码如下:
public class BFragment extends Fragment { //要传送的数据 public int count=50; public String aaa="中华人民共和国"; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View bfragmentView=inflater.inflate(R.layout.fragment_b, container, false); final Button button=(Button)bfragmentView.findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //它是可以多条发送的 EventBus.getDefault().post(Integer.valueOf(count)); EventBus.getDefault().post(aaa); } }); return bfragmentView; } }
第三步:A碎片接收。接收方要做一些工作注册,解绑,接收
public class AFragment extends Fragment { //做一个afView View的目的是为了接收碎片文件转成碎片视图,有了它,就好求其中的控件 View afView; @Override public void onAttach(Context context) { super.onAttach(context); //注册EventBus EventBus.getDefault().register(this); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View fragmentView=inflater.inflate(R.layout.fragment_a, container, false); //把碎片XML转换过来的视图接下来 afView=fragmentView; return fragmentView; } @Override public void onDestroyView() { super.onDestroyView(); //注销EventBus EventBus.getDefault().unregister(this); } //事件接收 @Subscribe public void onEvent(Integer count){ //Toast.makeText(getContext(), String.valueOf(count), Toast.LENGTH_SHORT).show(); //用afView去查找本视图中的R.id.at1方便。 TextView tv1=(TextView)afView.findViewById(R.id.at1); tv1.setText(String.valueOf(count)); } }