Handler跨线程通信的工作原理和使用

回顾一下Handler跨线程通信:

Handler的使用
  1. 在接收线程中创建Looper对象。主线程中的Looper对象已经由系统创建。
  2. 在接收线程中创建Handler对象,复写handleMessage方法处理消息。
  3. 开启Looper的消息循环,主线程中已由系统开启。
  4. 在发送线程创建Message,并使用接收线程中的Handler引用发送消息。
    测试HandlerActivity代码:

    public class MainActivity extends AppCompatActivity {
    
        public static final String TAG = "MainActivity";
        private Handler mThreadHandler;
        private Handler mMainHandler = new Handler(new Handler.Callback() {
            // 主线程接收到子线程发送的消息
            @Override
            public boolean handleMessage(Message msg) {
                if (msg.obj != null) {
                    Log.e(TAG, msg.obj.toString());
                    mThreadReplyText.setText("收到子线程回复:" + msg.obj.toString());
                }
                return true;
            }
        });
        private EditText mMainEditText;
        private TextView mThreadReplyText;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mMainEditText = findViewById(R.id.main_edit_text);
            mThreadReplyText = findViewById(R.id.thread_reply_text);
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Looper.prepare();
                    mThreadHandler = new Handler(new Handler.Callback() {
                        // 子线程接收到主线程发送的消息并回复
                        @Override
                        public boolean handleMessage(Message msg) {
                            if (msg.obj != null) {
                                Message reply = Message.obtain();
                                reply.obj = "主线程说\"" + msg.obj.toString()+"\"";
                                // 在子线程中使用主线程中的Handler对象的引用向主线程发送消息
                                mMainHandler.sendMessage(reply);
                            }
    
                            return true;
                        }
                    });
                    Looper.loop();
                }
            }).start();
        }
    
    
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.main_send_button:
                    Message message = Message.obtain();
                    message.obj = mMainEditText.getText();
                    // 主线程向子线程发送消息:在主线程中使用子线程中的Handler对象的引用向子线程发送消息
                    if (mThreadHandler != null) {
                        mThreadHandler.sendMessage(message);
                    } else {
                        while (mThreadHandler == null) {
                            Log.e(TAG, "子线程还没有完成ThreadHandler的创建");
                            if (mThreadHandler != null) {
                                Log.e(TAG, "ThreadHandler创建完成!");
                                mThreadHandler.sendMessage(message);
                            }
                        }
                    }
                    break;
            }
        }
    }

    XML文件:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity"
        android:padding="20dp">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
    
            <EditText
                android:id="@+id/main_edit_text"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="wrap_content"
                android:hint="主线程对子线程说:"/>
    
            <Button
                android:id="@+id/main_send_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="发送"
                android:onClick="onClick"/>
    
        </LinearLayout>
    
        <TextView
            android:id="@+id/thread_reply_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="16sp"
            android:paddingTop="20dp"
            android:paddingBottom="20dp"/>
    
    </LinearLayout>
Handler的工作原理

Handler的消息传递机制涉及到四个部分:
1. Message:线程间传递的对象。
2. MessageQueue: 消息队列,用来存放Handler发布的Message.
3. Handler:负责将Message插入到MessageQueue中以及对MessageQueue中的Message进行处理。
4. Looper:负责从MessageQueue中取出Message,并交给Handler.

其中:
+ Looper存储在ThreadLocal中,Looper在创建时会同时创建MessageQueue,作为其成员对象.因此LooperMessageQueue是属于创建者线程的,各线程之间的LooperMessageQueue相互独立。
+ Handler在创建时会从当前线程的ThreadLocal中取得Looper.
+ 发送消息时,在发送线程中调用接收线程中的HandlersendMessage方法,过程中,Handler会将自身赋予到Messagetarget中,并将Message插入到Handler对应的MessageQueue中。
+ 而接收线程中的Looper在循环过程中会取出这个Message,通过Message.target取出接收线程中的Handler,并将消息交Handler对象处理。由此实现了跨线程通信。
+ 要注意的是:线程与LooperMessageQueue是一对一的关系,即一个线程只维护一个Looper和一个MessageQueue;而线程与Handler的关系是一对多,即一个线程可以有很多Handler,一个Handler只对应一个线程,这也是为什么Handler在发送消息时,为什么要将自身赋给Message.target的原因。

Handler内存泄露的解决方法

方法1:通过程序逻辑进行保护。
+ 关闭Activity的时候停掉后台线程,这样就相当于切断了Handler和外部连接的线,Activity自然会在合适的时候被回收。
+ 如果你的Handler是被delay的Message持有了引用,那么在Activity销毁前使用相应的HandlerremoveCallbacksAndMessages()方法,把消息对象从消息队列移除就行了。

方法2:将Handler声明为静态类
+ 静态类不持有外部类的对象,这样即使Handler在运行,Activity也可以被回收。
+ 由于静态类的Handler不再持有外部类对象,如果要操作Activity需要增加一个Activity的弱引用。

参考链接:
面试:Handler 的工作原理是怎样的?
Handler解析(一):是如何实现线程之间的切换

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值