Activity与Fragment通讯(99%)完美处理计划-Android-优质IT资源分享社区

admin
管理员
管理员
  • UID1
  • 粉丝29
  • 关注4
  • 发帖数581
  • 社区居民
  • 忠实会员
  • 原创写手
阅读:232回复:0

  Activity与Fragment通讯(99%)完美处理计划

楼主#
更多 发布于:2016-05-30 21:59


前言
近来一直在想着能否有一种非常好的计划来处理:Android中Activity与Fragment之间通讯的疑问,什么叫非常好呢,即是能让Fragment的复用性高,功用还有好(不必反射),代码还要好保护,不需要为每对Activity和Fragment之间界说接口而忧愁。
先简略说下Javascript这门言语吧,或许有人就会问:咱们不是聊Android的java疑问吗?如何论题转到JavaScript了。由于我的处理计划的启示是从它来的,没兴趣的兄弟能够略过。近来在学习javascript这门言语,一起自个搞Android(java)开发也有5年多时间了,所以在学习js的过程中,就会惯性的把这两者进行对比。
与java言语的 谨慎 相比
Javascript是一门“放浪形骸”、”落拓不羁”(广泛)的言语。
为何要用“放浪形骸”这个词呢,下面是它的一个解说:
放浪形骸 [fàng dàng bù jī][解说]
羁:束缚。放纵固执,不加检核,不受束缚。
由于我觉得这个词更能充沛的表现js弱类型的特色。
在给变量赋值时 能够这么写:
var a = 1;
还能够这么写:
var b = '123';var o = new Object();
乃至还能够这么写:
var fun = new function(){};fun1 = new
function(){};
能够把任何类型的值赋给一个变量,也能够不加var关键词来声明一个变量,是不是很固执,很不拘谨啊。
“落拓不羁”首要表现了JavaScript的语法更广泛、更简略的特色:
比方:
//函数声明不需要界说回来值,参数前面不需要有类型呈现,  //函数体里边就能够有回来值
 function max(a,b){ return a > b? a:b; }  /* *能够传递任意多个参数,在java里边根本不能够 */
 function print(){      var len = arguments.length;      for(var i = 0; i <
len; i++){          console.log(arguments);     }  }  相应java代码:   int max(int
a, int b){       return a> b? a:b;  }  /* *传递任意多个Object类型的参数 */  void
print(Object... args){       for (int i = 0; i < args.length; i++){          
   System.out.println(args);        }   }
上面的代码说明晰JavaScript在声明函数时,不会有像java那么严厉的规矩,语法落拓不羁,语法更简略(这儿没有说java不好的意思)。
启示点
JavaScript中有一个主要的点(万事万物皆目标),函数也不列外,而且函数能够作为另外一个函数的参数,如:
//遍历一个数组如果是它是数组,就把它乘以10再输出     var array = [1,2,
'你好' , '不' ,31,15];    //数组的each办法接纳一个函数     testArray.each( function( value ){
          typeof value == 'number' ? alert( value *10 ):null;    })  ;
