万能Interface实现Fragment之间的通讯

来源:互联网 发布:网络书香讲坛 编辑:程序博客网 时间:2024/05/19 21:03

实现两个Fragment之间的通讯方法有很多种,如:

EventBus:使用方便,但其使用的是反射原理,会有稍微的延迟,并且他人维护不方便;

static静态变量:使用方便,但是,每个static变量都会占用一块内存区,Android系统分配给每个App的内存是有限的(63M),过多很容易造成App内存溢出;

广播Broadcast Receiver:Android的广播是有限制的,除了系统的广播外,其他的广播尽量少用。另外,广播会有延迟;

接口:接口是我们常用的Fragment之间的通讯方式,通过一个主Activity作为通讯桥梁(谷歌官方声明:两个Fragment之间永远不要直接通讯),实现两个Fragment之间的通讯。

接口的方式是我们推荐的,但是,传统的接口方式会造成一些问题,如果主Activity实现了多个Fragment的通讯回调接口,它的代码结构将是这样的:

第一步:定义接口

[java] view plain copy
  1. public interface Fragment1CallBack {  
  2.     void buttonClick1();  
  3. }  

第二步:Fragment调用接口

[java] view plain copy
  1. public class Fragment1 extends Fragment {  
  2.   
  3.     private TextView tv;  
  4.     private Button btn;  
  5.     private Fragment1CallBack fragment1CallBack;  
  6.   
  7.     @Nullable  
  8.     @Override  
  9.     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {  
  10.         View view = inflater.inflate(R.layout.fragment_layout,null);  
  11.         tv = (TextView) view.findViewById(R.id.textView);  
  12.         btn = (Button) view.findViewById(R.id.button);  
  13.         btn.setOnClickListener(new View.OnClickListener() {  
  14.             @Override  
  15.             public void onClick(View v) {  
  16.                 //调用接口方法  
  17.                 fragment1CallBack.buttonClick1();  
  18.             }  
  19.         });  
  20.         tv.setText(this.getClass().getSimpleName());  
  21.         return view;  
  22.     }  
  23.   
  24.     @Override  
  25.     public void onAttach(Context context) {  
  26.         super.onAttach(context);  
  27.         // 保证容器Activity实现了回调接口 否则抛出异常警告  
  28.         try {  
  29.             fragment1CallBack = (Fragment1CallBack) context;  
  30.         } catch (ClassCastException e) {  
  31.             throw new ClassCastException(context.toString()  
  32.                     + " must implement Fragment1CallBack");  
  33.         }  
  34.     }  
  35. }  

第三步:Activity实现接口回调

[java] view plain copy
  1. public class MainActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener,  
  2.                                                                 Fragment1CallBack,  
  3.                                                                 Fragment2CallBack,  
  4.                                                                 Fragment3CallBack,  
  5.                                                                 Fragment4CallBack{  
  6.   
  7.     private ViewPager viewpager;  
  8.     private RadioGroup radioGroup;  
  9.     private MyPagerAdapter adapter;  
  10.     private List<Fragment> fragments = new ArrayList<>();  
  11.   
  12.     @Override  
  13.     protected void onCreate(Bundle savedInstanceState) {  
  14.         super.onCreate(savedInstanceState);  
  15.         setContentView(R.layout.activity_main);  
  16.         viewpager = (ViewPager) findViewById(R.id.viewpager);  
  17.         radioGroup = (RadioGroup) findViewById(R.id.radioGroup);  
  18.         radioGroup.setOnCheckedChangeListener(this);  
  19.         fragments.add(new Fragment1());  
  20.         fragments.add(new Fragment2());  
  21.         fragments.add(new Fragment3());  
  22.         adapter = new MyPagerAdapter(getSupportFragmentManager(), fragments);  
  23.         viewpager.setAdapter(adapter);  
  24.         viewpager.setCurrentItem(0,false);  
  25.         viewpager.setOffscreenPageLimit(3);  
  26.         viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {  
  27.             @Override  
  28.             public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {  
  29.   
  30.             }  
  31.   
  32.             @Override  
  33.             public void onPageSelected(int position) {  
  34.   
  35.             }  
  36.   
  37.             @Override  
  38.             public void onPageScrollStateChanged(int state) {  
  39.   
  40.             }  
  41.         });  
  42.     }  
  43.   
  44.     @Override  
  45.     public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) {  
  46.         switch (checkedId){  
  47.             case R.id.radio1:  
  48.                 viewpager.setCurrentItem(0);  
  49.                 break;  
  50.             case R.id.radio2:  
  51.                 viewpager.setCurrentItem(1);  
  52.                 break;  
  53.             case R.id.radio3:  
  54.                 viewpager.setCurrentItem(2);  
  55.                 break;  
  56.         }  
  57.     }  
  58.     @Override  
  59.     public void buttonClick1() {  
  60.         // Fragment1回调  
  61.   
  62.     }  
  63.     @Override  
  64.     public void buttonClick2() {  
  65.         // Fragment2回调  
  66.   
  67.     }  
  68.     @Override  
  69.     public void buttonClick3() {  
  70.         // Fragment3回调  
  71.   
  72.     }  
  73.     @Override  
  74.     public void buttonClick4() {  
  75.         // Fragment4回调  
  76.   
  77.     }  
  78. }  

