Android中消息傳遞,看這一篇足夠了

   上次寫了Android的文件存儲,這是和外界的信息交流,今天來寫個Android的內部的信息交流,Android的消息傳遞方式。

    該博客分爲以下幾個方面:  1、Android 常見的需要傳遞數據的地方
                                                                                                          Activity與Activity
                                                                                                          Activity 與 Fragment
                                                                                                          Activity 與 Service

                                                2、常見的傳遞數據的方式
                                                                                          這四種方式適用於所有的傳遞數據的地方
                                                                                                           EventBus方式傳遞數據
                                                                                                            BroadCast方式傳遞數據
                                                                                                            觀察者模式傳遞數據
                                                                                                            接口回調

                                               3、對所有的方式進行代碼演示,和比較

                                               4、格外經驗  Fragment的生命週期,多個切換的處理方法
 

    首先簡單的介紹一下,需要傳遞消息的地方。Activity 和 Activity 之間的傳遞數據,初學者都找到 Intent 切了頁面也穿了數據(很low),Activity 向 Fragemnt 傳遞數據(Bundle),Fragment向Activity傳遞數據(回調接口),這些最Android的入門。

     然後再簡單的介紹傳遞數據的幾種方式,代碼已經上傳到Github上面 地址:https://github.com/KEYD111/AndroidMessageHandler,請大家對照着代碼看,註釋很詳細了。

     2.1  Handler Message  網上說可以可以在Activity和Fragment之間使用,沒試過,感覺那樣,代碼會顯得雜亂無章,個人建議在一個類中使用就行了

      2.2 廣播的方式,該博客不具體介紹,想知道的看我的另外一篇博客  

                        BroadCast的兩種使用方法                   https://mp.csdn.net/postedit/83044862

      2.3 EventBus 的方式   該博客不具體介紹,想知道的看我的另外一篇博客  

                        Android中EventBus(事件總線)傳遞數據           https://mp.csdn.net/postedit/83044862

             這兩種方式,都已經介紹的很詳細,關鍵如果放在一個工程中,大家不容易看。因爲東西太多了

      2.4 接口回調的方式,  很方便,快捷

      2.5 觀察者模式  下面着重介紹觀察者模式。

3.代碼演示

    先把簡單的說了,再來難的  在 MainActivity 生成兩個數  int 0 開始遞增    char A 遞增到 Z

new Timer().schedule(new TimerTask() {
    @Override
    public void run() {
        //生成兩個一直動態變換的數據 1000週期
        count++;
        Log.i("dachen main", "count:" + count + "");
        if (achar == 'Z') {
            achar = 'A';
        }
        achar = (char) (achar + 1);
        Log.i("dachen main", "tmp:" + new String(new char[]{achar}));  //char 轉字符串
    }
}, 0, 1000);

  3.1 Activity和Activity通信:

//這種方式 沒什麼卵用,根本不靠譜
Intent intent1 = new Intent(this, BroadcastActivity.class);
intent1.putExtra(IStatus.IStatus_Act2ActKey, IStatus.IStatus_Act2Actvalue);
startActivity(intent1);

3.2 Activity傳數據到Fragment

MainActivity中代碼爲:

Bundle bundle1 = new Bundle();   
bundle1.putString(IStatus.IStatus_Act2FragKey1, IStatus.IStatus_Act2FragValue1);
bundle1.putString(IStatus.IStatus_Act2FragKey2, IStatus.IStatus_Act2FragValue2);
bundle1.putString(IStatus.IStatus_Act2FragKey3, IStatus.IStatus_Act2FragValue3);
if (fragmentTest1 != null) {
    fragmentTest1.setArguments(bundle1);
}  這種方式有一個空指針異常的問題,看代碼中的巧妙解決的方法,這邊就給出重點代碼

Fragment中代碼爲:

if (isAdded()) {
         //此處也有處理空指針異常的方法,萬一不讓讀者混亂,放在了代碼中顯示
        String a1 = getArguments().getString(IStatus.IStatus_Act2FragKey1);
        String a2 = getArguments().getString(IStatus.IStatus_Act2FragKey2);
        String a3 = getArguments().getString(IStatus.IStatus_Act2FragKey3);
        Log.i("dachen", "Frag1  Bundle方式接受來自Activity的數據爲 " + "a1:" + a1 + ",a2:" + a2 + ",a3:" + a3);
}

3.3 Fragment向Activity中傳遞數據

      

//通過回調函數傳遞值
Fragment中代碼爲
在線程中將 數據
if (myCallBackListener != null) {
    myCallBackListener.onDataChange2(i + "");
} 傳出去
private MyCallBackListener myCallBackListener;

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    myCallBackListener = (MyCallBackListener) context;
}