当我看到上面JavaScript中函数的用法时我眼前一亮,为啥我不能够学习之来处理android中activity与fragment通讯的疑问呢?
Fragment的任务
先让咱们聊聊Fragment为何呈现,这对于咱们处理Activity与Fragment的通讯有协助。一个新事物的发生老是为了处理旧事物存在的疑问,Fragment是android3.0的产品,在android3.0之前处理手机、平板电脑的适配疑问是很头疼的,对ActivityGroup有形象的兄弟,应该能深深的体会到ActivityGroup包裹的多个Activity之间切换等一系列的功用疑问。由此Fragment诞生了。自己总结的Fragment的任务:
处理手机、平板电脑等各种设备的适配疑问
处理多个Activity之间切换功用疑问
模块化,由于模块化致使复用的好处
Fragment的运用
Fragment是能够被包裹在多个不一样Activity内的,一起一个Activity内能够包裹多个Fragment,Activity就如一个大的容器,它能够办理多个Fragment。一切Activity与Fragment之间存在依靠联系。
Activity与Fragment通讯计划
上文说到Activity与Fragment之间是存在依靠联系的,因而它们之间必然会涉及到通讯疑问,处理通讯疑问必然会涉及到目标之间的引证。由于Fragment的呈现有一个主要的任务即是:模块化,然后进步复用性。若到达此作用,Fragment有必要做到高内聚,低耦合。
如今咱们动动脚趾都能想到的处理它们之间通讯的计划有:handler,播送,EvnetBus,接口等(或许还有别的计划,请咱们多多共享),那咱们就聊下这些计划。
handler计划:
先上代码
public class MainActivity extends
FragmentActivity{      //声明一个Handler      public Handler mHandler = new
Handler(){          @Override           public void handleMessage(Message msg) {
               super.handleMessage(msg);                 ...相应的处理代码           }
    }     ...相应的处理代码   }    public class MainFragment extends Fragment{        
 //保留Activity传递的handler           private Handler mHandler;           @Override
          public void onAttach(Activity activity) {              
 super.onAttach(activity);               //这个当地现已发生了耦合,若还有别的的activity,这个当地就得修改  
             if(activity instance MainActivity){                      mHandler =
 ((MainActivity)activity).mHandler;                }           }          
...相应的处理代码     }
该计划存在的缺陷:
Fragment对详细的Activity存在耦合,不利于Fragment复用
不利于保护,若想删去相应的Activity,Fragment也得改动
无法获取Activity的回来数据
handler的运用自己感觉就很不爽(不知咱们是不是有同感)
播送计划:
详细的代码就不写了,说下该计划的缺陷:
用播送处理此疑问有点大材小用了,自己感觉播送的意图是用在一对多,接纳播送者是不知道的状况
播送功用肯定会差(不要和我说功用不是疑问,对于手机来说功用是大疑问)
传达数据有约束(有必要得完成序列化接谈锋能够)
暂时就想到这些缺陷,别的的缺陷请咱们群策群力下吧。
EventBus计划:
详细的EventBus的运用能够自个查找下,自己对该计划的观点:
EventBus是用反射机制完成的,功用上会有疑问(不要和我说功用不是疑问,对于手机来说功用是大疑问)
EventBus难于保护代码
无法获取Activity的回来数据
接口计划
我想这种计划是咱们最易想到,运用最多的一种计划吧,详细上代码:
//MainActivity完成MainFragment敞开的接口  public class
MainActivity extends FragmentActivity implements FragmentListener{      
 @override         public void toH5Page(){ }       ...别的处理代码省掉   }    public
class MainFragment extends Fragment{         public FragmentListener mListener;
       //MainFragment敞开的接口        public static interface FragmentListener{    
       //跳到h5页面           void toH5Page();         }         @Override      
 public void onAttach(Activity activity) {            
 super.onAttach(activity);              //对传递进来的Activity进行接口变换              
if(activity instance FragmentListener){                   mListener =
((FragmentListener)activity);              }         }         ...别的处理代码省掉
 }
