日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

android fragmentactivity fragment,Android:Activity与Fragment通信(99%)完美解决方案

發(fā)布時(shí)間:2023/12/1 Android 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android fragmentactivity fragment,Android:Activity与Fragment通信(99%)完美解决方案 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

最近一直在想著能否有一種更好的方案來解決:Android中Activity與Fragment之間通信的問題,什么叫更好呢,就是能讓Fragment的復(fù)用性高,性能還有好(不用反射),代碼還要好維護(hù),不需要為每對Activity和Fragment之間定義接口而發(fā)愁。

先簡單說下Javascript這門語言吧,或許有人就會(huì)問:咱們不是聊Android的java問題嗎?怎么話題轉(zhuǎn)到JavaScript了。因?yàn)槲业慕鉀Q方案的啟發(fā)是從它來的,沒興趣的朋友可以略過。最近在學(xué)習(xí)javascript這門語言,同時(shí)自己搞Android(java)開發(fā)也有5年多時(shí)間了,所以在學(xué)習(xí)js的過程中,就會(huì)慣性的把這兩者進(jìn)行比較。

與java語言的 嚴(yán)謹(jǐn) 相比 Javascript是一門"放蕩不羈"、"不拘小節(jié)"(寬泛)的語言。

為什么要用"放蕩不羈"這個(gè)詞呢,下面是它的一個(gè)解釋:

放蕩不羈 [fàng dàng bù jī][解釋] 羈:約束。放縱任性,不加檢點(diǎn),不受約束。

因?yàn)槲矣X得這個(gè)詞更能充分的體現(xiàn)js弱類型的特點(diǎn)。

在給變量賦值時(shí) 可以這樣寫:

var a = 1;

還可以這樣寫:

var b = '123';

var o = new Object();

甚至還可以這樣寫:

var fun = new function(){};

fun1 = new function(){};

可以把任何類型的值賦給一個(gè)變量,也可以不加var關(guān)鍵字來聲明一個(gè)變量,是不是很任性,很不拘束啊。

"不拘小節(jié)"主要體現(xiàn)了JavaScript的語法更寬泛、更簡單的特點(diǎn): 比如:

js代碼:

//函數(shù)聲明不需要定義返回值,參數(shù)前面不需要有類型出現(xiàn),

//函數(shù)體里面就可以有返回值

function max(a,b){ return a > b? a:b; }

/* *可以傳遞任意多個(gè)參數(shù),在java里面根本不可以 */

function print(){

var len = arguments.length;

for(var i = 0; i < len; i++){

console.log(arguments[i]);

}

}

相應(yīng)java代碼:

int max(int a, int b){

return a> b? a:b;

}

/* *傳遞任意多個(gè)Object類型的參數(shù) */

void print(Object... args){

for (int i = 0; i < args.length; i++){

System.out.println(args[i]);

}

}

上面的代碼說明了JavaScript在聲明函數(shù)時(shí),不會(huì)有像java那么嚴(yán)格的規(guī)定,語法不拘小節(jié),語法更簡單(這里沒有說java不好的意思)。

啟發(fā)點(diǎn)

JavaScript中有一個(gè)重要的點(diǎn)(萬事萬物皆對象),函數(shù)也不列外,并且函數(shù)可以作為另外一個(gè)函數(shù)的參數(shù),如:

js代碼:

//遍歷一個(gè)數(shù)組如果是它是數(shù)組,就把它乘以10再輸出

var array = [1,2, '你好' , '不' ,31,15];

//數(shù)組的each方法接收一個(gè)函數(shù)

testArray.each( function( value ){

typeof value == 'number' ? alert( value *10 ):null;

}) ;

當(dāng)我看到上面JavaScript中函數(shù)的用法時(shí)我眼前一亮,為啥我不可以借鑒之來解決android中activity與fragment通信的問題呢?

Fragment的使命

先讓我們聊聊Fragment為什么出現(xiàn),這對于我們解決Activity與Fragment的通信有幫助。一個(gè)新事物的產(chǎn)生總是為了解決舊事物存在的問題,Fragment是android3.0的產(chǎn)物,在android3.0之前解決手機(jī)、平板電腦的適配問題是很頭疼的,對ActivityGroup有印象的朋友,應(yīng)該能深深的體會(huì)到ActivityGroup包裹的多個(gè)Activity之間切換等一系列的性能問題。由此Fragment誕生了。個(gè)人總結(jié)的Fragment的使命:

解決手機(jī)、平板電腦等各種設(shè)備的適配問題

解決多個(gè)Activity之間切換性能問題

模塊化,因?yàn)槟K化導(dǎo)致復(fù)用的好處

Fragment的使用