public interface MyCallBackListener {
    public abstract void onDataChange2(String data);
}

   MainActivity 中實現接口 

FragmentTest1.MyCallBackListener  然後數據就來了。

3.4 Service向MainActivity中傳遞數據

       Service和Activity的區別就是一個看得見,一個看不見,所以都得在Androidmanifest中註冊。

      Service中代碼,繼承Service的類

@Override
public IBinder onBind(Intent intent) {
    return new Binder2();
}


//全部返回回去
public class Binder2 extends Binder {
    public MySerice2 getService() {
        return MySerice2.this;
    }
}

@Override
public void onCreate() {
    super.onCreate();
    connecting = true;
    new Thread(new Runnable() {
        @Override
        public void run() {
            int i = 0;
            while (connecting == true) {
                i++;
                if (callBack2 != null) {
                    callBack2.onDataChange2(i + "");
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }).start();
}

public void setCallback2(CallBack2 callback2) {
    this.callBack2 = callback2;

}

public static interface CallBack2 {
    void onDataChange2(String data);
}

@Override
public void onDestroy() {
    super.onDestroy();
    connecting = false;
}
在MainActivity中的接受,
bindService(new Intent(this, MySerice2.class), serviceConnection2, BIND_AUTO_CREATE);  先綁定
ServiceConnection serviceConnection2 = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service2) {
        MySerice2.Binder2 binder2 = (MySerice2.Binder2) service2;
        final MySerice2 mySerice2 = binder2.getService();
        mySerice2.setCallback2(new MySerice2.CallBack2() {
            @Override
            public void onDataChange2(String data) {
               Log.i("dachen","接受來自Service的數據:"+data);
            }
        });
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
};    //這樣就不需要實現接口,但是也可以實現 ServiceConnection 的接口, 數據來了

4  觀察者模式

    準確的來說,觀察者模式,不是Android特定的,以上的有些方法,必須在Android中纔可以使用,現在觀察者模式 C++,Java,php 都有,這只是一種思想。簡單的來說,觀察者模式,可以簡單的認爲就是廣播,和EventBus都是類似的東西。個人理解爲,就是對一個構造類的 set() get() 方法,做到了代碼的耦合性,便於管理,觀察者設計模式定義了對象間的一種一對多的組合關係,以便一個對象的狀態發生變化時,所有依賴於它的對象都得到通知並自動刷新。

     首先觀察者模式自己實現,或是利用官方給的接口。

    以下   目標類(被觀察者)  具體的目標類       觀察者    具體的觀察者      這些需要 Java的基礎,不懂的可以仔細的去研究一下,觀察者模式是行爲型設計模式,需要一定(創建,構造的思想)。但是你如果只是簡單的想傳遞數據的話,按我的方法,一個發送,一個接受就完事了,很簡單。

    但是,不能坑大家,我還是得介紹一下記住了:     觀察者是實現接口     對象是繼續父類

     原理 A 創建觀察者接口  

                 public interface Observer {
                        //將觀察的對象傳進來
                    public abstract void update(Subject1 subject1);
                 }

             B 創建對象的類 Subject1

public class Subject1 {

    protected List<Observer> list = new ArrayList<>();  //存放觀察主題對象的所有的觀察者

    public void registerNewObserver(Observer obs) {   //增加新的觀察者
        list.add(obs);
    }

    public void removeOldObserver(Observer obs) {  //刪除舊的觀察者
        list.remove(obs);
    }

    //通知所有的觀察者更新狀態
    public void notifyAllObservers() {
        for (Observer obs : list) {
            obs.update(this);
        }
    }
}

C  實例化  類  

public class ConcreteSubject extends Subject1 {

    private int state;    //具體的方法

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
        this.notifyAllObservers();    //目標對象的值發生改變通知所有的觀察者
    }
}

D 實例化觀察者  接口

public class ConcreteObserver implements Observer {
    public int getMyState() {
        return myState;
    }

    public void setMyState(int myState) {
        this.myState = myState;
    }

    private int myState;   //myState需要跟目標對象的state值保持一致

    @Override
    public void update(Subject1 subject1) {
        myState = ((ConcreteSubject) subject1).getState();
    }
}

然後測試一下

//觀察者模式測試
private void ModelOfObserver() {
    //創建目標對象
    ConcreteSubject subject = new ConcreteSubject();

    //創建多個觀察者
    ConcreteObserver concreteObserver1 = new ConcreteObserver();
    ConcreteObserver concreteObserver2 = new ConcreteObserver();
    ConcreteObserver concreteObserver3 = new ConcreteObserver();

    //添加觀察者  添加到 subject的容器中去
    subject.registerNewObserver(concreteObserver1);
    subject.registerNewObserver(concreteObserver2);
    subject.registerNewObserver(concreteObserver3);

    //改變 subject 的狀態
    subject.setState(3000);
    Log.i("dachen", concreteObserver1.getMyState() + "");
    Log.i("dachen", concreteObserver2.getMyState() + "");
    Log.i("dachen", concreteObserver3.getMyState() + "");

    subject.setState(30);
    Log.i("dachen", concreteObserver1.getMyState() + "");
    Log.i("dachen", concreteObserver2.getMyState() + "");
    Log.i("dachen", concreteObserver3.getMyState() + "");
}   
 package爲observer

  大家注意了,,,,,數據的改變是在目標的那個類裏面,監聽的改變是在觀察者的那個類裏面,main只是作爲一個類似緩衝區的地方,數據不是在 main 中監聽的,打印出來只是爲了方便大家看,,我代碼中具體的有演示效果。

       這是原理,大家一看頭疼,太多了,實現一個數據傳遞要這麼多東西,所以我們可以直接用官方的,繼承 和 接口  同樣數據也是在裏面實現的,,大家需要觀察的數據對象繼承類實現,放在線程中變換數據,需要得到的數據的類實現觀察者的接口,理論比較抽象,看代碼   package 爲 modelofobserver   不懂的代碼中註釋多多,程序員,不要天天看文字。我是很討厭看文字。

       那麼問題來了,覺得這樣子好煩,每次要獲得一個數據,都要實現接口,能不能有種向以前的那種方法,比如說 MainActivity中扔出一個數據,誰要,誰去接受,當然可以,參考別人的博客https://blog.csdn.net/wbwjx/article/details/51587887

      我自己做了實現 package observer , 你們用的時候,直接把三個文件複製進去進行了

       假設  MainActivity 傳數據給 Fragment 則這個樣子寫

        Main中  

Object notify1 = ObservableManager.newInstance()
        .notify(IStatus.IStatus_ObserverKey1, "使用觀察者模式COPY傳遞數據:", count, achar);

      就這麼簡單    IStatus.IStatus_ObserverKey1    KEY 

                            "使用觀察者模式COPY傳遞數據:", count, achar   Value   想傳多少傳多少,都不要list了 很方便了

     Fragment中    

ObservableManager.newInstance().registerObserver(IStatus.IStatus_ObserverKey1, this);  註冊  實現接口
@Override
public Object function(Object[] data) {
    Log.i("dachen fragment1", String.valueOf(data[0]) + "," + String.valueOf(data[1]));
    return "我是fragment1的返回結果";
}     數據來了   他還有反饋    很人性化  很方便  

   差不多就結束了,,強烈建議大家,對照着代碼來看,作者全部實現成功了。

   還有個小問題,就是存在多個 Fragment 但是,又不想每個 fragment 啓動後都接受數據,或是啓動 切換不銷燬,但是隻想在 有View的時候接受數據,我的代碼中已經處理好了。簡單的介紹一下吧,這是具體問題的處理方法。

   首先如何切換 Fragment  android 4.3   和 Android5.1 以後的方法是不一樣的,需要獲得  getSupportFragmentManager();

   然後切換的方式,我自己用過的有兩種,一個是 replace 一個是 hide ,還有一個是 viewpager 大家有興趣自己看,我沒有親自實踐,所以不介紹。

   replace 是 切換的時候直接將前面的一個銷燬了, hide只是隱藏了,我個人喜歡hide   避免不必要的錯誤。

   講一下 fragment的生命週期,學習https://www.jianshu.com/p/c8f34229b6dc 他的博客

hide的方法時:

  • Fragment1 的生命週期變化爲:onCreate()、onCreateView、onStart()、onResume() 回調 onHiddenChanged() 方法

  • Fragment2 的生命週期變化爲: onCreate()、onCreateView、onStart()、onResume()

  • Fragment 2 再次返回到 Fragment 1:不走任何生命週期方法但是回調 onHiddenChanged()方法


replace的方法時:

  • 載入Fragment 1時:

Fragment 1的生命週期:onCreate()、onCreateView()、onStart()、onResume()

  • 切換到Fragment2時:

Fragment 1的生命週期:onPause()、onStop()、onDestroyView()、onDestroy()

Fragment 2的生命週期:onCreate()、onCreateV()、onStart()、onResume()

  • Fragment 2切換回Fragment 1時:

Fragment2的生命週期:onPause()、onStop()、onDestroyView()、onDestroy()

Fragment 1的生命週期:onCreate()、onCreateV()、onStart()、onResume()

 hide 方法,將數據變化方法 onhiddenchange 裏面 ,上面的數據傳遞的處理

    ObservableManager.newInstance().removeObserver(this);
} else
    ObservableManager.newInstance().registerObserver("MAINSEND1", this);

 不足之處,請大家不吝賜教,如果侵權,請儘快聯繫作者。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章