Android Event Processing Mechanism

Android Event Processing Mechanism

If you want to process messages in Android, such as a classic application scenario: Update the UI after receiving a network response, just add a Handler member to the thread that responds to the event, as follows

public class MainActivity extends Activity {
    Handler messageHandler = new MyMessageHandler();
}

Superficially, Handler is not associated with the current thread, so other threads send messages through handler.sendMessage(msg); how does the main thread receive and process messages? Go in and see the code.

public Handler(Callback callback, boolean async) {
    ...
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}
public final class Looper {
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
}

public class ThreadLocal<T> {
    ...
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }
    ...
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
    ...
}
class Thread{
    ...
    ThreadLocal.ThreadLocalMap threadLocals = null;
    ...
}

The above code clearly describes how to get the Looper of the current thread. The Looper for setting up threads is done at the start-up stage of threads, as follows:

In the ActivityThread class

public final class ActivityThread {
    public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        ...
        Looper.loop();
        ...
    }
}

public final class Looper {
    public static void prepareMainLooper() {
        prepare(false);
        ...
        }
    }
}

In the HandlerThread class, which also has event handling capabilities

public class HandlerThread extends Thread {
    ...
    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
    ...
}

Thus, if you want a thread to be called an event processing thread, you must first Looper.prepare(); then Looper. loop (); loop () to make the current thread enter the message processing cycle, as follows:

public final class Looper {
    public static void loop() {
        final Looper me = myLooper();
        ...
        for (;;) {
            Message msg = queue.next(); // might block
            ...
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            ...
        }
    }
}
public final class Message implements Parcelable {
    ...
    Handler target;
    ...
}
public class Handler {
    ...
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
    ...
}

Whether you call any form of Handler.sendXXXMessage(Message), you go to enqueueMessage() and record the current Handler in Message. Event loop threads are distributed to this handler through msg.target.dispatchMessage(msg). That is, which handler sends messages and which handler processes them.

prepare() constructs a Looper to be saved to ThreadLocalMap members of the thread. As follows:

public final class Looper {
    public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
}
public class ThreadLocal<T> {
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    ...
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
    ...
}
class Thread{
    ...
    ThreadLocal.ThreadLocalMap threadLocals = null;
    ...
}

That is to say, when running on a thread with event processing (UI thread with Android or a Handler Thread), a Looper is constructed internally and the event loop is processed. When a handler is constructed by the thread, the constructor records the looper of the thread and its queue, which is sent to the queue when the message is sent by the handler. The thread where the message is located calls the handler to handle the event.

So far, Android's event handling mechanism is clear.

Why do I read Android code? From Java to C++?

I'm a C++ programmer. Most of my work is in C++, but why do I read Android's code? I don't want to change careers, but I want to learn how to implement it. I need to know that C++ programmers often need to implement some basic functions by themselves.

A Java programmer, especially in the current domestic Java industry environment, almost few people write a basic library to provide functions for others to use, such as message mechanism. Most Java programmers in China can be said to be worthy of "moving bricks". There is no derogation here, but a kind of praise: Java programmers have many excellent libraries and frameworks ready-made and built on rich standard libraries. Java programmers only need to choose an excellent library to build functions together according to their own needs, and pay more attention to business logic- That's the essence of Enterprise. Business is number one.

And a C++ programmer wants to realize a function. Yes, there are many ready-made libraries that can be used ideologically. However, due to the lack of C++ standard libraries, there is no unified solution for many functions. So the libraries themselves realize the functions that should be provided by the standard libraries. The algorithms of these functions are different and the interfaces are different. When programmers combine them together, they cause the complexity of learning and using. This complexity makes many C++ programmers give another choice - to build a wheel that meets their own functions - which could have been avoided. As long as the C++ standard library provides the basic functions needed by C++ programmers in time, the C++ Standards Committee screwed up the matter. If one day you want to implement a C++ library similar to Apache Java HttpClient's function, how do you choose network modules to achieve cross-platform perfectly? Until C++17, network functions were not added to the C++ standard library, so Apache chose asio (hypothesis); later you used Redis, you added hiredis(libuv as network library) to your code, asio and libuv smiled at each other. With helplessness. —— You can imagine how much the C++ Standards Committee has delayed.

Of course, I look at it from the perspective of a C++ developer. The C++ Standards Committee has always been cautious in reviewing C++ proposals, but this can not be a stumbling block to the development of C++. C++ with such a lack of standard library is not suitable for enterprise application development, you'd better choose Java or C#, or other more suitable language.

Keywords: Java Android network Apache

Added by jonnypixel on Mon, 01 Jul 2019 04:37:42 +0300