Fragment是可以被包裹在多個(gè)不同Activity內(nèi)的,同時(shí)一個(gè)Activity內(nèi)可以包裹多個(gè)Fragment,Activity就如一個(gè)大的容器,它可以管理多個(gè)Fragment。所有Activity與Fragment之間存在依賴關(guān)系。

Activity與Fragment通信方案

上文提到Activity與Fragment之間是存在依賴關(guān)系的,因此它們之間必然會(huì)涉及到通信問題,解決通信問題必然會(huì)涉及到對象之間的引用。因?yàn)镕ragment的出現(xiàn)有一個(gè)重要的使命就是:模塊化,從而提高復(fù)用性。若達(dá)到此效果,Fragment必須做到高內(nèi)聚,低耦合。

現(xiàn)在大家動(dòng)動(dòng)腳趾都能想到的解決它們之間通信的方案有:handler,廣播,EvnetBus,接口等(或許還有別的方案,請大家多多分享),那我們就聊下這些方案。

handler方案:

先上代碼

public class MainActivity extends FragmentActivity{

//聲明一個(gè)Handler

public Handler mHandler = new Handler(){

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

...相應(yīng)的處理代碼

}

}

...相應(yīng)的處理代碼

}

public class MainFragment extends Fragment{

//保存Activity傳遞的handler

private Handler mHandler;

@Override

public void onAttach(Activity activity) {

super.onAttach(activity);

//這個(gè)地方已經(jīng)產(chǎn)生了耦合,若還有其他的activity,這個(gè)地方就得修改

if(activity instance MainActivity){

mHandler = ((MainActivity)activity).mHandler;

}

}

...相應(yīng)的處理代碼

}

該方案存在的缺點(diǎn):

Fragment對具體的Activity存在耦合,不利于Fragment復(fù)用

不利于維護(hù),若想刪除相應(yīng)的Activity,Fragment也得改動(dòng)

沒法獲取Activity的返回?cái)?shù)據(jù)

handler的使用個(gè)人感覺就很不爽(不知大家是否有同感)

廣播方案:

具體的代碼就不寫了,說下該方案的缺點(diǎn):

用廣播解決此問題有點(diǎn)大材小用了,個(gè)人感覺廣播的意圖是用在一對多,接收廣播者是未知的情況

廣播性能肯定會(huì)差(不要和我說性能不是問題,對于手機(jī)來說性能是大問題)

傳播數(shù)據(jù)有限制(必須得實(shí)現(xiàn)序列化接口才可以)

暫時(shí)就想到這些缺點(diǎn),其他的缺點(diǎn)請大家集思廣益下吧。

EventBus方案:

具體的EventBus的使用可以自己搜索下,個(gè)人對該方案的看法:

EventBus是用反射機(jī)制實(shí)現(xiàn)的,性能上會(huì)有問題(不要和我說性能不是問題,對于手機(jī)來說性能是大問題)

EventBus難于維護(hù)代碼

沒法獲取Activity的返回?cái)?shù)據(jù)

接口方案

我想這種方案是大家最易想到,使用最多的一種方案吧,具體上代碼:

//MainActivity實(shí)現(xiàn)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);

//對傳遞進(jìn)來的Activity進(jìn)行接口轉(zhuǎn)換

if(activity instance FragmentListener){

mListener = ((FragmentListener)activity);

}

}

...其他處理代碼省略

}

這種方案應(yīng)該是既能達(dá)到復(fù)用,又能達(dá)到很好的可維護(hù)性,并且性能也是杠杠的。但是唯一的一個(gè)遺憾是假如項(xiàng)目很大了,Activity與Fragment的數(shù)量也會(huì)增加,這時(shí)候?yàn)槊繉ctivity與Fragment交互定義交互接口就是一個(gè)很頭疼的問題(包括為接口的命名,新定義的接口相應(yīng)的Activity還得實(shí)現(xiàn),相應(yīng)的Fragment還得進(jìn)行強(qiáng)制轉(zhuǎn)換)。 想看更好的解決方案請看下面章節(jié)。

大招來也

設(shè)計(jì)模式里經(jīng)常提到的一個(gè)概念就是封裝變化,同時(shí)受javascript中的函數(shù)的參數(shù)可以是函數(shù)對象的啟發(fā)下,我有了下面的想法,先上代碼:代碼地址

/** * + Created by niuxiaowei on 2016/1/20.

* 各種方法集合的類,可以把一個(gè)方法類以key-value的形式放入本類,

* 可以通過key值來調(diào)用相應(yīng)的方法 */

