Threads use tutorial four for communication between main threads and sub-threads

Posted by nwoottonn on Mon, 15 Jul 2019 21:08:14 +0200

This time we will talk about the implementation of Handler, which has several knowledge points closely related to him.

I. Concept
MessageQueue: Message queue, which can only have one thread, is managed by Looper. MessageQueue will be created automatically when Looper is created, while only the main thread will create Looper automatically. Non-main threads need to create Looper using the prepare function.
Message: The message unit in the message queue, which is obtained by the obtain function.
Looper: Each Looper is associated with a thread and gets the current Looper through Looper.myLooper().
Handler: Handler handles messages. Handler encapsulates information as Message through obtainMessage and sends it to Looper through sendMessage to put it into MessageQueue. Looper then broadcasts the message when it sees the message Queue, so that handler receives the message and handleMessage processes it.

2. Passing messages between threads
1. The main thread sends information to the main thread

public class MainActivity extends Activity {

    private Button btnTest;
    private TextView textView;

    private Handler handler;

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

        btnTest = (Button)this.findViewById(R.id.btn_01);
        textView = (TextView)this.findViewById(R.id.view_01);

        btnTest.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {

                Looper looper = Looper.getMainLooper(); //Looper objects for main threads
                //Here handler is created with the Loper object of the main thread.
                //So, the Message sent by this handler is passed to the Message Queue of the main thread.
                handler = new MyHandler(looper);
                handler.removeMessages(0);//Clear the message queue

                Message msg = handler.obtainMessage(1, 1, 1, "The main thread sent a message");
                //Building Message Objects
                //First parameter: what parameter
                //The second and third parameters are meaningless.
                //The fourth parameter is the object that needs to be encapsulated
                handler.sendMessage(msg); //send message

            }
        });
    }

    class MyHandler extends Handler{
        public MyHandler(Looper looper){
            super(looper);
        }
        public void handleMessage(Message msg){
            super.handleMessage(msg);
            if(msg.what==1)
                textView.setText("I'm the main thread. Handler,Received the message:"+(String)msg.obj);
        }
    }
}

Although Handler can update the UI, it does not mean that it has been created in the main thread, because it automatically uses the current thread when it is created. It is created in the main thread, and it works in the main thread. Similarly, in the sub-thread, it also works in the sub-thread and cannot update the UI. So the above code Looper looper = Looper.getMainLooper() can be dispensed with.
new MyHandler(looper), where looper is the main thread, so its handleMessage function is in the main thread, but its sendMessage function is also in the main thread, so this is the main thread to send the main thread information.

2. Subthreads pass information to the main thread

public class MainActivity extends Activity {

    private Button btnTest;
    private TextView textView;

    private Handler handler;

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

        btnTest = (Button)this.findViewById(R.id.btn_01);
        textView = (TextView)this.findViewById(R.id.view_01);

        btnTest.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {

                //You can see here that a thread is started to manipulate the encapsulation and sending of messages.
                //So the sending of the original main thread becomes the sending of other threads, is it simple? Ha-ha
                new MyThread().start();
            }
        });
    }

    class MyHandler extends Handler{

        public MyHandler(Looper looper){
            super(looper);
        }

        public void handleMessage(Message msg){
            super.handleMessage(msg);
            textView.setText("I'm the main thread. Handler,Received the message:"+(String)msg.obj);
        }
    }

    //Add a thread class
    class MyThread extends Thread{

        public void run(){
            Looper looper = Looper.getMainLooper(); //Looper objects for main threads
            //Here handler is created with the Loper object of the main thread.
            //So, the Message sent by this handler is passed to the Message Queue of the main thread.
            handler = new MyHandler(looper);

            //Building Message Objects
            //The first parameter is the message code you specify to facilitate selective reception in handler
            //The second and third parameters are meaningless.
            //The fourth parameter is the object that needs to be encapsulated
            Message msg = handler.obtainMessage(1,1,1,"Other threads send messages");

            handler.sendMessage(msg); //send message
        }
    }
}

Here is the command to send messages running inside Thread, even though the Looper is the Looper of the main thread, it has no effect on who the current thread is. So where is the thread that sends the information, the thread is the starting point, and the Handler or Thread that sends the information calculates the destination, which is determined by the looper in the creation function new MyHandler(looper). The looper is the main thread, and the looper is created by itself and is in the sub-thread.