上述传统方式,在回调接口比较少的情况下还可以接受,但是,若接口很多,那么,我们需要在Activity类声明中implements很多的接口,类中还要实现一大堆接口方法,显得特别繁琐。

为了解决这种过于繁琐的操作,我们采用面向对象思想,将接口抽象成一个对象,一个接口中包含有函数(函数名、返回值、参数、没有实现的函数体)。因此,我们可以定义出下面几个类:

Function类(接口抽象类的基础类):

[java] view plain copy
  1. public abstract class Function {  
  2.      public String mFunctionName;  
  3.   
  4.     public Function(String functionName){  
  5.         this.mFunctionName = functionName;  
  6.     }  
  7.   
  8. }  
FunctionNoParamNoResault类(无参无返回值接口抽象类):
[java] view plain copy
  1. public abstract class FunctionNoParamNoResault extends Function{  
  2.     public FunctionNoParamNoResault(String functionName){  
  3.         super(functionName);  
  4.     }  
  5.     public abstract void function();  
  6. }  
FunctionWithParamAndResult类(有参有返回值接口抽象类):
[java] view plain copy
  1. public abstract class FunctionWithParamAndResult<Result,Param> extends Function{  
  2.     public FunctionWithParamAndResult(String functionName){  
  3.         super(functionName);  
  4.     }  
  5.     public abstract Result function(Param pram);  
  6. }  
FunctionWithParamOnly类(有参无返回值接口抽象类):

[java] view plain copy
  1. public abstract class FunctionWithParamOnly<Param> extends Function{  
  2.     public FunctionWithParamOnly(String functionName){  
  3.         super(functionName);  
  4.     }  
  5.     public abstract void function(Param pram);  
  6. }  

FunctionWithResultOnly类(无参有返回值接口抽象类):

[java] view plain copy
  1. public abstract class FunctionWithResultOnly<Result> extends Function{  
  2.     public FunctionWithResultOnly(String functionName){  
  3.         super(functionName);  
  4.     }  
  5.     public abstract Result function();  
  6. }  

定义完所有的接口抽象类之后,我们在定义一个接口管理类,通过接口管理类来管理调用对应的函数方法。

FunctionManager类(管理和调用不同的方法):