public class Functions {

//帶參數(shù)方法的集合,key值為方法的名字

private HashMap mFunctionWithParam ;

//無參數(shù)無返回值的方法集合,同理key值為方法名字

private HashMap mFunctionNoParamAndResult ;

/** * 基礎(chǔ)方法類 */

public static abstract class Function{

//方法的名字,用來做調(diào)用,也可以理解為方法的指針

public String mFunctionName;

public Function(String functionName){

this.mFunctionName = functionName;

}

}

/** * 帶有參數(shù)沒有返回值的方法

* @param 參數(shù) */

public static abstract class FunctionWithParam extends Function{

public FunctionWithParam(String functionName) {

super(functionName);

}

public abstract void function(Param param);

}

/** * 沒有參數(shù)和返回值的方法 */

public static abstract class FunctionNoParamAndResult extends Function{

public FunctionNoParamAndResult(String functionName) {

super(functionName);

}

public abstract void function();

}

/** * 添加帶參數(shù)的函數(shù)

* @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;

}

/** * 添加帶返回值的函數(shù)

* @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;

}

/** * 根據(jù)函數(shù)名,回調(diào)無參無返回值的函數(shù)

* @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("沒有此函數(shù)"); }

}

/** * 調(diào)用具有參數(shù)的函數(shù)

* @param funcName

* @param param

* @param */

public void invokeFunc(String funcName,Param param)throws FunctionException{

FunctionWithParam f = null;

if(mFunctionWithParam != null){

f = mFunctionWithParam.get(funcName);

if(f != null){ f.function(param); }

}

}

}

設(shè)計(jì)思路:

1. 用一個(gè)類來模擬Javascript中的一個(gè)Function

Function就是此類,它是一個(gè)基類,每個(gè)Functioon實(shí)例都有一個(gè)mFuncName 既然是方法(或者函數(shù))它就有有參數(shù)和無參數(shù)之分

FunctionWithParam是Function的子類,代表有參數(shù)的方法類,方法參數(shù)通過泛型解決

FunctionNoParamAndResult是Function的子類,代表無參無返回值的方法類

2. 一個(gè)可以存放多個(gè)方法(或者函數(shù))的類

Functions類就是此類,下面簡單介紹下Functions有4個(gè)主要方法:

addFunction(FunctionNoParamAndResult function) 添加一個(gè)無參無返回值的方法類

addFunction(FunctionWithParam function) 添加一個(gè)有參無返回值的方法類

invokeFunc(String funcName) 根據(jù)funcName調(diào)用一個(gè)方法

invokeFunc(String funcName,Param param) 根據(jù)funcName調(diào)用有參無返回值的方法類

使用舉例:代碼地址

每個(gè)app都有的基礎(chǔ)activity(BaseActivity)

public abstract class BaseActivity extends FragmentActivity {

/**

* 為fragment設(shè)置functions,具體實(shí)現(xiàn)子類來做

* @param fragmentId */

public void setFunctionsForFragment(

int fragmentId){

}

}

其中的一個(gè)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, "成功調(diào)用無參無返回值方法", Toast.LENGTH_LONG).show();

}

}).

addFunction(new Functions.FunctionWithParam(MainFragment.FUNCTION_HAS_PARAM_NO_RESULT) {

@Override

public void function(Integer o) {

Toast.makeText(MainActivity.this, "成功調(diào)用有參無返回值方法 參數(shù)值=" + o, Toast.LENGTH_LONG).show(); } }));

}

}

}

每個(gè)app都會(huì)有的基礎(chǔ)fragment(BaseFragment)

public abstract class BaseFragment extends Fragment {

protected BaseActivity mBaseActivity;

/** * 函數(shù)的集合 */

protected Functions mFunctions;

/** * activity調(diào)用此方法進(jìn)行設(shè)置Functions

* @param functions */

public void setFunctions(Functions functions){

this.mFunctions = functions;

}

@Override

public void onAttach(Activity activity) {

super.onAttach(activity);

//呼叫activity進(jìn)行回調(diào)方法的設(shè)置

if(activity instanceof BaseActivity){

mBaseActivity = (BaseActivity)activity;

mBaseActivity.setFunctionsForFragment(getId());

}

}

}

MainActivity對應(yīng)的MainFragment

public class MainFragment extends BaseFragment {

/** * 沒有參數(shù)沒有返回值的函數(shù) */

public static final String FUNCTION_NO_PARAM_NO_RESULT = "FUNCTION_NO_PARAM_NO_RESULT";

/** * 有參數(shù)沒有返回值的函數(shù) */

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 {

//調(diào)用無參無返回值的方法

mFunctions.invokeFunc(

FUNCTION_NO_PARAM_NO_RESULT);

} catch (FunctionException e) {

e.printStackTrace();

}

}

});

mBut3.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

try {

//調(diào)用有參無返回值的方法

mFunctions.invokeFunc(

FUNCTION_HAS_PARAM_NO_RESULT, 100);

} catch (FunctionException e) {

e.printStackTrace(); }

}

});

}

看到這您是不是覺得已經(jīng)結(jié)束了,當(dāng)然是沒有了,因?yàn)檫€有2個(gè)問題沒解決。方法返回值和方法接收多個(gè)參數(shù)的問題。