3. Information from the main thread to the sub-thread

public class MainActivity extends Activity {

    private Button btnTest;
    private TextView textView;

    private Handler handler;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        btnTest = (Button)this.findViewById(R.id.btn_01);
        textView = (TextView)this.findViewById(R.id.view_01);


        //Start threads
        new MyThread().start();    

        btnTest.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                //Here handler is instantiated in the thread
                //Threads are instantiated at startup
                Message msg = handler.obtainMessage(1,1,1,"Messages sent by the main thread");
                handler.sendMessage(msg);
            }
        });
    }

    class MyHandler extends Handler{

        public MyHandler(Looper looper){
            super(looper);
        }

        public void handleMessage(Message msg){
            super.handleMessage(msg);
            textView.setText("I'm the main thread. Handler,Received the message:"+(String)msg.obj);
        }
    }

    class MyThread extends Thread{

        public void run(){
            Looper.prepare(); //Create a Loper object for this thread to receive messages

            //Note: handler here is defined in the main thread oh, ha, ha.
            //The handler object is used directly. Are you looking for it? Where is it instantiated?
            //See now??? Ha-ha, you can't instantiate it at the beginning, because the thread's Looper object
            //Not yet. Now you can instantiate
            //Here Looper.myLooper() gets the Looper object for the thread.
            handler = new ThreadHandler(Looper.myLooper());
            //It's actually a loop that cancels messages from MessageQueue.
            Looper.loop(); 

        }

        //Define message processing classes in thread classes
        class ThreadHandler extends Handler{

            public ThreadHandler(Looper looper){
                super(looper);
            }

            public void handleMessage(Message msg){
                //Here, the Message in the MessageQueue in this thread is processed
                //Here we return a message to the main thread
                handler = new MyHandler(Looper.getMainLooper());

                Message msg2 = handler.obtainMessage(1,1,1,"Subthreads receive:"+(String)msg.obj);

                handler.sendMessage(msg2);
            }
        }
    }
}

Note here that the Looper here does not use the main thread, but is created by itself, so the acceptance function is in the sub-thread. Then it sends information to the main thread, accepts information, assigns value to handler, and then sends information to the sub-thread.

4. Send messages to yourself

public class MainActivity extends Activity {

    private Button btnTest;
    private TextView textView;

    private Handler handler;

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

        btnTest = (Button)this.findViewById(R.id.btn_01);
        textView = (TextView)this.findViewById(R.id.view_01);


        btnTest.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                //Start threads
                new MyThread().start();
            }
        });
    }

    class MyHandler extends Handler{

        public MyHandler(Looper looper){
            super(looper);
        }

        public void handleMessage(Message msg){
            super.handleMessage(msg);
            textView.setText((String)msg.obj);
        }
    }

    class MyThread extends Thread{

        public void run(){
            Looper.prepare(); //Create the Loper object for this thread
            //Here Looper.myLooper() gets the Looper object for the thread.
            handler = new ThreadHandler(Looper.myLooper());
            Message msg = handler.obtainMessage(1,1,1,"Myself");
            handler.sendMessage(msg);

            Looper.loop();

        }

        //Define message processing classes in thread classes
        class ThreadHandler extends Handler{

            public ThreadHandler(Looper looper){
                super(looper);
            }

            public void handleMessage(Message msg){
                //Here, the Message in the MessageQueue in this thread is processed
                //Here we return a message to the main thread
                //Add a judgment to see if the thread sends its own message
                if(msg.what == 1 && msg.obj.equals("Myself")){

                    handler = new MyHandler(Looper.getMainLooper());

                    Message msg2 = handler.obtainMessage(1,1,1,"Informer thread:I received what I sent to myself. Message");

                    handler.sendMessage(msg2);
                }

            }
        }
    }
}

Here in the sub-thread to send information, and then because this acceptance function in the sub-thread, so we can say that they send information to themselves, and then they assign the handler to the main thread Looper and send information, so the position of receiving information in the main thread, which is the sub-thread to send information to the main thread.
So far, let's talk about thread pools next time.