[java] view plain copy
  1. public class FunctionManager {  
  2.     private static FunctionManager instance;  
  3.     private HashMap<String,FunctionNoParamNoResault> mFunctionNoParamNoResault;  
  4.     private HashMap<String,FunctionWithParamOnly> mFunctionWithParamOnly;  
  5.     private HashMap<String,FunctionWithResultOnly> mFunctionWithResultOnly;  
  6.     private HashMap<String,FunctionWithParamAndResult> mFunctionWithParamAndResult;  
  7.   
  8.     private FunctionManager() {  
  9.         mFunctionNoParamNoResault = new HashMap<>();  
  10.         mFunctionWithParamOnly = new HashMap<>();  
  11.         mFunctionWithResultOnly = new HashMap<>();  
  12.         mFunctionWithParamAndResult = new HashMap<>();  
  13.     }  
  14.     public static FunctionManager getInstance(){  
  15.         if(instance == null){  
  16.             instance = new FunctionManager();  
  17.         }  
  18.         return instance;  
  19.     }  
  20.   
  21.     /** 
  22.      * 添加无参无返回值的接口方法 
  23.      * @param function 
  24.      * @return 
  25.      */  
  26.   
  27.     public FunctionManager addFunction(FunctionNoParamNoResault function){  
  28.         mFunctionNoParamNoResault.put(function.mFunctionName,function);  
  29.         return this;  
  30.     }  
  31.   
  32.     /** 
  33.      * 调用无参无返回值的接口方法 
  34.      * @param funcName 
  35.      */  
  36.     public void invokeFunc(String funcName){  
  37.         if(TextUtils.isEmpty(funcName) == true){  
  38.             return;  
  39.         }  
  40.         if(mFunctionNoParamNoResault != null){  
  41.             FunctionNoParamNoResault f = mFunctionNoParamNoResault.get(funcName);  
  42.             if(f != null){  
  43.                 f.function();  
  44.             }  
  45.             if (f == null){  
  46.                 try {  
  47.                     throw  new FunctionException("Has no this function" + funcName);  
  48.                 } catch (FunctionException e) {  
  49.                     e.printStackTrace();  
  50.                 }  
  51.             }  
  52.         }  
  53.     }  
  54.     /** 
  55.      * 添加无参有返回值的接口方法 
  56.      * @param function 
  57.      * @return 
  58.      */  
  59.     public FunctionManager addFunction(FunctionWithResultOnly function){  
  60.         mFunctionWithResultOnly.put(function.mFunctionName,function);  
  61.         return this;  
  62.     }  
  63.     /** 
  64.      * 调用无参有返回值的接口方法 
  65.      * @param funcName 
  66.      */  
  67.     public <Result> Result invokeFunc(String funcName,Class<Result> clz){  
  68.         if(TextUtils.isEmpty(funcName) == true){  
  69.             return null;  
  70.         }  
  71.         if(mFunctionWithResultOnly != null){  
  72.             FunctionWithResultOnly f = mFunctionWithResultOnly.get(funcName);  
  73.             if(f != null){  
  74.                 if(clz != null){  
  75.                     return clz.cast(f.function());  
  76.                 } else {  
  77.                     return (Result) f.function();  
  78.                 }  
  79.             }else {  
  80.                 try {  
  81.                     throw  new FunctionException("Has no this function" + funcName);  
  82.                 } catch (FunctionException e) {  
  83.                     e.printStackTrace();  
  84.                 }  
  85.             }  
  86.         }  
  87.         return null;  
  88.     }  
  89.     /** 
  90.      * 添加有参有返回值的接口方法 
  91.      * @param function 
  92.      * @return 
  93.      */  
  94.     public FunctionManager addFunction(FunctionWithParamAndResult function){  
  95.         mFunctionWithParamAndResult.put(function.mFunctionName,function);  
  96.         return this;  
  97.     }  
  98.     /** 
  99.      * 调用有参有返回值的接口方法 
  100.      * @param funcName 
  101.      */  
  102.     public <Result,Param> Result invokeFunc(String funcName,Class<Result> clz ,Param data){  
  103.         if(TextUtils.isEmpty(funcName) == true){  
  104.             return null;  
  105.         }  
  106.         if(mFunctionWithParamAndResult != null){  
  107.             FunctionWithParamAndResult f = mFunctionWithParamAndResult.get(funcName);  
  108.             if(f != null){  
  109.                 if(clz != null){  
  110.                     return clz.cast(f.function(data));  
  111.                 } else {  
  112.                     return (Result) f.function(data);  
  113.                 }  
  114.             }else {  
  115.                 try {  
  116.                     throw  new FunctionException("Has no this function" + funcName);  
  117.                 } catch (FunctionException e) {  
  118.                     e.printStackTrace();  
  119.                 }  
  120.             }  
  121.         }  
  122.         return null;  
  123.     }  
  124.     /** 
  125.      * 添加有参无返回值的接口方法 
  126.      * @param function 
  127.      * @return 
  128.      */  
  129.     public FunctionManager addFunction(FunctionWithParamOnly function){  
  130.         mFunctionWithParamOnly.put(function.mFunctionName,function);  
  131.         return this;  
  132.     }  
  133.     /** 
  134.      * 调用有参无返回值的接口方法 
  135.      * @param funcName 
  136.      */  
  137.     public <Param> void invokeFunc(String funcName,Param data ){  
  138.         if(TextUtils.isEmpty(funcName) == true){  
  139.             return ;  
  140.         }  
  141.         if(mFunctionWithParamOnly != null){  
  142.             FunctionWithParamOnly f = mFunctionWithParamOnly.get(funcName);  
  143.             if(f != null){  
  144.                 f.function(data);  
  145.             }else {  
  146.                 try {  
  147.                     throw  new FunctionException("Has no this function" + funcName);  
  148.                 } catch (FunctionException e) {  
  149.                     e.printStackTrace();  
  150.                 }  
  151.             }  
  152.         }  
  153.         return ;  
  154.     }  
  155. }  