方法返回值的問題

上代碼:代碼地址

/** * 有返回值,沒有參數(shù)的方法

* @param */

public static abstract class FunctionWithResult extends Function{

public FunctionWithResult(String functionName) {

super(functionName);

}

public abstract Result function();

}

/** * 帶有參數(shù)和返回值的 方法

* @param

* @param */

public static abstract class FunctionWithParamAndResult extends Function{

public FunctionWithParamAndResult(String functionName) {

super(functionName);

}

public abstract Result function(Param data);

}

FunctionWithResult無參數(shù)有返回值的方法類

FunctionWithParamAndResult 有參數(shù)也有返回值的方法類

在Functions類中定義添加和調(diào)用這2種方法類的 相應(yīng)方法。

其次是方法含有多個(gè)參數(shù)的問題

在解決此問題時(shí)我想了很多辦法(比如怎樣引入多個(gè)泛型,但最終以失敗告終,希望有看了這篇文章的朋友可以多提下寶貴意見)。然后我就想到了用Bundle來解決多參數(shù)的問題,把多個(gè)參數(shù)放到Bundle中,但是在往Bundle中塞入數(shù)據(jù)時(shí)得有一個(gè)對應(yīng)的key值,生成key值以及記住key值(記住key值是為了從Bundle中取數(shù)據(jù))是一個(gè)繁瑣的事。同時(shí)Bundle不能傳遞非序列化對象。所以就封裝了一個(gè)FunctionParams類解決以上問題,請看類的實(shí)現(xiàn): 代碼地址

/** * 函數(shù)的參數(shù),當(dāng)函數(shù)的參數(shù)涉及到多個(gè)值時(shí),可以用此類,

* 此類使用規(guī)則:存參數(shù)與取參數(shù)的順序必須一致,

* 比如存參數(shù)順序是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 默認(rèn)返回false */

public boolean getBoolean(){

if(mParams != null){

return mParams.getBoolean((mIndex++) + "");

} return false;

}

/** * 該類用來創(chuàng)建函數(shù)參數(shù) */

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封裝了取參數(shù)的功能,比如:

public Param getObject(Class p){

if(mObjectParams == null){ return null; }

return p.cast(mObjectParams.get((mIndex++) + ""));

}

取對象參數(shù)的功能,不需要傳人key值,只需要傳人需要即將取出來的類的Class實(shí)例即可

FunctionParamsBuilder類,看它的名字就知道是用了設(shè)計(jì)模式里的Builder(構(gòu)建)模式。該類是用來存放參數(shù)的,當(dāng)所有的參數(shù)都存放完畢后調(diào)用create()方法創(chuàng)建一個(gè)FunctionParams對象事物都是有兩面性的,有缺點(diǎn)就有優(yōu)點(diǎn),只不過是在某些場合下優(yōu)點(diǎn)大于缺點(diǎn),還是反之。

FunctionParams解決了以上提到的Bundle傳遞多參數(shù)種種不便的問題,但同時(shí)FunctionParams也有一個(gè)缺點(diǎn)就是存參數(shù)的順序與取參數(shù)的順序一定要一致,比如:

//存的順序 new

FunctionParamsBuilder().putString("1").putInt(2)

.putBoolean(true).create();

//取的順序

functionParams.getString();

functionParams.getInt();

functionParams.getBoolean();

但是這種缺點(diǎn)函數(shù)的定義來看也不是缺點(diǎn)。

Activity與Fragment之間的通信是通過Functions的,即把變化的部分封裝在Functions是類中,Functions起一個(gè)橋梁作用。

此方案優(yōu)點(diǎn):

Fragment與Activity的耦合性幾乎沒有

性能也好(沒用反射)

可以從Activity獲取返回?cái)?shù)據(jù)

擴(kuò)展性好(新增加的成對的Activity與Fragment之間的通信只需做以下幾步:

1.新增加Activity只需要覆蓋BaseActivity中的 setFunctionsForFragment(int fragmentId) 方法,把相應(yīng)的回調(diào)函數(shù)加入。

2.相應(yīng)的Fragment定義函數(shù)key值即可)

總結(jié)

簡單總結(jié)為以下幾點(diǎn):

Fragment的使命

Activity與Fragment之間通信的解決方案(handler,廣播,EventBus,接口)的優(yōu)缺點(diǎn)。

我自己關(guān)于Activity與Fragment之間通信的解決方案(Functions),其實(shí)解決的主要是Fragment調(diào)用Activity的方案。

希望大家能多提寶貴意見,多交流。代碼地址

本人微信:704451290

本人公眾賬號(hào)

總結(jié)

以上是生活随笔為你收集整理的android fragmentactivity fragment,Android:Activity与Fragment通信(99%)完美解决方案的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。