As far as I know, there are many ways to communicate between activities and fragments. Such as:

  1. Handler way
  2. The interface way
  3. Public methods
  4. Radio program
  5. EventBus

Handler not only increases the coupling between modules, but also one-way communication. For example, if you instantiate Handler in an Activity, The Fragment can only send a message to the Activity, but if the Activity sends a message to the Fragment in reverse, communication between the fragments will not be possible.

The interface approach was the easiest one to use, and when I decided that the Handler approach wasn’t going to cut it, I immediately thought of interfaces. However, after some practice, I found that the interface method still does not work. If only one-to-one communication, interface may be the best solution, which is not only portable, but also does not affect the performance at all. However, if one Activity communicates with many fragments, the interface can only be implemented by the Activity. The Fragment calls the interface and sends messages to the Activity. The reverse is not true. You need to define multiple interfaces, implement different interfaces for each Fragment, and then instantiate each interface to call the Activity. If there are dozens of fragments that need to send information to the Activity, You would have to implement dozens of interfaces for your Activity, which would be a silly thing to do, and you wouldn’t be able to communicate between fragments using interfaces.

As for public methods, they call each other’s exposed methods. For example, you can call a public method in a Fragment from the host Activity, or you can find another Fragment from the host Activity, and then you can make a judgment in the Activity, and then call itself or other methods in the Fragment. However, this will greatly increase the coupling between programs, which is not conducive to future maintenance and expansion.

Then the broadcast, broadcast available to all applications in the system is a kind of that send a notification mechanism, using radio to complete a single message communication within the APP, a little kill chicken in a profound sense, how also need to be sent through radio object serialized interface, slightly affect performance, so don’t usually use radio to communicate.

Finally, There is EventBus, which is difficult to evaluate because I haven’t used it yet, but it also uses reflection to communicate messages inside EventBus, which will definitely have an impact on performance.

With all this said, it seems that every method is not ideal, so what else is there? I’ve made some negative comments about all of these methods, but that’s not to say they shouldn’t be used. My own approach is actually a combination of Handler and interface. Use the Handler to send information to the Activity, and use the interface in watch mode to send information to the Fragment. While using Handler does lead to some coupling between activities and fragments, this minimizes the impact. If you want to expand or modify your Activity, you only need to modify the code in your Fragment. The use of interfaces is completely decoupled. Therefore, it is a more suitable and relatively convenient method at present.

Handler is used just as it would be in normal use. Create a new Handler in your Activity. Of course, this Handler cannot be static. When a Fragment needs to send a message or notification to an Activity or other Fragment, it can send the message through a Handler that has been bound to it. The message carries a key that indicates the purpose of the message. When an Activity receives a message, it responds based on the key. It can either call its own methods or send adjustment notifications through the Observable interface, which also carries key information. There is a hub between the observable and the observer. The updated content will be sent to every “observer” registered in the relay station. Finally, all fragments implementing the interface of “observer” will receive the updated message, and then judge the message individually and make a reasonable response. This is how the Handler is combined with the observer pattern. This is the best solution for my current application architecture.

Here’s the code, starting with the observable interface:

/** * Created by Alpha on 2017/3/15. * Observable interface to notify event producers */

public interface Observable{

    void registerObserver(Observer observer);

    void removeObserver(Observer observer);

    void notifyObservers(a);
}Copy the code

Observer interface:

/** * Created by Alpha on 2017/3/15. * Observer interface, notifying event recipients */

public interface Observer {

    void update(String msg);

}Copy the code

Since my apps only need to send key notifications to each other internally, the methods in the Observer interface have only one parameter, and you can add parameters as needed, such as Obkect or generics, to increase adaptability. Take a look at how the message management center is implemented:

/** * Created by Alpha on 2017/3/15. * Event handler */

public class EventManager implements Observable {

    /** * Successfully adds inbox to the calendar, notifying the INBOX interface to remove the clicked item and update the display */
    public static final String TO_INBOX_FRAGMENT = "delete_and_update_inbox";

    private List<Observer> observers;
    private String message;

    public void publishMessage(String message) {
        this.message = message;
        notifyObservers();
    }

    public EventManager(List<Observer> 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(a) {
        for(Observer o : observers) { o.update(message); }}}Copy the code

It’s just the standard observer mode. I’ve internally defined constants here to provide reference for other classes to recognize keys. In fact, Java also provides the observation mode interface, but one of the disadvantages is that in order to enable the observer to freely fetch data from the observer, the observer is defined as a class, not an interface. Therefore, the scalability becomes poor. If the observer has to integrate with other classes, it will not be able to use it. So write your own observer mode, there’s not much code anyway.

With the observer mode written, you can instantiate a time manager in the Activity to send messages:

    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); }};Copy the code

For convenience, I defined the method parameter type as Message in the Observer interface, so that it fits in with the Handler messaging mechanism to a certain extent and does not need to customize the Message type. Such a two-way communication message mechanism is complete, but I think for this kind of mash-up style, before looking up information on the network, also saw this article: Using the observer mode perfectly solves the communication problem between activity and fragment. The blogger can realize two-way communication only using the observer mode, without using the Handler, which is very impressive. But to be honest, at my current level, I don’t understand the last observer mode… Looks like I got a long way to go.


Updated on March 16, 2017

Yesterday after writing the article and their own complete implementation again, found that there are still some points need to say:

BaseFragment

As I thought yesterday, instantiating an instance of EventManager in MainActivity and adding constructors with EventManager parameters to each Fragment requires registering and unregistering within each Fragment. So it becomes redundant. If you want to implement a BaseFragment class, you only need to register and unregister it in the BaseFragment class. If you want to implement a BaseFragment class, you only need to inherit the corresponding constructor of the base class. At the same time, the observer interface implemented by the base class can complete the observer registration. This saves a lot of effort by eliminating the need to implement the interface in every implementation class. The specific code is as follows:

/** * 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(a) {
        super.onDestroy();
        eventManager.removeObserver(this); }}Copy the code

I have both MainActivity Handler and Eventmanager in the base class, and the access nature is protected for its subclass to call. Because methods in an interface are not automatically overwritten by the compiler in subclasses, an exception is thrown in the base class to force the subclass to reimplement the method, which is to accept and judge messages as needed. Subclasses that implement the BaseFragment class will be required to inherit the constructor from the base class, so they can get a reference to the EventManager, and the base class will register and de-register the EventManager. Therefore, you need to pass a reference to the EventManager when instantiating the Fragment in the MainActivity, for example:

    private void initFragment(a) {
        // Preload all fragments
        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();
    }Copy the code

A concrete BaseFragmen implementation class:

    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; }}Copy the code

This article was originally published at alphagao.com/2017/03/15/… .