这种计划应该是既能到达复用,又能到达很好的可保护性,而且功用也是杠杠的。可是仅有的一个惋惜是假设项目很大了,Activity与Fragment的数量也会添加,这时候为每对Activity与Fragment交互界说交互接口即是一个很头疼的疑问(包含为接口的命名,新界说的接口相应的Activity还得完成,相应的Fragment还得进行强制变换)。
想看非常好的处理计划请看下面章节。
大招来也
设计方式里常常说到的一个概念即是封装改变,一起受javascript中的函数的参数能够是函数目标的启示下,我有了下面的想法,先上代码:代码地址
/** * + Created by niuxiaowei on 2016/1/20.  *
各种办法调集的类,能够把一个办法类以key-value的方式放入本类,  * 能够经过key值来调用相应的办法 */   public class
Functions {      //带参数办法的调集,key值为办法的姓名      private
 HashMapmFunctionWithParam ;    
 //无参数无回来值的办法调集,同理key值为办法姓名     private
HashMapmFunctionNoParamAndResult ;      /** *
根底办法类 */     public static abstract class Function{        
//办法的姓名,用来做调用,也能够理解为办法的指针          public String mFunctionName;          public
Function(String functionName){                this.mFunctionName = functionName;
        }      }      /** * 带有参数没有回来值的办法     * @param 参数 */     public static
abstract class FunctionWithParam extends Function{          public
FunctionWithParam(String functionName) {              super(functionName);      
  }        public abstract void function(Param param);    }    /** * 没有参数和回来值的办法
*/   public static abstract class FunctionNoParamAndResult extends Function{    
     public FunctionNoParamAndResult(String functionName) {              
 super(functionName);          }          public abstract void function();    }
   /** * 添加带参数的函数     * @param function {@link
com.niu.myapp.myapp.view.util.Functions.FunctionWithParam}    * @return */    
public Functions addFunction(FunctionWithParam function){            
if(function == null){                  return this;             }          
 if(mFunctionWithParam == null){                  mFunctionWithParam = new
HashMap<>(1);            }      
 mFunctionWithParam.put(function.mFunctionName,function);        return this;  
   }      /** * 添加带回来值的函数      * @param function {@link
com.niu.myapp.myapp.view.util.Functions.FunctionWithResult}     * @return */    
public Functions addFunction(FunctionNoParamAndResult function){        
 if(function == null){ return this; }          if(mFunctionNoParamAndResult ==
null){                mFunctionNoParamAndResult = new HashMap<>(1);      
  }         mFunctionNoParamAndResult.put(function.mFunctionName,function);    
 return this;    }     /** * 依据函数名,回调无参无回来值的函数   * @param funcName */    public
void invokeFunc(String funcName) throws FunctionException {        
FunctionNoParamAndResult f = null;        if(mFunctionNoParamAndResult != null){
             f = mFunctionNoParamAndResult.get(funcName);              if(f !=
null){ f.function(); }        }         if(f == null){ throw new
FunctionException("没有此函数"); }     }    /** * 调用具有参数的函数     * @param funcName  
 * @param param    * @param*/      publicvoid
invokeFunc(String funcName,Param param)throws FunctionException{          
 FunctionWithParam f = null;            if(mFunctionWithParam != null){        
         f = mFunctionWithParam.get(funcName);                   if(f != null){
f.function(param); }            }    
}}
设计思路:
1. 用一个类来模仿Javascript中的一个Function
Function即是此类,它是一个基类,每个Functioon实例都有一个mFuncName
既然是办法(或许函数)它就有有参数和无参数之分
FunctionWithParam是Function的子类,代表有参数的办法类,办法参数经过泛型处理
FunctionNoParamAndResult是Function的子类,代表无参无回来值的办法类
2. 一个能够寄存多个办法(或许函数)的类
Functions类即是此类,下面简略介绍下Functions有4个首要办法:
addFunction(FunctionNoParamAndResult function)
添加一个无参无回来值的办法类
addFunction(FunctionWithParam function)
添加一个有参无回来值的办法类
invokeFunc(String funcName) 依据funcName调用一个办法
invokeFunc(String funcName,Param param)
依据funcName调用有参无回来值的办法类
运用举例:代码地址
每个app都有的根底activity(BaseActivity)
public abstract class BaseActivity extends
FragmentActivity {          /**          * 为fragment设置functions,详细完成子类来做        
* @param fragmentId */        public void setFunctionsForFragment(            
 int fragmentId){        }   }
其间的一个activity:
public class MainActivity extends BaseActivity {  
       @Override public void setFunctionsForFragment(int fragmentId) {          
    super.setFunctionsForFragment(fragmentId);               switch (fragmentId)
{                   case R.id.fragment_main:                     FragmentManager
fm = getSupportFragmentManager();                    BaseFragment fragment =
(BaseFragment) fm.findFragmentById(fragmentId);                  
//开端添加functions               fragment.setFunctions(new Functions()            
      .addFunction(new
Functions.FunctionNoParamAndResult(MainFragment.FUNCTION_NO_PARAM_NO_RESULT) {  
                    @Override                      public void function() {    
                      Toast.makeText(MainActivity.this, "成功调用无参无回来值办法",
Toast.LENGTH_LONG).show();                      }               }).            
     addFunction(new
Functions.FunctionWithParam(MainFragment.FUNCTION_HAS_PARAM_NO_RESULT)
{                        @Override                        public void
function(Integer o) {                          
 Toast.makeText(MainActivity.this, "成功调用有参无回来值办法 参数值=" + o,
Toast.LENGTH_LONG).show(); } }));                       }               }
}
每个app都会有的根底fragment(BaseFragment)
public abstract class BaseFragment extends
Fragment {            protected BaseActivity mBaseActivity;            /** *
函数的调集 */            protected Functions mFunctions;            /** *
activity调用此办法进行设置Functions           * @param functions */           public void
setFunctions(Functions functions){                this.mFunctions = functions;  
        }          @Override          public void onAttach(Activity activity) {
               super.onAttach(activity);               //呼叫activity进行回调办法的设置    
         if(activity instanceof BaseActivity){                    mBaseActivity
= (BaseActivity)activity;                    
mBaseActivity.setFunctionsForFragment(getId());               }          }
 }
