MainActivity和ViewPager中的多个Fragment通信问题
一、MainActivity和单个Fragment通信
Activity和单个Fragment通信,非常简单,用接口回调的方法,很容易实现。具体可参见链接。但是对于Activity和多个Fragment之间的通讯,提及较少。下面讲一讲如何实现Activity和多个Fragment通讯。
二、MainActivity和多个Fragment通信
上一节已经实现了多个Fragment的滚动。
1、多个Fragment将信息传给Activity
第一步
在上一节的基础上给三个Fragment:Fragment_Control、 Fragment_Oversee、Fragment_ConnectDevice分别添加三个按钮,ID分别为:button_control_send 、button_see_send 、button_connect_send 。再给三个Fragment分别添加接口:
Fragment_Control
package com.example.dx.testviewpager;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
/**
* Created by dx on 2018/9/8.
*/
public class Fragment_Control extends Fragment implements View.OnClickListener {
private Button control_send;
private onControlSend2Activity controlSend2Activity ;
public View onCreateView(LayoutInflater inflater , ViewGroup container, Bundle savedInstanceState){
View view=inflater .inflate(R.layout .activity_control ,container,false) ;
control_send =(Button)view.findViewById(R.id.button_control_send ) ;
control_send .setOnClickListener(this) ;
return view;
}
//接口
interface onControlSend2Activity
{
public void receiveDataFromControl(String content,int whichFragment);
}
//接口监听
public void setOnConnectSend2ActivityListener(onControlSend2Activity on){
this.controlSend2Activity =on;
}
@Override
public void onClick(View v )
{
if(v.getId() ==R.id.button_control_send )
{
String content="我来自Fragment_Control";
this.controlSend2Activity .receiveDataFromControl(content,0) ;//触发
}
}
}
Fragment_Oversee:
package com.example.dx.testviewpager;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
/**
* Created by dx on 2018/9/8.
*/
public class Fragment_Oversee extends Fragment implements View.OnClickListener {
private Button see_Send;
public onSeeSend2Activity seeSend2Activity ;
public View onCreateView(LayoutInflater inflater , ViewGroup container, Bundle savedInstanceState){
View view=inflater .inflate(R.layout .activity_see ,container,false) ;
see_Send =(Button)view.findViewById(R.id.button_see_send ) ;
see_Send .setOnClickListener(this) ;
return view;
}
//接口
interface onSeeSend2Activity
{
public void receiveDataFromSee(String content,int whichFragment);
}
//接口监听
public void setOnConnectSend2ActivityListener(onSeeSend2Activity on){
this.seeSend2Activity =on;
}
@Override
public void onClick(View v )
{
if(v.getId() ==R.id.button_see_send )
{
String content="我来自Fragment_Oversee";
this.seeSend2Activity .receiveDataFromSee(content,1) ;//触发
}
}
}
Fragment_ConnectDevice:
package com.example.dx.testviewpager;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
/**
* Created by dx on 2018/9/10.
*/
public class Fragment_ConnectDevice extends Fragment implements View .OnClickListener {
private Button connect_send;
public onConnectSend2Activity connectSend2Activity ;
public View onCreateView(LayoutInflater inflater , ViewGroup container, Bundle savedInstanceState){
View view=inflater .inflate(R.layout .activity_connect ,container,false) ;
connect_send =(Button )view.findViewById(R.id.button_connect_send ) ;
connect_send .setOnClickListener(this) ;
return view;
}
//接口
interface onConnectSend2Activity
{
public void receiveDataFromConnect(String content,int whichFragment);
}
//接口监听
public void setOnConnectSend2ActivityListener(onConnectSend2Activity on){
this.connectSend2Activity =on;
}
@Override
public void onClick(View v)
{
if(v.getId() ==R.id.button_connect_send )
{
String content="我来自Fragment_ConnectDevice";
this.connectSend2Activity .receiveDataFromConnect(content,2) ;//触发
}
}
}
第二步
照常理,应该是在MainActivity中实现三个Fragment的接口,并且给三个Fragment注册监听事件,但问题在于,如何获得当前的Fragment?又如何给它注册监听事件呢?
网上有一种获得当前Fragment的方法,参考。获取到当前Fragment后,给它注册监听。想到了在 onPageSelected(int arg0) 函数中根据选中的Fragment注册相应的监听事件。事实上,我也这样试过了,然后发现程序闪退。
那出现了什么问题呢?后来查阅资料发现,我们获取当前Fragment的setPrimaryItem()函数在onPageSelected()函数之后执行,也就是说在onPageSelected(int arg0) 中找到的Fragment对象是滑动之前的。
那么有什么其他方法可以给Fragment动态注册监听事件呢?下面我提供一种方法:setPrimaryItem()函数是每次切换Fragment都会执行的,因此可以通过回调监听这个函数,并且把当前Fragment参数给传递出去。
package com.example.dx.testviewpager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.view.ViewGroup;
import java.util.List;
/**
* Created by dx on 2018/9/18.
*/
public class TabFragmentPagerAdapter extends FragmentPagerAdapter {
private FragmentManager mfragmentManager;
private List<Fragment> mlist;
public Fragment currentFragment;
private OnFragmentChangedListener onFragmentChangedListener ;
/**
* 定义回调接口,我们监听setPrimaryItem()中的position,就是切换的fragment
*/
public interface OnFragmentChangedListener {
public void onFragmentChanged(int pos);
}
/**
*设置监听函数
*/
public void setOnFragmentChangedListener (OnFragmentChangedListener onFragmentChangedListener )
{
this.onFragmentChangedListener =onFragmentChangedListener ;
}
public TabFragmentPagerAdapter(FragmentManager fm, List<Fragment> list) {
super(fm);
this.mlist = list;
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
this.currentFragment= (Fragment) object;
onFragmentChangedListener .onFragmentChanged(position ) ;//触发监听,将position传递出去
super.setPrimaryItem(container, position, object);
}
@Override
public Fragment getItem(int arg0) {
return mlist.get(arg0);//显示第几个页面
}
@Override
public int getCount() {
return mlist.size();//有几个页面
}
}
第二步
在MainActivity里注册监听,并且重写接口的实现方法。代码很长,但是关键部分都有注释。
package com.example.dx.testviewpager;
import android.graphics.Color;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Gravity;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements Fragment_Control .onControlSend2Activity,Fragment_ConnectDevice .onConnectSend2Activity ,Fragment_Oversee .onSeeSend2Activity, TabFragmentPagerAdapter .OnFragmentChangedListener{
private List<Fragment> list;
private ViewPager myViewPager;
private TabFragmentPagerAdapter adapter;
private TextView text_Control;
private TextView text_Oversee;
private TextView text_connectDevice;
private TextView topTitle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView()
{
text_Control=(TextView) findViewById(R.id.textView_control ) ;
text_Oversee =(TextView) findViewById(R.id.textView_oversee ) ;
text_connectDevice =(TextView) findViewById(R.id.textView_connectDevice ) ;
topTitle =(TextView) findViewById(R.id.textView_topTitle ) ;
myViewPager = (ViewPager) findViewById(R.id.myViewPager);
//绑定点击事件
myViewPager.setOnPageChangeListener(new MyPagerChangeListener()) ;
//把Fragment添加到List集合里面
list = new ArrayList<>();
list.add(new Fragment_Control() );
list.add(new Fragment_Oversee() );
list.add(new Fragment_ConnectDevice() );
adapter = new TabFragmentPagerAdapter(getSupportFragmentManager(), list);
myViewPager.setAdapter(adapter);
myViewPager.setCurrentItem(1); //初始化显示第一个页面
adapter .setOnFragmentChangedListener(this) ;//给adapter注册监听事件
}
/**
* 设置一个ViewPager的侦听事件,当左右滑动ViewPager时菜单栏被选中状态跟着改变
*
*/
public class MyPagerChangeListener implements ViewPager.OnPageChangeListener {
@Override
public void onPageScrollStateChanged(int arg0) {
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageSelected(int arg0) {
switch (arg0) {
case 0:
text_Control .setTextColor(Color.GREEN );
text_Oversee .setTextColor(Color.BLACK );
text_connectDevice .setTextColor(Color.BLACK );
topTitle .setText("手动控制") ;
break;
case 1:
text_Control .setTextColor(Color.BLACK );
text_Oversee .setTextColor(Color.GREEN );
text_connectDevice .setTextColor(Color.BLACK );
topTitle .setText("数据监控") ;
break;
case 2:
text_Control .setTextColor(Color.BLACK );
text_Oversee .setTextColor(Color.BLACK );
text_connectDevice .setTextColor(Color.GREEN );
topTitle .setText("连接设备") ;
break;
}
}
}
//监听当前Fragment,并且初始化
@Override
public void onFragmentChanged(int pos){
switch(pos) {
case 0:
Fragment_Control fc1 = (Fragment_Control) ((TabFragmentPagerAdapter) myViewPager.getAdapter()).currentFragment;
if (fc1 == null) {
Toast toast1 = Toast.makeText(getApplicationContext(),
"未获取到当前的Fragment"+String .valueOf(pos) , Toast.LENGTH_LONG);
toast1.setGravity(Gravity.CENTER, 0, 0);
toast1.show();
} else {
fc1.setOnControlSend2ActivityListener(this) ;
}
break;
case 1:
Fragment_Oversee fc2=(Fragment_Oversee) ((TabFragmentPagerAdapter )myViewPager .getAdapter() ).currentFragment ;
if(fc2==null)
{
Toast toast1 = Toast.makeText(getApplicationContext(),
"未获取到当前的Fragment"+String .valueOf(pos), Toast.LENGTH_LONG);
toast1.setGravity(Gravity.CENTER, 0, 0);
toast1.show();
}else{
fc2.setOnSeeSend2ActivityListener(this) ;
}
break;
case 2:
Fragment_ConnectDevice fc3=(Fragment_ConnectDevice) ((TabFragmentPagerAdapter )myViewPager .getAdapter() ).currentFragment ;
if(fc3==null)
{
Toast toast1 = Toast.makeText(getApplicationContext(),
"未获取到当前的Fragment"+String .valueOf(pos), Toast.LENGTH_LONG);
toast1.setGravity(Gravity.CENTER, 0, 0);
toast1.show();
}else{
fc3.setOnConnectSend2ActivityListener(this) ;
}
break;
}
}
//监听来自Fragment_control数据
@Override
public void receiveDataFromControl(String content,int whichFragment){
Toast toast1 = Toast.makeText(getApplicationContext(),
content, Toast.LENGTH_LONG);
toast1.setGravity(Gravity.CENTER, 0, 0);
toast1.show();
}
//监听来自Fragment_Oversee数据
@Override
public void receiveDataFromSee(String content,int whichFragment){
Toast toast1 = Toast.makeText(getApplicationContext(),
content, Toast.LENGTH_LONG);
toast1.setGravity(Gravity.CENTER, 0, 0);
toast1.show();
}
//监听来自Fragment_ConnectDevice数据
@Override
public void receiveDataFromConnect(String content,int whichFragment){
Toast toast1 = Toast.makeText(getApplicationContext(),
content, Toast.LENGTH_LONG);
toast1.setGravity(Gravity.CENTER, 0, 0);
toast1.show();
}
}
实现效果:
2、Activity向多个Fragment传值
方法类似,这里只想提醒一下,在Fragment给MainActivity注册监听时:`
MainActivity mainActivity =(MainActivity) getActivity() ;
mainActivity .setOnSendData2FragmentListener(new receiveData2Activity() ) ;//给MainActivity注册监听
用接口回调的方法传值,了解执行过程以后,其实很简单。
三、源码
源码。 提取码:v01o