EventBus's Little Demo

Posted by shivangp on Tue, 04 Jun 2019 21:14:53 +0200

Preface

Before we talked about the observer mode, I must say EventBus. I've been looking at the source code of EventBus these days. I've seen the whole process and found the advantages of EventBus. But there are still some details that are not clear. Now we are at a stage where we don't know how to express them in language. So the source code parsing of EventBus will be delayed a little bit. Rry.

So I will write a demo first. Finally, on the basis of this demo, I will briefly talk about the performance optimization of EventBus for several functions.

text

First, let's think about the question: is it using Obserable and Obsever in Java, or do we define the observer and the observee ourselves?

I think so:

1. Semantically, Obserable and Obsever are slightly worse, and they repeat the naming of classes with some open source libraries, such as RxJava, which is easy to confuse.

2. If we use Obserable, every definition of the observer has to implement some internal details, that is, to define new classes, and we often distinguish between them by String or int to make it easier to manage.

So I think it's more convenient to implement the whole process by myself. That's not nonsense. The code starts.

First, the callback function is defined, and the observer implements the interface.

/**
 * Created by li.zhipeng on 2017/8/4.
 *
 *      EventBus Notification callback function
 */

public interface EventListener {

    void onEvent(int eventCode, Object object);
}

Redefining the observer:

/**
 * Created by li.zhipeng on 2017/8/4.
 * <p>
 * EventBus Subject class, which implements the main logic to be distributed by the observer
 */

public class EventBus {

    /**
     * Use the singleton pattern
     */
    private static EventBus instance;

    private EventBus() {
    }

    public synchronized static EventBus getInstance() {
        if (instance == null) {
            instance = new EventBus();
        }
        return instance;
    }


    /**
     * Preserve all observers and categorize them by observer
     * <p>
     * Here we use the int type as the identifier of the observer, mainly to use efficient SparseArray.
     * <p>
     * Each observer corresponds to a HashSet, in which all observers are saved.
     */
    private SparseArray<HashSet<EventListener>> observables = new SparseArray<>();


    /**
     * Registered Observer Method
     * <p>
     * Adding synchronous locks to prevent abnormalities caused by simultaneous registration, notification, removal and other operations
     */
    public synchronized void registerEvent(int eventCode, EventListener listener) {
        // First of all, find a set of pairs among all the observers.
        HashSet<EventListener> observers = observables.get(eventCode);
        // If there is no collection, create a new collection and put it in it.
        if (observers == null) {
            observers = new HashSet<>();
            observables.put(eventCode, observers);
        }
        // Adding observers
        observers.add(listener);
    }

    /**
     * Unbind the observer
     * <p>
     * Adding synchronous locks to prevent abnormalities caused by simultaneous registration, notification, removal and other operations
     */
    public synchronized void unregisterEvent(int eventCode, EventListener listener) {
        // First of all, find a set of pairs among all the observers.
        HashSet<EventListener> observers = observables.get(eventCode);
        // Remove the observer from the collection
        if (observers != null) {
            observers.remove(listener);
        }
    }

    /**
     * Notify the corresponding observer of the event in which the observee has changed
     * <p>
     * Here we imitate Observable's approach
     */
    public void sendEvent(int eventCode, Object object) {
        // Define a temporary Set set Set first
        EventListener[] arrLocal;
        // Synchronization locks are added here to avoid multithreading or problems caused by multiple operations at the same time.
        synchronized (this) {
            arrLocal = toArray(observables.get(eventCode));
        }
        // Development Distribution Events
        for (int i = arrLocal.length - 1; i >= 0; i--) {
            arrLocal[i].onEvent(eventCode, object);
        }
    }

    /**
     * HashSet Turn array
     * */
    private EventListener[] toArray(HashSet<EventListener> set){
        EventListener[] r = new EventListener[set.size()];
        Iterator<EventListener> it = set.iterator();
        for (int i = 0; i < r.length; i++) {
            r[i] = it.next();
        }
        return r;
    }

    /**
     * Clear up all observers
     * */
    public void clear(){
        observables.clear();
    }

}

We store all observers and their corresponding observers in Map as key pairs, so that they can be easily acquired and saved. Then we register and unbind to add or remove observers. Notification is actually an operation to traverse the corresponding observers.

It's not much different from before.

public class MainActivity extends AppCompatActivity implements EventListener{

    private TextView textView;

    private int count;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = (TextView) findViewById(R.id.textView);
    // Click Send an Event Notifying Change
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getInstance().sendEvent(1, "test" + count++);
            }
        });
         // register
        EventBus.getInstance().registerEvent(1, this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // Untying
        EventBus.getInstance().unregisterEvent(1, this);
    }

    // Implemented callback function
    @Override
    public void onEvent(int eventCode, Object object) {
        textView.setText((String) object);
    }
}

Optimization of EventBus

The central idea of implementation is not different, but in terms of performance, it must be very rough. For example, all operations are in the main thread, so concurrency and time-consuming have potential problems. So how can EventBus optimize these problems?

1. Increase queue management, increase asynchronous notification, reduce the pressure of the main thread.
2. On the basis of queue management, the mechanism of task cancellation is added to prevent the execution of duplicate tasks.
3. A cache mechanism is added to prevent the creation of meaningless objects at each notification and reduce memory overhead.
4. To increase the execution of the callback function, whether it is in the main thread or in the sub-thread, it can be used by annotations.

summary

EventBus also has some very good features, which I haven't found and mentioned yet, but from the popularity of its use by many developers, first of all, it shows that it is stable, reliable and efficient. I will study its source code carefully, and then introduce it carefully.

Topics: Java