然后,定义一个要使用回调接口的Fragment的基类。

BaseFragment类:

[java] view plain copy
  1. public class BaseFragment extends Fragment{  
  2.   
  3.     protected FunctionManager mFunctionManager;  
  4.     private MainActivity mBaseActivity;  
  5.   
  6.     /** 
  7.      * 为要实现接口的Fragment添加FunctionManager 
  8.      * @param functionManager 
  9.      */  
  10.     public void setmFunctionManager(FunctionManager functionManager){  
  11.         this.mFunctionManager = functionManager;  
  12.     }  
  13.   
  14.     /** 
  15.      * 确保Mainctivity实现了Fragment相应的接口回调 
  16.      * @param context 
  17.      */  
  18.     @Override  
  19.     public void onAttach(Context context) {  
  20.         super.onAttach(context);  
  21.         if(context instanceof MainActivity){  
  22.             mBaseActivity = (MainActivity) context;  
  23.             mBaseActivity.setFuctionsForFragment(getTag());  
  24.         }  
  25.     }  
  26. }  

在具体某个Fragment类中,调用接口。如:

Fragment3类(调用有参有返回值接口方法):

[java] view plain copy
  1. public class Fragment3 extends BaseFragment{  
  2.     private TextView tv;  
  3.     private Button btn;  
  4.     //定义一个接口标记  
  5.     public static final String INTERFACE_PARAM_RESULT = Fragment1.class.getName() + "PR";  
  6.   
  7.     @Nullable  
  8.     @Override  
  9.     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {  
  10.         View view = inflater.inflate(R.layout.fragment_layout,null);  
  11.         tv = (TextView) view.findViewById(R.id.textView);  
  12.         tv.setText(this.getClass().getSimpleName());btn = (Button) view.findViewById(R.id.button);  
  13.         btn.setOnClickListener(new View.OnClickListener() {  
  14.             @Override  
  15.             public void onClick(View v) {  
  16.                 //这里调用接口  
  17.                 String str = mFunctionManager.invokeFunc(INTERFACE_PARAM_RESULT,String.class,"我是传输的字符串");  
  18.                 Toast.makeText(getActivity(),str,Toast.LENGTH_SHORT).show();  
  19.             }  
  20.         });  
  21.   
  22.         return view;  
  23.     }  
  24. }  

MainActivity中添加接口并实现接口方法:

MainActivity类:

