HandlerThread 소개

소개

HandlerThread는 Thread를  상속 하고 Looper를 내부적으로 캡슐화합니다 . handlerThread.start() 메서드를 호출한 후 Looper MessageQueue가 내부적으로 생성되며 Looper 객체를 통해 Handler를 인스턴스화 한 다음 이 Handler를 다른 스레드에서  사용할 수 있습니다 .
1. 기존의 Thread + Handler 방식을 사용하여 스레드 간 통신 실현
Looper 객체를 직접 구현한 다음 Looper 루프에 Handler 객체를 생성하여 Handler 메시지를 수신하고 해당 작업을 수행해야 합니다.
public Handler threadHandler;
new Thread(new Runnable() {
    @Override
    public void run() {
        Looper.prepare();
        threadHandler = new Handler(Looper.myLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                // 处理消息,因为这个方法是在子线程调用,所以要在这执行耗时任务
            }
        };
        Looper.loop();
    }
}).start();

2. HandlerThread를 사용하여 스레드 간 통신 실현

먼저 HandlerThread 인스턴스를 생성한 다음 handlerThread.start()를 호출하여 Looper  객체를 생성한  다음 handlerThread.getLooper() 를 통해 HandlerThread  에서 Looper 객체를 가져오고 이 Looper 객체 를 기반으로 핸들러를 생성하여  하위 스레드를 처리합니다. 논리.
HandlerThread handlerThread = new HandlerThread("handler-thread");
handlerThread.start(); // 必须在Handler创建前调用,因为线程start后才会创建Looper
Handler threadHandler = new Handler(handlerThread.getLooper()) {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        // 处理消息,在子线程调用,所以要在这执行耗时任务

    }
};

실현원리

public class HandlerThread extends Thread {
    int mPriority;  // 线程优先级
    int mTid = -1;  // 线程Id
    Looper mLooper; // Looper循环器对象
    private @Nullable Handler mHandler;  // Handler 对象

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    
    /**
     * 开启Looper循环之前的准备工作
     * 复写之后,添加自己的逻辑
     */
    protected void onLooperPrepared() {  }

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
    
    /**
     * 此方法返回与此线程关联的循环器。如果这个线程没有启动或者
     * 因为任何原因isAlive()返回false,这个方法将返回null。
     * 如果这个线程已经启动,这个方法将阻塞,直到循环器初始化为止。
     */
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        // 如果线程已经启动,则会等待,直到创建了循环器。
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

    /**
     * 返回一个已经与此线程进行关联的 Handler对象。
     */
    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }

    /**
     * 这是退出循环器Looper的方法,一旦调用了quit()方法,消息队列中的消息将会立即停止处理,
     * 并且之后发来的所有消息都会失败。比如sendMessage()方法会返回false。
     * 这是不安全的一种退出方式。即不管是否正在处理消息,直接移除所有回调。
     */
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

    /**
     * 安全的退出Looper循环,
     * 会等待正在处理的消息处理完后再退出。
     */
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

    /**
     * 获取线程Id
     */
    public int getThreadId() {
        return mTid;
    }
}

HandlerThread의 우선 순위 우선 순위

HandlerThread 스레드 의 우선 순위를 합리적으로 할당 하고 스레드를 어느 정도 최적화하십시오.
기본 우선순위는 process.THREAD_PRIORITY_DEFAULT 이며 값은 "0" 입니다 .
우선 순위의 값 범위는 "-20 ~ 19"이며 값이 작을수록 우선 순위가 높습니다. 우선 순위가 높은 스레드는 더 많은 CPU 리소스를 얻게 되며 그 반대의 경우도 마찬가지입니다. 그러나 HandlerThread 는 작업자 스레드와 같이 높은 우선 순위를 설정할 필요가 없으므로 필요에 따라 합리적인 우선 순위 수준을 설정해야 합니다.

HandlerThread 사용 시나리오

Looper 를 캡슐화하기 때문에 Thread + Looper 장면  에 속합니다 . 하위 스레드에서 시간이 많이 걸리는 작업 및 다중 작업 작업을 실행합니다.
로컬 IO 작업의 경우 :
HandlerThread는 로컬 IO 읽기 및 쓰기 작업을 처리하는 데 사용할 수 있습니다. 대부분의 로컬 IO 작업은 밀리초가 걸리므로 단일 스레드 + 대기열의 형태인 HandlerThread의 경우 차단이 발생하지 않습니다. 또한 postAtFrontQueue() 메서드를 사용하여 로컬 IO를 읽을 수 있습니다. 그러면 실행을 위해 읽기 작업을 큐 앞에 빠르게 추가할 수 있습니다. 예: 데이터베이스에서 데이터를 읽고 ListView 목록에 표시합니다.
네트워크 IO 작업이 아닌 경우:
HandlerThread는 단일 스레드 동기 대기열이므로 네트워크 IO 작업 처리에 적합하지 않습니다.  
HandlerThread의 장단점
장점 : 여러 작업을 수행하기 위해 하나의 스레드만 시작할 수 있습니다.
단점 : 멀티태스킹이 지원되지만 HandlerThread는 동기식이며 동시성을 달성할 수 없습니다.
           따라서 스레드 작업 중 하나를 실행하는 데 너무 오래 걸리면 후속 작업이 지연됩니다.
지침
HandlerThread 사용이 끝나면 quitSafe() 또는 quit() 메서드를 호출하여 스레드를 종료 해야 합니다 .
quitSafe()는 종료하기 전에 처리 중인 메시지가 처리될 때까지 기다립니다.
quit() 메시지 처리 여부에 관계없이 모든 콜백을 직접 제거합니다.

おすすめ

転載: blog.csdn.net/m0_49508485/article/details/127255505