I finally understand Handler (2)

Continued I finally understand Handler (1)
After reading the previous article, I believe you have a certain understanding of handler. This chapter begins to practice

1. Application of multiple handler s in multithreading

public class HandlerTestActivity extends AppCompatActivity {
    private static final String TAG = "HandlerTestActivity";
    private Handler mHandler;
    private Handler mHandler1;
    private MyThread mThread1;
    private Handler mHandler2;
    private MyThread mThread2;

    class MyThread extends Thread {
        private Looper mLooper;

        @Override
        public void run() {
            super.run();
            Looper.prepare();
            synchronized (this) {
                mLooper = Looper.myLooper();
                notifyAll();
            }
            Looper.loop();
        }

        public Looper getLooper() {
            if (!isAlive()) {
                return null;
            }

            synchronized (this) {
                while (isAlive() && mLooper == null) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                    }
                }
            }
            return mLooper;
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       mThread1 = new MyThread();
       mThread1.start();

       mThread2 = new MyThread();
       mThread2.start();

       mHandler = new Handler() {
           @Override
           public void handleMessage(Message msg) {
               super.handleMessage(msg);
               Log.d(TAG,"get Message =="+msg.what);
           }
       };
       new Thread(() -> mHandler.sendEmptyMessage(10)).start();
       mHandler.sendEmptyMessage(0);


        mHandler1 = new Handler(mThread1.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                Log.d(TAG,"get Message =="+msg.what);
            }
        };
        mHandler1.sendEmptyMessage(1);

        mHandler2 = new Handler(mThread2.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                Log.d(TAG,"get Message =="+msg.what);
            }
        };
        mHandler2.sendEmptyMessage(2);

    }

}

Output results:

Here we experiment with sending messages between multiple threads.

  • Comparison between Handler default instantiation and Handler specified Looper object instantiation
  • Comparison between handler sending messages in the main thread and in the child thread
  • In the previous article, we also gave an example of instantiating a Handler object in a child thread.

In this way, our understanding of Handler should be clearer! Here we explore why multithreading should be implemented like the above example.

1.1 specifying the Looper object

First of all, we need to understand whether the Looper object can not be specified in the above example (that is, whether the 61 line mThread1.getLooper() can not be specified). The answer is: Yes. Even if we add a line of code new thread (() - > mhandler1 sendEmptyMessage(12)). start(); Handler1 sends messages in the child thread, and it can still receive them. In this case, do we not need to specify the Looper object?

  if we do not specify the Looper object, we use the Looper of the main thread; Now we specify mthread1 Getlooper(), the Looper object in Thread1 is used in mHandler1. Of course, there is no problem here, but if our Handler1 is instantiated in a child thread, we must specify the Looper object. Otherwise, when sending a message, how does the program know which thread you want to save to the message queue.

1.2 getLooper()

mThread1. The run method of MyThread is executed when getLooper(), looper Prepare may not be executed yet, so wait in the getLooper method when looper Prepare () executes notifyAll. A lock is added here to ensure thread safety.

Generally, we use the default handler instantiation, which can fully meet our daily development needs. The above MyThread class is created to allow us to instantiate handler in the sub thread for encapsulation, and it is a relatively simple encapsulation. Android system provides us with a better handler thread.

2. Introduction of handlerthread

HandlerThread is more comprehensive than MyThread above, and it comes with the core class library. We can use it directly.

public class HandlerThreadActivity extends AppCompatActivity {
    private static final String TAG = "HandlerThreadActivity";
    private HandlerThread mHandlerThread;
    private HandlerThread mHandlerThread1;
    private HandlerThread mHandlerThread2;
    private Handler mHandler;
    private Handler mHandler1;
    private Handler mHandler2;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mHandlerThread = new HandlerThread("handler-thread");
        mHandlerThread.start();

        mHandlerThread1 = new HandlerThread("handler-thread1");
        mHandlerThread1.start();

        mHandlerThread2 = new HandlerThread("handler-thread2");
        mHandlerThread2.start();

        mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                Log.d(TAG,"get Message ==="+msg.what);
            }
        };

        new Thread(()-> {
            mHandler1 = new Handler(mHandlerThread1.getLooper()) {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    Log.d(TAG,"get Message ==="+msg.what);
                }
            };
            mHandler.sendEmptyMessage(0);
            mHandler1.sendEmptyMessage(1);
        }).start();


        new Thread(()-> {
            mHandler2 = new Handler(mHandlerThread2.getLooper()) {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    Log.d(TAG,"get Message ==="+msg.what);
                }
            };
            mHandler2.sendEmptyMessage(10);
        }).start();

    }

    @Override
    protected void onResume() {
        super.onResume();
        mHandler2.sendEmptyMessage(2);
    }
}

Output results:

Here is a simple use, focusing on the instantiation of Handler in multithreading. I hope you will be more comfortable in practical use.

Keywords: Android

Added by kamsmartx on Sun, 16 Jan 2022 13:58:51 +0200