MainActivity对应的MainFragment
public class MainFragment extends BaseFragment {  
        /** * 没有参数没有回来值的函数 */          public static final String
FUNCTION_NO_PARAM_NO_RESULT = "FUNCTION_NO_PARAM_NO_RESULT";          /** *
有参数没有回来值的函数 */         public static final String FUNCTION_HAS_PARAM_NO_RESULT =
"FUNCTION_HAS_PARAM_NO_RESULT";          @Override           public void
onViewCreated(View view, @Nullable Bundle savedInstanceState) {              
super.onViewCreated(view, savedInstanceState);               mBut1 = (Button)
getView().findViewById(R.id.click1);                mBut3 = (Button)
getView().findViewById(R.id.click3);               mBut1.setOnClickListener(new
View.OnClickListener() {                    @Override                     public
void onClick(View v) {                          try {                          
    //调用无参无回来值的办法                               mFunctions.invokeFunc(          
                     FUNCTION_NO_PARAM_NO_RESULT);                        }
catch (FunctionException e) {                               e.printStackTrace();
                       }                    }              });            
 mBut3.setOnClickListener(new View.OnClickListener() {                
 @Override                   public void onClick(View v) {                      
  try {                                //调用有参无回来值的办法                            
   mFunctions.invokeFunc(                                
FUNCTION_HAS_PARAM_NO_RESULT, 100);                        } catch
(FunctionException e) {                               e.printStackTrace(); }    
                }               });  }
看到这您是不是觉得现已结束了,当然是没有了,由于还有2个疑问没处理。办法回来值和办法接纳多个参数的疑问。
办法回来值的疑问
上代码:代码地址
/** * 有回来值,没有参数的办法     * @param  */    public
static abstract class FunctionWithResult extends Function{         public
FunctionWithResult(String functionName) {              super(functionName);    
    }          public abstract Result function();    }    /** * 带有参数和回来值的 办法  
 * @param    * @param & */   public static abstract class