[java] view plain copy
  1. public class MainActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener{  
  2.   
  3.     private ViewPager viewpager;  
  4.     private RadioGroup radioGroup;  
  5.     private MyPagerAdapter adapter;  
  6.     private List<Fragment> fragments = new ArrayList<>();  
  7.   
  8.     @Override  
  9.     protected void onCreate(Bundle savedInstanceState) {  
  10.         super.onCreate(savedInstanceState);  
  11.         setContentView(R.layout.activity_main);  
  12.         viewpager = (ViewPager) findViewById(R.id.viewpager);  
  13.         radioGroup = (RadioGroup) findViewById(R.id.radioGroup);  
  14.         radioGroup.setOnCheckedChangeListener(this);  
  15.         fragments.add(new Fragment1());  
  16.         fragments.add(new Fragment2());  
  17.         fragments.add(new Fragment3());  
  18.         fragments.add(new Fragment4());  
  19.         adapter = new MyPagerAdapter(getSupportFragmentManager(), fragments);  
  20.         viewpager.setAdapter(adapter);  
  21.         viewpager.setCurrentItem(0,false);  
  22.         viewpager.setOffscreenPageLimit(4);  
  23.         viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {  
  24.             @Override  
  25.             public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {  
  26.   
  27.             }  
  28.   
  29.             @Override  
  30.             public void onPageSelected(int position) {  
  31.   
  32.             }  
  33.   
  34.             @Override  
  35.             public void onPageScrollStateChanged(int state) {  
  36.   
  37.             }  
  38.         });  
  39.     }  
  40.   
  41.     @Override  
  42.     public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) {  
  43.         switch (checkedId){  
  44.             case R.id.radio1:  
  45.                 viewpager.setCurrentItem(0);  
  46.                 break;  
  47.             case R.id.radio2:  
  48.                 viewpager.setCurrentItem(1);  
  49.                 break;  
  50.             case R.id.radio3:  
  51.                 viewpager.setCurrentItem(2);  
  52.                 break;  
  53.             case R.id.radio4:  
  54.                 viewpager.setCurrentItem(3);  
  55.                 break;  
  56.         }  
  57.     }  
  58.   
  59.     /** 
  60.      * 添加接口并实现接口中的方法回调 
  61.      * @param tag Fragment标记 
  62.      */  
  63.     public void setFuctionsForFragment(String tag){  
  64.         FragmentManager fm = getSupportFragmentManager();  
  65.         BaseFragment fragment = (BaseFragment) fm.findFragmentByTag(tag);  
  66.         FunctionManager functionManager = FunctionManager.getInstance();  
  67.         fragment.setmFunctionManager(functionManager.addFunction(new FunctionNoParamNoResault(Fragment1.INTERFACE) {  
  68.             @Override  
  69.             public void function() {  
  70.                 //接口中的方法回调  
  71.                 Toast.makeText(MainActivity.this,"成功调用无参无返回值的接口",Toast.LENGTH_SHORT).show();  
  72.             }  
  73.         }).addFunction(new FunctionWithResultOnly<String>(Fragment2.INTERFACE_RESULT) {  
  74.             @Override  
  75.             public String function() {  
  76.                 //接口中的方法回调  
  77.                 return "I Love U";  
  78.             }  
  79.         }).addFunction(new FunctionWithParamAndResult<String,String>(Fragment3.INTERFACE_PARAM_RESULT) {  
  80.             @Override  
  81.             public String function(String pram) {  
  82.                 //接口中的方法回调  
  83.                 return pram;  
  84.             }  
  85.         }).addFunction(new FunctionWithParamOnly<String>(Fragment4.INTERFACE_PARAM) {  
  86.   
  87.             @Override  
  88.             public void function(String pram) {  
  89.                 //接口中的方法回调  
  90.                 Toast.makeText(MainActivity.this,"成功调用有参无返回值的接口:" + pram,Toast.LENGTH_SHORT).show();  
  91.             }  
  92.         }));  
  93.     }  
  94. }  


至此,一个实现Fragment之间数据通讯的万能接口框架就搭建完成了。

源码传送门:https://github.com/legallonly/FragnmentInterfaceDemo

原创粉丝点击