オブザーバーモードを使用して、単一Activityと複数のFragment通信を解決

8703 ワード

今のところ、私が知っているactivityとfragmentの間の通信方式はまだたくさんあります.例:
  • Handler方式
  • インタフェース方式
  • 公有方法
  • 放送方式
  • EventBus

  • この5つの方法を少し分析すると、Handler方式はHandlerを理解している人が最も考えやすいが、Handlerは各モジュール間の結合性を高めるだけでなく、一方向通信しかできない.例えば、ActivityでHandlerをインスタンス化すると、FragmentからActivityにしかメッセージを送信できないが、逆にActivityからFragmentにメッセージを送信すると実現しにくく、双方向ではない以上、ではFragment間の通信も実現できません.
    インタフェース方式は最も簡単で使いやすい方法で、Handler方式が需要を満たすことができないと確信したとき、私はすぐにインタフェースを思い出しました.しかし、私が実践してみると、インタフェース方式は依然としてだめで、一対一の通信であれば、インタフェースは最も良い案かもしれません.軽くて、性能に少しも影響しません.しかし、1つの(Activity)対マルチ(Fragment)通信であれば、Activityによってインタフェースが実現され、Fragmentがインタフェースを呼び出し、Activityにメッセージを送信するしかない.逆にだめです.多くのインタフェースを定義する必要があります.Fragmentごとに異なるインタフェースを実現する必要があります.それからActivityは各インタフェースをインスタンス化して呼び出します.数十個のFragmentがActivityに情報を送信する必要がある場合、Activityに数十個のインタフェースを実現させなければなりません.これはどんなに愚かなことで、インタフェースを使ってもFragment間の通信を実現できません.
    公有の方法とは、互いに相手を呼び出して公開される方法である.例えば、Fragmentで宿主Activityの共通メソッドを呼び出すこともできるし、宿主Activityで他のFragmentを検索し、Activityで少し判断してから、自身または他のFragmentのメソッドを呼び出すこともできる.しかし、これはプログラム間の結合性を大幅に増加させ、今後のメンテナンスと拡張に不利である.
    次にブロードキャスト、ブロードキャストはシステム内のすべてのアプリケーションに通知を送信できる仕組みであり、ブロードキャストを用いて単一のAPP内部のメッセージ通信を完了し、牛刀を使っているような感じがする.また、ブロードキャストによって送信される必要があるオブジェクトに対してシーケンス化インタフェースを実現することは、性能にわずかな影響を与えるため、一般的にブロードキャストを用いずに通信を行う.
    最後にEventBusであり、EventBusのコアもオブザーバーモードであり、イベントを購読することで通知情報を受け取り、同時に対応するメソッド名を反射することでメッセージの通信を実現することは、パフォーマンスに一定の影響を及ぼすに違いない(3.0バージョンでは反射は使用されなくなり、注釈によって実現され、反射検索方法の多くの弊害を免れた).コードが混同されたときにEventBusに対する混同を残すと、メソッド名が露出し,逆方向に口を残すが,強制的に混同すると反射によって対応するメソッドが見つからない.(本節は3月22日に改正)
    こんなにたくさん言った以上、どの方法もあまり理想的ではないようですが、他にどんな方法がありますか.私はこれらのいくつかの方法に対していくつかのマイナスの評価をしたが、これらの方法を使わないわけではない.私自身が使っている方法は、実はHandlerとインタフェースの結合です.ActivityにはHandlerでメッセージを送信し,観察モードのインタフェースでFragmentにメッセージを送信する.Handlerを使用すると、ActivityとFragmentの間に一定の結合性が存在することは確かですが、影響は最小限に抑えられます.拡張または修正するには、Fragmentのコードを変更するだけです.インタフェースの使用は完全にデカップリングされている.そのため、現在は比較的適切で、比較的便利な方法です.
    Handlerの使用は通常の使用と同じで、Activityではnewが1つのHandlerで、もちろんこのHandlerはstaticではありません.FragmentがActivityまたは他のFragmentにメッセージまたは通知を送信する必要がある場合、すでにバインドされているHandlerによってメッセージを送信することができ、メッセージにはkeyが携帯され、このメッセージを送信する意図が何であるかを示す.Activityはメッセージを取得するとkeyに基づいて応答し、自身のメソッドを呼び出すこともできるし、『オブザーバーインタフェース』によって調整通知を発行することもできる.もちろんこの通知はkey情報も持ち込み、観察者と観察者の間に中継局があり、その中で中継局は『観察者』からの更新を受け取り、その更新内容を中継局に登録された『観察者』に送信し、最後に『観察者』インタフェースを実現したFragmentはすべて更新されたメッセージを受け取り、それぞれのメッセージを判断し、合理的な応答を行う.これがHandlerが観察者モードと結合する方法である.私の現在のアプリケーションアーキテクチャにとって、これは最高の解決策です.
    次のコードは、まずオブザーバインタフェースです.
    /**
     * Created by Alpha on 2017/3/15.
     *  , 
     */
    
    public interface Observable{
    
        void registerObserver(Observer observer);
    
        void removeObserver(Observer observer);
    
        void notifyObservers();
    }
    

    オブザーバインタフェース:
    /**
     * Created by Alpha on 2017/3/15.
     *  , 
     */
    
    public interface Observer {
    
        void update(String msg);
    
    }
    

    私のアプリケーションの内部間ではkey通知を相互に発行するだけでよいので、観察者インタフェースの方法は1つのパラメータしかありません.あなたも自分の必要に応じてパラメータを追加します.例えば、Obkectや汎用型などです.メッセージ管理センターがどのように実現されているかを見てみましょう.
    /**
     * Created by Alpha on 2017/3/15.
     *  
     */
    
    public class EventManager implements Observable {
    
        /**
         *   inbox  ,  inbox   item  
         */
        public static final String TO_INBOX_FRAGMENT = "delete_and_update_inbox";
    
        private List observers;
        private String message;
    
        public void publishMessage(String message) {
            this.message = message;
            notifyObservers();
        }
    
        public EventManager(List observers) {
            this.observers = observers;
        }
    
    
        @Override
        public void registerObserver(Observer observer) {
            observers.add(observer);
        }
    
        @Override
        public void removeObserver(Observer observer) {
            int i = observers.indexOf(observer);
            if (i > 0) {
                observers.remove(i);
            }
        }
    
        @Override
        public void notifyObservers() {
            for (Observer o : observers) {
                o.update(message);
            }
        }
    }
    

    実は標準的な観察者パターンの書き方です.ここでは、keyの識別に他のクラスの参照を提供する定数を内部的に定義しました.実際にJava内部でも観察モードインタフェースが提供されていますが、Java内部では観察者が自由に観察者にデータを取ることができるように、観察者をインタフェースではなくクラスとして定義するため、拡張性が悪くなり、観察者が他のクラスから統合しなければならない場合は使用できないので、自分で観察者モードを書きましょう.どうせコードもあまりありません.
    オブザーバーモードが作成されると、Activityで時間管理者をインスタンス化してメッセージを送信できます.
        public Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case REQUEST_NEW_AGENDA:
                        eventManager.publishMessage(EventManager.TO_INBOX_FRAGMENT);
                        eventManager.notifyObservers();
                        break;
                }
                super.handleMessage(msg);
            }
        };
    

    便宜上、私が観察者インタフェースで定義した方法パラメータのタイプはMessageであり、Handlerメッセージメカニズムとある程度適切であり、メッセージタイプを別途カスタマイズする必要はない.このような双方向通信のメッセージメカニズムは完成したが、私のこのような混同スタイルについて、以前ネット上で資料を調べたとき、この文章を見た:観察者モードを使ってactivityとfragment通信の問題を完璧に解決し、ブロガーは単純に観察者モードを使って双方向通信を実現し、Handlerを使っていないので、とてもすごいと感じた.でも正直に言うと、私の今のレベルで、最後の観察者モードの内容は、私には読めませんでした...私が行く道はまだ長いようですね.
    2017年3月16日に更新
    昨日文章を書いた後、また自分で完全に実現して、やはりいくつかの点を言う必要があることに気づきました.

    BaseFragment


    私が昨日考えたように、MainActivityでEventManagerのインスタンスをインスタンス化し、各FragmentにEventManagerパラメータ付きの構造方法を追加し、各Fragmentに登録と逆登録を行うと冗長になります.後に比較的簡便な使い方が発見されたので、Fragmentが多くなると必ずBaseFragmentというベースクラスがあるのではないかと思いますが、BaseFragmentで登録と逆登録をすればよいだけで、具体的な実装クラスFragmentはベースクラスの対応する構造方法を継承するとともに、ベースクラスで観察者インタフェースを実現すれば観察者の登録を完了することができます.これにより,各実装クラスでインタフェース実装を行う必要がなくなり,多くの力が省けただろう.具体的なコードは以下の通りです.
    /**
     * Created by Alpha on 2017/3/15.
     */
    
    public class BaseFragment extends Fragment implements Observer {
        protected EventManager eventManager;
        protected Handler handler;
    
        public BaseFragment(EventManager eventManager) {
            this.eventManager = eventManager;
            eventManager.registerObserver(this);
        }
    
        @Override
        public void onAttach(Context context) {
            super.onAttach(context);
            if (context instanceof MainActivity) {
                MainActivity activity = (MainActivity) context;
                this.handler = activity.mHandler;
            }
        }
    
        @Override
        public void onUpdate(Message msg) {
            throw new RuntimeException("must override this method in Observer!");
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            eventManager.removeObserver(this);
        }
    }
    

    私は同時にベースクラスでMainActivityのHandlerとEventmanagerを手に入れ、アクセスの性質は保護タイプで、そのサブクラスの呼び出しを便利にしました.インタフェースのメソッドはサブクラスでコンパイラが自動的に上書きしないため,ベースクラスに異常を投げ出し,サブクラスにこのメソッドを再実現させ,すなわち自分の必要に応じてメッセージの受信と判断を行う.このようなクラスはベースクラスBaseFragmentを実装する際にベースクラスの構造方法を継承するように要求され,EventManagerの参照を取得し,下位レベルでベースクラスによって登録と逆登録を行うことができる.したがって、MainActivityでFragmentをインスタンス化するときにEventManagerへの参照が必要になります.たとえば、次のようになります.
        private void initFragment() {
            // fragment
            fragmentList = new ArrayList<>();
            inboxFragment = new InboxFragment(eventManager);
            eventFragment = new EventFragment(eventManager);
            memoFragment = new MemoFragment(eventManager);
            contextFragment = new ContextFragment(eventManager);
            finishFragment = new FinishFragment(eventManager);
            trashFragment = new TrashFragment(eventManager);
            fragmentList.add(inboxFragment);
            fragmentList.add(eventFragment);
            fragmentList.add(memoFragment);
            fragmentList.add(contextFragment);
            fragmentList.add(finishFragment);
            fragmentList.add(trashFragment);
            fragmentManager = getSupportFragmentManager();
            transaction = fragmentManager.beginTransaction();
            transaction.add(R.id.content_frame, inboxFragment);
            transaction.add(R.id.content_frame, eventFragment);
            transaction.add(R.id.content_frame, memoFragment);
            transaction.add(R.id.content_frame, contextFragment);
            transaction.add(R.id.content_frame, finishFragment);
            transaction.add(R.id.content_frame, trashFragment);
            hideAllFragment(transaction);
            transaction.show(inboxFragment);
            fragPosition = 0;
            transaction.commitAllowingStateLoss();
        }
    

    特定のBaseFragmen実装クラス:
        public InboxFragment(EventManager eventManager) {
            super(eventManager);
        }
    
        @Override
        public void onUpdate(Message msg) {
            switch (msg.what) {
                case InboxEvent.INBOX_ADD:
                    showTextDialog(msg.obj.toString());
                    break;
                case InboxEvent.INBOX_UPDATE:
                    updateInboxData();
                    break;
            }
        }
    

    この文書は、http://alphagao.com/2017/03/15/using-observer-pattern-deal-event-between-activity-and-fragments/.