基本概念

Handler是Android提供的一套消息机制,可以在同一个或者不同线程之间传递消息。

在异步传递消息时,Handler像是两个线程之间通信的桥梁,桥的一端是Handler对象的setXxxMessage()方法(发送msg),另一端是同一个Handler对象的handleMessage(msg)方法(接收msg),两个线程共享一个Handler对象。

这个消息处理机制中,包含四个关键对象:Handler、Message、MessageQueue、Looper

rokcetTemplate 延时消息 handler延迟消息原理_rokcetTemplate 延时消息

Handler的作用

  • 线程间通信
  • 延时操作
  • 定时循环

Handler的常用方法

public final boolean sendEmptyMessageDelayed(int what, long delayMillis)
(立即)发送一个延时 msg 到 handler 的消息队列中,等delayMillis毫秒之后,这个 msg 会被从消息队列中
取出,然后做一些处理。不管是否重写了 handleMessage 方法,delayMillis毫秒之后,这个 msg 都会被从消
息队列中取出。

public final boolean hasMessages(int what)
判断消息队列中是否包含标志为 what 的 msg

public final void removeMessages(int what)
移除消息队列中标志为 what 的 msg

public final void removeCallbacksAndMessages(@Nullable Object token)
如果 token 为 null,则清除当前 handler 对象中所有的 callback 和 msg

public final boolean postDelayed(@NonNull Runnable r, long delayMillis)
延时异步执行,这个Runnable在那个线程执行取决于Looper在哪个线程

 

使用场景:子线程要更新UI

Android为了线程安全,并不允许我们在UI线程(主线程)外操作UI,即不允许在子线程中直接操作UI,这时候就需要在子线程中调用Handler对象的setXxxMessage()方法(发送msg),在主线程中调用同一个Handler对象的handleMessage(msg)方法(接收msg),根据msg处理相应的跟新UI逻辑

错误示范:直接在子线程中更新UI

报错信息:Only the original thread that created a view hierarchy can touch its views.

package com.clc.app14;

import android.os.Bundle;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {

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

        //执行Timer的schedule方法时,会新建一个线程
        new Timer().schedule(new TimerTask() {
            int i = 0;
            @Override
            public void run() {
                i ++;
                //在这个新的线程中操作UI
                TextView textView = findViewById(R.id.textview);
                textView.setText(""+i);
            }
        },0,1000);
    }
}

利用Handler使子线程间接操作UI(通知主线程跟新UI)

package com.clc.app14;

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

import androidx.appcompat.app.AppCompatActivity;

import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {

    //系统已经为主线程初始化了一个Looper对象,所以我们直接创建Handler对象
    Handler handler = new Handler(){
        int i = 0;

        //重写handleMessage(),接收本对象sendXxx()方法发来的msg对象,并做处理
        @Override
        public void handleMessage(Message msg) {

            if (msg.what == 1){
                i ++;
                TextView textView = findViewById(R.id.textview);
                textView.setText(""+i);
            }
        }
    };

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

        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                //在需要的地方,调用在主线程中实例化的handler对象的sendXxx()方法,向本对象的handleMessage()发送msg
                //每一次调用sendXxx(),执行一次handleMessage()
                handler.sendEmptyMessage(1);
            }
        },0,1000);
    }
}

另一个demo:自定义一个子线程

package com.clc.app14;

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

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {


    Handler handler = new Handler() {

        //重写handleMessage(),接收本对象sendXxx()方法发来的msg对象,并做处理
        //handleMessage()在主线程中执行
        //本对象sendXxx()方法的调用与执行,可以在其他线程中
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == 1){
                TextView textView = findViewById(R.id.textview);
                textView.setText(msg.getData().getString("key"));
            }
        }
    };

    //新建一个线程,在这个线程中通知更新UI
    class Thread1 extends Thread{
        @Override
        public void run() {
            //创建要发送的msg
            Message msg = new Message();
            msg.what = 1;
            Bundle bundle = new Bundle();
            bundle.putString("key","value");
            msg.setData(bundle);
            //在需要的地方,调用在子线程中实例化的handler对象的sendXxx()方法,向本对象的handleMessage()发送msg
            //每一次调用sendXxx(),执行一次handleMessage()
            handler.sendMessage(msg);
        }
    }

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

        //在主线程中启动子线程
        Thread1 thread1 = new Thread1();
        thread1.start();
    }
}

使用场景:定时循环

mHandler = new Handler();
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                //TODO
                mHandler.postDelayed(this, 1000);
            }
        });

使用场景:一定时间内多次回调,只执行第一次

package com.example.handler1;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private static final int DO_IT = 0;
    private static final long DELAY_MILLIS = 1000;
    private Handler mHandler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.tv).setOnClickListener(v -> {
            if (!mHandler.hasMessages(DO_IT)) {
                Log.d(TAG, "do it");
                mHandler.sendEmptyMessageDelayed(DO_IT, DELAY_MILLIS);
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacksAndMessages(null);
    }
}

使用场景:多次快速连续回调,只执行最后一次

package com.example.handler1;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private static final int DO_IT = 0;
    private static final long DELAY_MILLIS = 1000;
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            if (msg.what == DO_IT) {
                Log.d(TAG, "do it");
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.tv).setOnClickListener(v -> {
            if (mHandler.hasMessages(DO_IT)) {
                mHandler.removeMessages(DO_IT);
            }
            mHandler.sendEmptyMessageDelayed(DO_IT, DELAY_MILLIS);
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacksAndMessages(null);
    }
}