1. 程式人生 > >android之fragment與fragment、activity與activity、fragment與activity之間的通訊

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);
        }