android之fragment與fragment、activity與activity、fragment與activity之間的通訊
Broadcast廣播接受者可以實現所有通訊;
-----------activity與activity之間的通訊---------
**********傳給上一個activity*********
//右側+按鈕的點選事件 public void addClick(View v){ Intent intent=new Intent(this,NextActivity.class); // startActivity(intent); //如果下一個activity關閉時,要在當前activity獲取下一個的資料,就要使用給下面的方法 startActivityForResult(intent,1);//1是requestCode,<span style="color:#ff0000;">用於標識請求的來源,在下面的onActivityResult中的requestCode可以區分業務</span> } //當開啟的activity關閉時呼叫,也就是下一個activity關閉時,在當前的activity呼叫 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); //requestCode 是從下一個activity關閉的時候傳過來的if(resultCode==10) { //data就是下一個頁面的意圖 String name = data.getStringExtra("name"); tx.setText(name); }else if(resultCode==20){ } } }
//吧資料返回給呼叫者 Intent intent=new Intent(); intent.putExtra("name","lambo"); setResult(10,intent);//<span style="color:#ff0000;">10是resultCode,用於標識返回結果的來源,在上一個activity中的onActivityResult中區分業務;當前activity關閉時,會傳給上一個activity</span>//關閉當前activity,才會執行上一個activity中的方法onActivityResult(int requestCode, int resultCode, Intent data) finish();
*********傳給下一個activity******
方法一:通過Intent傳值給ACOne:
Intent inten = new Intent(getContext(), ACOne.class); inten.putExtra("f", "diyige"); startActivity(inten);/*跳轉到下一個頁面*/
方法二:用Bundle攜帶引數:
public void OpenNew(View v){ //新建一個顯式意圖,第一個引數為當前Activity類物件,第二個引數為你要開啟的Activity類 Intent intent =new Intent(MainActivity.this,MainActivity2.class); //用Bundle攜帶資料 Bundle bundle=new Bundle(); //傳遞name引數為tinyphp bundle.putString("name", "tinyphp"); intent.putExtras(bundle); startActivity(intent); } protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.newtest); //新頁面接收資料 Bundle bundle = this.getIntent().getExtras(); //接收name值 String name = bundle.getString("name"); Log.i("獲取到的name值為",name); }
------------fragment與fragment之間的通訊---------
public class Fragment1 extends Fragment { @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View v=inflater.inflate(R.layout.fragment1,null); // 給fragment上的按鈕新增點選事件 v.findViewById(R.id.btn_change).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //拿到frgment---fragment之間的通訊 Fragment2 f2= (Fragment2) getActivity().getFragmentManager().findFragmentByTag("two");//two是fragment2的tag, 切換fragmentbeginTracsaction.replace(R.id.lltwo,new Fragment2(),"two");中two是tag f2.changeStr("我要改變世界"); } }); return v; } }
_________________fragment與activity之間的通訊__-----------
------activity傳值給fragment-------
方法一:在activity中建一個bundle,把要傳的值存入bundle,然後通過fragment的setArguments(bundle)傳到fragment,在fragment中,用getArguments接收, activity中: FragmentTransaction ft=fm.beginTransaction(); OneFragment oneFragment=new OneFragment(); ft.replace(R.id.frame,oneFragment,"f1"); Bundle bundle=new Bundle(); bundle.putString("one","要傳的值"); oneFragment.setArguments(bundle); ft.commit(); OneFragment中: Bundle bundle=getArguments(); String s=bundle.getString("one");
方法二:
可以看到Fragment比Activity多了幾個額外的生命週期回撥方法:
onAttach(Activity)
當Fragment與Activity發生關聯時呼叫。
onCreateView(LayoutInflater, ViewGroup,Bundle)
建立該Fragment的檢視
onActivityCreated(Bundle)
當Activity的onCreate方法返回時呼叫
onDestoryView()
與onCreateView想對應,當該Fragment的檢視被移除時呼叫
onDetach()
與onAttach相對應,當Fragment與Activity關聯被取消時呼叫
注意:除了onCreateView,其他的所有方法如果你重寫了,必須呼叫父類對於該方法的實現,
在fragmentOne中:
public class FragmentOne extends Fragment { private Button btn; private TextView text; private String str; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View v=inflater.inflate(R.layout.fragmentone,null); // 給fragment上的按鈕新增點選事件 text = v.findViewById(R.id.tv_fragmentone); btn = v.findViewById(R.id.getImgae); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { } }); text.setText(str); // return inflater.inflate(R.layout.fragmentone,container,false); return v; } @Override public void onAttach(Context context) { super.onAttach(context); str = ((MainActivity)context).toFragmentone(); Log.e("ss",str); } }
在MainActivity中:
//給FragmentOne傳值 public String toFragmentone(){ return "fragmentone"; }
-----fragment傳值給activity----
******通過在fragment中實現介面的方式,Fragment向Activity傳值的步驟 介面回撥傳遞(5部曲)
1.fragment中準備回撥介面 介面中宣告傳值的回撥方法
2.在fragment中定義屬性private MyListener myListener
3.重寫fragment中的onAttach()方法:listener = (MyLisener)getActivity();
4.fragment觸發事件時回傳值
5.Activity中實現回撥介面 重寫回調方法獲取回傳的值並顯示
在fragment中:
importandroid.content.Context;
public class FragmentOne extends Fragment { private Button btn; private TextView text; private String str; // private MainActivity ac; private MyListener ac; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View v=inflater.inflate(R.layout.fragmentone,null); // 給fragment上的按鈕新增點選事件 text = v.findViewById(R.id.tv_fragmentone); btn = v.findViewById(R.id.getImgae); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //通過呼叫在activity中實現的介面方法,吧資料傳給Mainactivity ac.sendContent("dddd"); } }); // return inflater.inflate(R.layout.fragmentone,container,false); return v; } //activity和fragment聯絡時候呼叫,fragment必須依賴activty @Override public void onAttach(Context context) { super.onAttach(context); //獲取實現介面的activity ac = (MyListener) getActivity();//或者ac=(MainActivity) context; } //①定義回撥介面 public interface MyListener{ public void sendContent(String info); } }在MainActivity中:
importcom.example.wofu.aichi010.Fragment.FragmentOne.MyListener;//fragmentOne中的介面 public class MainActivity extends BaseActivity implements RadioGroup.OnCheckedChangeListener,MyListener{
//fragmentOne中的介面,在這實現,以實現fragmentOne傳值Mainactivity public void sendContent(String info) { if (info!=null && !"".equals(info)) { Log.e("sss",info); }else { } } }
**********EventBus實現fragment向Activity傳值**********
EventBus是一款Android下的釋出/訂閱事件匯流排機制。可以代替Intent、Handler、Broadcast等在Fragment、Activity之間傳遞訊息。優點:開銷小,程式碼優雅。將傳送者和接受者解耦。*****新增依賴 implimentation 'org.greenrobot:eventbus:3.0.0' ******EventBus的三要素 Event:事件,可以是任意型別的物件。 Subscriber:事件訂閱者,在EventBus3.0之前訊息處理的方法只能限定於onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,他們分別代表四種執行緒模型。而在EventBus3.0之後,事件處理的方法可以隨便取名,但是需要新增一個註解@Subscribe,並且要指定執行緒模型(預設為POSTING)。 Publisher:事件釋出者,可以在任意執行緒任意位置傳送事件,直接呼叫EventBus的post(Object)方法。可以自己例項化EventBus物件,但一般使用EventBus.getDefault()就好了,根據post函式引數的型別,會自動呼叫訂閱相應型別事件的函式。 ******** EventBus的四種執行緒模型(ThreadMode) POSTING(預設):如果使用事件處理函式指定了執行緒模型為POSTING,那麼該事件在哪個執行緒釋出出來的,事件處理函式就會在這個執行緒中執行,也就是說釋出事件和接收事件在同一個執行緒。線上程模型為POSTING的事件處理函式中儘量避免執行耗時操作,因為它會阻塞事件的傳遞,甚至有可能會引起應用程式無響應(ANR)。 MAIN:事件的處理會在UI執行緒中執行。事件處理時間不能太長,長了會ANR的。 BACKGROUND:如果事件是在UI執行緒中釋出出來的,那麼該事件處理函式就會在新的執行緒中執行,如果事件本來就是子執行緒中釋出出來的,那麼該事件處理函式直接在釋出事件的執行緒中執行。在此事件處理函式中禁止進行UI更新操作。 ASYNC:無論事件在哪個執行緒釋出,該事件處理函式都會在新建的子執行緒中執行,同樣,此事件處理函式中禁止進行UI更新操作。普通的方法是先註冊(register),再post,才能接受到事件;如果你使用postSticky傳送事件,那麼可以不需要先註冊,也能接受到事件,也就是一個延遲註冊的過程。粘性事件就是為了解決這個問題,通過 postSticky 傳送粘性事件,這個事件不會只被消費一次就消失,而是一直存在系統中,直到被 removeStickyEvent 刪除掉。那麼只要訂閱了該粘性事件的所有方法,只要被register 的時候,就會被檢測到,並且執行。訂閱的方法需要新增 sticky = true 屬性。該廣播發送後,會儲存在記憶體中,如果後來有註冊的Receiver與之匹配,那麼該Receiver便會接收到該廣播。那麼粘性事件同理,在註冊之前便把事件發生出去,等到註冊之後便會收到最近傳送的粘性事件(必須匹配)。注意:只會接收到最近傳送的一次粘性事件,之前的會接受不到;
****舉例*****
普通事件:
//註冊成為訂閱者 EventBus.getDefault().register(this);
//訂閱方法,當接收到事件的時候,會呼叫該方法 @Subscribe(threadMode = ThreadMode.MAIN) public void onEvent(MessageEvent messageEvent){ textView.setText(messageEvent.getMessage()); } @Override protected void onDestroy() { super.onDestroy(); //解除註冊 EventBus.getDefault().unregister(this); }
在另一個activity或者fragment中post事件:
與觀察者模式對應的,當有事件發生,需要通知觀察者的時候,被觀察者會呼叫notifyObservers()方法來通知所有已經註冊的觀察者,在EventBus中,對觀察者模式底層進行了封裝,我們只需要呼叫以下程式碼就能把事件傳送出去:
EventBus.getDefault().post(new MessageEvent("傳送的訊息"));
@Subscribe註解,該註解標識了當前方法為訂閱方法;該註解內部有三個成員,分別是threadMode、sticky、priority。threadMode代表訂閱方法所執行的執行緒,sticky代表是否是粘性事件,priority代表優先順序。給這個三個成員賦不同的值,能使得訂閱方法有著不同的效果。
*******ThreadMode是一個列舉型別,有著以下幾個型別:
POSTING:表示訂閱方法執行在傳送事件的執行緒。
MAIN:表示訂閱方法執行在UI執行緒,由於UI執行緒不能阻塞,因此當使用MAIN的時候,訂閱方法不應該耗時過長。
BACKGROUND:表示訂閱方法執行在後臺執行緒,如果傳送的事件執行緒不是UI執行緒,那麼就使用該執行緒;如果傳送事件的執行緒是UI執行緒,那麼新建一個後臺執行緒來呼叫訂閱方法。
ASYNC:訂閱方法與傳送事件始終不在同一個執行緒,即訂閱方法始終會使用新的執行緒來執行。
ThreadMode預設是使用POSTING的,如果需要更改設定,可以在添加註解的時候同時為threadMode賦值。 *****.priority 優先順序 設定該優先順序的目的是,當一個事件有多個訂閱者的時候,優先順序高的會優先接收到事件。
粘性事件:
註冊粘性事件 EventBus.getDefault().register(this); 傳送粘性事件: EventBus.getDefault().postSticky(new MessageEvent("傳送粘性事件")); 接受粘性事件: @Subscribe(sticky = true) public void onEvent(MessageEvent messageEvent){ Log.d("cylog","接受到了來自EventBus的事件:"+messageEvent.getMessage()); } 取消註冊 @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); }