[Android]Fragment與Activity之間的通訊方案
Fragment依賴於Activity,那麼它們之間的通訊就必須要涉及。通過自己的尋找和實踐,知道了Fragment和Activity之間的通訊方案大概有5種,各有優缺點,用哪個方案看需求吧。
- setArguments(Bundle args)
- Handler
- Broadcast廣播
- EventBus
- 介面回撥
上程式碼,開始分析。自己寫了個小Demo:Fragment通訊Demo ,裡邊有上邊前4種通訊方式。
demo中1、2、3為activity->fragment,2、3若要fragment->activiy則相關程式碼調換位置即可。4包含雙向通訊。
一、 setArguments(Bundle args)
此方式還挺簡單的,貌似是谷歌官方推薦的一種資料傳遞方式,如果遇到記憶體重啟,系統會自動儲存資料,和Activity中的Intent一個原理。
用Android Studio新建一個Fragment時,會自帶一個函式:
private static final String ARG_PARAM1 = "param1"; private static final String ARG_PARAM2 = "param2"; private String mParam1; private String mParam2; /** * Use this factory method to create a new instance of * this fragment using the provided parameters. * * @param param1 Parameter 1. * @param param2 Parameter 2. * @return A new instance of fragment Fragment1. */ // TODO: Rename and change types and number of parameters public static Fragment1 newInstance(String param1, String param2) { Fragment1 fragment = new Fragment1(); Bundle args = new Bundle(); args.putString(ARG_PARAM1, param1); args.putString(ARG_PARAM2, param2); //儲存資料 fragment.setArguments(args); return fragment; }
在Activity中新建Fragment例項的時候,直接傳入想要傳送的資料。
//1.直接傳入引數 setArguments() 傳遞資料
Fragment1 fragment1 = Fragment1.newInstance(number1, number2);
取出資料在Fragment的OnCreat()中,用getArguments()函式取出。
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //獲取activity傳遞的資料 if (getArguments() != null) { mParam1 = getArguments().getString(ARG_PARAM1); mParam2 = getArguments().getString(ARG_PARAM2); } }
二、Handler方式
比如Activity向Fragment傳遞資料,首先,保證進行通訊的Activity和Fragment使用同一個Handler例項物件。Activity中設定全域性 變數hander,並給出其Setter方法。在響應事件中,封裝資料到message中,然後進行傳送。
//2.使用handler傳遞資料
//在handler傳送資料之前,注意需要先開啟fragment。
//否則handler變數一直為空 此handler變數是fragment呼叫setHandler()傳來的。
if (handler == null) {
return;
}
Message message = new Message();
bundle.putString(SaveData1, number1);
bundle.putString(SaveData2, number2);
message.setData(bundle);
handler.sendMessage(message);
Activity中暴露的Setter方法:
//設定handler物件 由fragment呼叫
public void setHandler(Handler handler) {
this.handler = handler;
}
Fragment中要接收資料,所以要註冊一個Handler來接收Message。同時,還要將handler物件設定給Activity。
onAttach中的activity是在基類BaseFragment中設定的,子類直接用了。
activity = (FrgmentActivity) context; //防止getActivity()空指標
@Override
public void onAttach(Context context) {
super.onAttach(context);
//設定Activity的handler物件
//為的是 activity和fragment使用同一個handler物件 才能進行handler通訊
activity.setHandler(handler);
}
//定義handler 用於接收訊息 接收activity傳遞來的資料
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle bundle = msg.getData();
String number1 = bundle.getString("number1");
String number2 = bundle.getString("number2");
//進行資料操作
textResult.setText(doAddition(number1, number2));
}
};
因為要在Fragment的生命週期onAttach中設定Activity的handler物件,所以傳遞資料傳送訊息,一定要在Fragment載入之後,即生命週期從onAttach走到onResume。否則Activity中的handler物件始終為null。
三、Broadcast廣播
廣播有很多用處,當然也可以用在這裡。Activity向Fragment通訊,則在Activity中傳送廣播,在Fragment中接收廣播。
Activity中傳送廣播:
//3.使用廣播傳遞資料
Intent intent = new Intent();
intent.setAction(ACTION_NAME);
intent.putExtra(SaveData1, number1);
intent.putExtra(SaveData2, number2);
//sendBroadcast(intent);
//使用本地廣播更加安全
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
Fragment中接收廣播:
public class Fragment3 extends BaseFragment {
private MyReceiver myReceiver;
@Override
public void onResume() {
super.onResume();
myReceiver = new MyReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(activity.ACTION_NAME);
//註冊廣播
//activity.registerReceiver(myReceiver, intentFilter);
LocalBroadcastManager.getInstance(activity).registerReceiver(myReceiver, intentFilter);
}
@Override
public int setFragmentLayoutID() {
return R.layout.fragment_fragment3;
}
//建立廣播接收例項
class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//獲取資料
String number1 = intent.getStringExtra(activity.SaveData1);
String number2 = intent.getStringExtra(activity.SaveData2);
//進行資料操作
textResult.setText(doAddition(number1, number2));
}
}
@Override
public void onPause() {
super.onPause();
//取消註冊廣播
//activity.unregisterReceiver(myReceiver);
LocalBroadcastManager.getInstance(activity).unregisterReceiver(myReceiver);
}
}
四、EventBus
EventBus是一款針對Android優化的釋出/訂閱事件匯流排。簡化了應用程式內各元件間、元件與後臺執行緒間的通訊。
EventBus詳細介紹請移步: Android事件匯流排(一)EventBus3.0用法全解析
首先新增依賴:
implementation 'org.greenrobot:eventbus:3.0.0'
Activity向Fragment中傳遞資料:(Fragment->Activity調換位置即可)
Fragment中要接收資料,首先要在Fragment中註冊和登出EventBus:
@Override
public void onResume() {
super.onResume();
//註冊EventBus,注意引數是this,傳入activity會報錯
EventBus.getDefault().register(this);
}
@Override
public void onPause() {
super.onPause();
//取消EventBus註冊
EventBus.getDefault().unregister(this);
}
還應該有一個接收資料,處理資料的函式。
//EventBus的處理事件函式 該方法可以隨意取名 必須為public 必須添加註解並指定執行緒模型
//之後EventBus會自動掃描到此函式,進行資料傳遞
@Subscribe(threadMode = ThreadMode.MAIN)
public void getData(Bundle bundle) {
String number1 = bundle.getString(activity.SaveData1);
String number2 = bundle.getString(activity.SaveData2);
//進行資料操作
textResult.setText(doAddition(number1, number2));
}
Activity在響應事件中打包資料,資料複雜的話可以專門封裝一個實體類,我的資料簡單,直接用Bundle封裝了。
//4.使用EventBus 向fragment傳遞資料
//利用bundle打包資料,也可自己封裝Event事件
bundle.putString(SaveData1, number1);
bundle.putString(SaveData2, number2);
//傳送資料
EventBus.getDefault().post(bundle);
是不是很簡單。
五、介面回撥
介面的方式懶得寫了,就是Fragment宣告一個介面,然後Activity實現介面。(反之亦然)
各個方式優缺點以及大神封裝的介面框架,參考:Android:Activity與Fragment通訊(99%)完美解決方案
~~年底了,公司over了,突然就下崗了(# ̄~ ̄#),希望自己能找到更好的工作。
待隨時補充,修正。