FunctionWithParamAndResultextends Function{        public
FunctionWithParamAndResult(String functionName) {            
 super(functionName);        }        public abstract Result function(Param
data); }
FunctionWithResult无参数有回来值的办法类
FunctionWithParamAndResult 有参数也有回来值的办法类
在Functions类中界说添加和调用这2种办法类的 相应办法。
其次是办法富含多个参数的疑问
在处理此疑问时我想了许多办法(比方如何引进多个泛型,但终究以失利告终,期望有看了这篇文章的兄弟能够多提下宝贵意见)。然后我就想到了用Bundle来处理多参数的疑问,把多个参数放到Bundle中,可是在往Bundle中塞入数据时得有一个对应的key值,生成key值以及记住key值(记住key值是为了从Bundle中取数据)是一个繁琐的事。一起Bundle不能传递非序列化目标。所以就封装了一个FunctionParams类处理以上疑问,请看类的完成:
代码地址
/** * 函数的参数,当函数的参数涉及到多个值时,能够用此类,   *
此类运用规矩:存参数与取参数的次序有必要共同,   * 比方存参数次序是new
*FunctionParamsBuilder().putString("a").putString("b").putInt(100);    *取的次序也是:
functionParams.getString(),    *functionParams.getString(),
functionParams.getInt(); */ public static class FunctionParams {      private
Bundle mParams = new Bundle(1);      private int mIndex = -1;      private Map
mObjectParams = new HashMap(1);      FunctionParams(Bundle mParams,Map
mObjectParams){          this.mParams = mParams;          this.mObjectParams =
mObjectParams;     }    public Param getObject(Class p){        if(mObjectParams
== null){ return null; }        return p.cast(mObjectParams.get((mIndex++) +
"")); }    /** * 获取int值    * @return */    public int getInt(){        
if(mParams != null){              return mParams.getInt((mIndex++) + ""); }
return 0;    }    /** * 获取int值    * @param defalut    * @return */    public int
getInt(int defalut){        if(mParams != null){          return
mParams.getInt((mIndex++) + "");        }       return defalut;     }    /** *
获取字符串    * @param defalut * @return */     public String getString(String
defalut){        if(mParams != null){          return
mParams.getString((mIndex++) + "");        }        return defalut;    }    /**
* 获取字符串 * @return */    public String getString(){        if(mParams != null){  
          return mParams.getString((mIndex++) + "");      } return null;    }  
   /** * 获取Boolean值    * @return 默认回来false */     public boolean getBoolean(){  
     if(mParams != null){            return mParams.getBoolean((mIndex++) + "");
       } return false;     }     /** * 该类用来创立函数参数 */     public static class
FunctionParamsBuilder{         private Bundle mParams ;         private int
mIndex = -1;         private Map mObjectParams = new HashMap(1);        public
FunctionParamsBuilder(){ }        public FunctionParamsBuilder putInt(int
value){             if(mParams == null){                  mParams = new
Bundle(2);             }              mParams.putInt((mIndex++) + "", value);  
           return this;      }      public FunctionParamsBuilder
putString(String value){            if(mParams == null){                mParams
= new Bundle(2);           }            mParams.putString((mIndex++) + "",
value);            return this;    }     public FunctionParamsBuilder
putBoolean(boolean value){          if(mParams == null){ mParams = new
Bundle(2); }          mParams.putBoolean((mIndex++) + "", value);        
 return this;     }      public FunctionParamsBuilder putObject(Object value){  
       if(mObjectParams == null){              mObjectParams = new HashMap(1);  
       }          mObjectParams.put((mIndex++) + "", value);           return
this;     }     public FunctionParams create(){         FunctionParams instance
= new FunctionParams(mParams,mObjectParams); return instance;    }  }}
FunctionParams封装了取参数的功用,比方:
public Param getObject(Class p){      
 if(mObjectParams == null){ return null; }         return
p.cast(mObjectParams.get((mIndex++) + ""));   }
取目标参数的功用,不需要传人key值,只需要传人需要行将取出来的类的Class实例即可
FunctionParamsBuilder类,看它的姓名就知道是用了设计方式里的Builder(构建)方式。该类是用来寄存参数的,当一切的参数都寄存结束后调用create()办法创立一个FunctionParams目标事物都是有两面性的,有缺陷就有长处,只不过是在某些场合下长处大于缺陷,仍是反之。
FunctionParams处理了以上说到的Bundle传递多参数各种不方便的疑问,但一起FunctionParams也有一个缺陷即是存参数的次序与取参数的次序一定要共同,比方:
//存的次序 new  
 FunctionParamsBuilder().putString("1").putInt(2)    .putBoolean(true).create();
   //取的次序    functionParams.getString();    functionParams.getInt();  
 functionParams.getBoolean();
可是这种缺陷函数的界说来看也不是缺陷。
Activity与Fragment之间的通讯是经过Functions的,即把改变的部分封装在Functions是类中,Functions起一个桥梁作用。
此计划长处:
Fragment与Activity的耦合性几乎没有
功用也好(没用反射)
能够从Activity获取回来数据
扩展性好(新添加的成对的Activity与Fragment之间的通讯只需做以下几步:
1.新添加Activity只需要掩盖BaseActivity中的
setFunctionsForFragment(int fragmentId) 办法,把相应的回调函数参加。
2.相应的Fragment界说函数key值即可)
疑问:咱们对于传递多参数是不是有非常好的见地?有的话加我qq:704451290,或许发我邮箱704451290@qq.com
总结
简略总结为以下几点:
Fragment的任务
Activity与Fragment之间通讯的处理计划(handler,播送,EventBus,接口)的优缺陷。
我自个对于Activity与Fragment之间通讯的处理计划(Functions),本来处理的首要是Fragment调用Activity的计划。期望咱们能多提宝贵意见,多沟通。代码地址








优质IT资源分享社区为你提供此文。
站有大量优质android教程视频,资料等资源,包含android基础教程,高级进阶教程等等,教程视频资源涵盖传智播客,极客学院,达内,北大青鸟,猎豹网校等等IT职业培训机构的培训教学视频,价值巨大。欢迎点击下方链接查看。

android教程视频
优质IT资源分享社区(www.itziyuan.top)
一个免费,自由,开放,共享,平等,互助的优质IT资源分享网站。
专注免费分享各大IT培训机构最新培训教学视频,为你的IT学习助力!

!!!回帖受限制请看点击这里!!!
!!!资源失效请在此版块发帖说明!!!

[PS:按 CTRL+D收藏本站网址~]

——“优质IT资源分享社区”管理员专用签名~

本版相似帖子

游客