Handler消息机制 —— 基本使用及存在的性能问题

一 、Handler是什么?

       主要用于异步消息的处理:当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分在消息队列中逐一将消息取出,然后对消息进行处理,也就是发送消息和接收消息不是同步的处理。 这种机制通常用来处理相对耗时比较长的操作。

简单说Handler是Android SDK来处理异步消息的核心类。 子线程与主线程通过Handler来进行通信。子线程可以通过Handler来通知主线程进行UI更新。

二 、 为什么使用Handler?

       Android的UI更新只能在UI线程。如果任意线程都可以更新UI的话,线程安全问题处理起来会相当麻烦复杂,就会出现页面错乱。所以就规定了Android的是单线程模型,只允许在UI线程更新UI操作。也就是在Android中更新Ui必须在主线程,在子线程更新Ui会报子线程不能修改UI异常。因此子线程想要=更新UI就需要通过handler来发送消息给UI线程,然后UI线程再去更新UI。


三 、handler的简单使用

         倒计时的实现

         1. activity_main.xml中的代码如下

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tv_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

             2. MainActivity中的代码如下

package com.lx.handler;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private int totalTime = 120;
    private TextView textView;


    private Handler handler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            if (msg.what == 1) {
                textView.setText(String.valueOf(totalTime));
            }
        }
    };

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

        textView = findViewById(R.id.tv_time);
        textView.setText(String.valueOf(totalTime));

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (totalTime > 0) {
                    SystemClock.sleep(1000);
                    totalTime--;
                    Message message = handler.obtainMessage();
                    message.what = 1;
                    handler.sendMessage(message);
                }
            }
        }).start();
    }
}

这样就简单实现了一个倒计时的功能。在子线程中通过handler发送一个消息(message)给主线程。主线程收到消息之后去更新UI。

关于handler发送消息的用法还有:

handler.sendMessageDelayed(message, 1000); // 发送延时消息
handler.sendEmptyMessage(1); // 发送空消息,参数是message的what值
handler.sendEmptyMessageDelayed(1, 1000);// 发送空延时消息,参数是message的what值

在子线程中还可以通过handler的post(Runnable runnable)或者postDelayed(Runnable runnable,long delayMillis)方法切换到主线程.

    new Thread(new Runnable() {
        @Override
        public void run() {

            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    // 这里是主线程,可以直接更新UI
                }
            }, 1000);

            handler.post(new Runnable() {
                @Override
                public void run() {
                    // 这里是主线程,可以直接更新UI
                }
            });
        }
    }).start();

4、handler使用存在的性能问题

        当我们使用handler的时候很多都是直接new Handler()直接使用

  private Handler handler=new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
   };

这样new会报警告的,查看警告是:

 

中文意思大概是:

这个处理程序类应该是静态的,否则可能会发生泄漏(匿名的android.os.Handler)。
由于这个处理程序被声明为一个内部类,它可以防止外部类被垃圾收集。如果处理程序使用Looper或MessageQueue来处理主线程以外的线程,那么就没有问题了。如果处理程序使用主线程的Looper或MessageQueue,则需要修复处理程序声明,如下所示:将处理程序声明为 静态类;在外 部类中,实例化对外部类的WeakReference,并在实例化处理程序时将该对象传递给处理程序;使用WeakReference对象对外部类的 所有成员进行引用。

说的很明显了,使用静态内部类来解决。

对上面倒计时的代码优化如下

package com.lx.handler;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.widget.TextView;

import java.lang.ref.WeakReference;

public class MainActivity extends AppCompatActivity {
    private int totalTime = 120;
    private TextView textView;
    private MyHandler handler = new MyHandler(this);


    private static class MyHandler extends Handler {
        //对Activity的弱引用
        private final WeakReference<MainActivity> mActivity;

        public MyHandler(MainActivity activity) {
            mActivity = new WeakReference<MainActivity>(activity);
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            if (msg.what == 1) {
                MainActivity activity = mActivity.get();
                if (activity != null) {
                    activity.textView.setText(String.valueOf(activity.totalTime));
                }
            }
        }
    }


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

        textView = findViewById(R.id.tv_time);
        textView.setText(String.valueOf(totalTime));

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (totalTime > 0) {
                    SystemClock.sleep(1000);
                    totalTime--;
                    Message message = handler.obtainMessage();
                    message.what = 1;
                    handler.sendMessage(message);
                }
            }
        }).start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // activity 退出时移除handler的所有回调以及消息
        handler.removeCallbacksAndMessages(null);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值