九、HandlerThread解析

Android系统中,执行耗时操作都需要另外开启子线程来执行,执行完线程以后自动销毁。为了避免重复的创建和销毁线程,避免过多的消耗性能,可以采用:

  • 1.使用线程池
  • 2.使用HandlerThread

1.HandleThread 使用场景,以及如何使用

使用场景

HandlerThread是Google帮我们封装好的,可以用来执行多个耗时操作,而不需要多次创建销毁线程,里面是采用HandlerLooper实现的。

使用方式
  1. 创建HandlerThread的实例对象
      //构造方法的参数表示的是线程的名称
  HandlerThread  mHandlerThread = new HandlerThread("wyw");
  1. 启动创建的实例对象
  mHandlerThread.start()
  1. 将实例对象和handler绑定在一起。(必须按照这三步进行)
  mThreadHandler = new Handler(mHandlerThread.getLooper()) {
            @Override
            public void handleMessage(@NonNull Message msg) {
                checkForUpdate();
                if (isUpdate) {
                    mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
                }
            }
        };

完整使用实例代码:

public class MyActivity extends AppCompatActivity {
    private static final int MSG_UPDATE_INFO = 0x100;

    private HandlerThread mHandlerThread;
    private Handler mThreadHandler;
    Handler mMainHandler = new Handler();
    private TextView tv;
    private boolean isUpdate = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //创建handlerThread实例
        mHandlerThread = new HandlerThread("wyw");
        //启动handlerThread实例
        mHandlerThread.start();
        //handlerThread 绑定handler
        mThreadHandler = new Handler(mHandlerThread.getLooper()) {
            @Override
            public void handleMessage(@NonNull Message msg) {
                checkForUpdate();
                if (isUpdate) {
                    mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
                }
            }
        };
    }

    private void checkForUpdate() {
        try {
            //模拟耗时
            Thread.sleep(1200);
            mMainHandler.post(new Runnable() {
                @Override
                public void run() {
                    String result = "实时更新中, 当前股票行情: %d";
                    result = String.format(result, (int) Math.random() * 5000 + 1000);
                    tv.setText(result);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        isUpdate = true;
        mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
    }

    @Override
    protected void onPause() {
        super.onPause();
        isUpdate = false;
        mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandlerThread.quit();
        mMainHandler.removeCallbacksAndMessages(null);
    }
}

2.HandlerThread源码解析

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    private @Nullable Handler mHandler;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    
    protected void onLooperPrepared() {
    }

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
//持有锁机制来获得当前线程的Looper对象
        synchronized (this) {
            mLooper = Looper.myLooper();
//发出通知,当前线程已经创建mLooper对象成功,这里主要是通知getLooper方法中的waiter
            notifyAll();
        }
//线程的优先级设置
        Process.setThreadPriority(mPriority);
//方法空实现,可以重写这个方法,处理线程开启之前的准备工作
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
 
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
//直到线程创建完Looper之后才能获取Looper对象,Looper未创建成功阻塞
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }

    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

    public int getThreadId() {
        return mTid;
    }
}
  • HandlerThread构造方法,一个参数和两个参数的,name代表当前线程的名称,priority代表线程的优先级。
  • 前面强调在使用HandlerThread的时候必须先调用start(),接着才可以将HandlerThreadHandler绑定在一起。因为在run()方法中,我们才初始化looper,而我们调用HandlerThread的start()方法的时候,线程会交给虚拟机调度,由虚拟机自动调用run()方法。
  • run()方法中使用锁机制和notifyAll()的原因,可以在getLooper()方法中找到。
    在获取mLooper对象的时候存在一个同步的问题,只有当当线程成功创建并且Looper对象也创建成功之后才能获取mLooper的值。这里等待waite()和run()中的notifAll()共同实现同步。
  • quit()和quitSafe()的区别:
    通过源码追踪,可以发现,实际这个两个方法最终调用的是MessageQueue.quit(boolean safe)。MessageQueue.quit方法源码:
    void quit(boolean safe) {
         if (!mQuitAllowed) {
             throw new IllegalStateException("Main thread not allowed to quit.");
         }
         synchronized (this) {
             if (mQuitting) {
                 return;
             }
             mQuitting = true;
             if (safe) {
                 removeAllFutureMessagesLocked();
             } else {
                 removeAllMessagesLocked();
             }
             // We can assume mPtr != 0 because mQuitting was previously false.
             nativeWake(mPtr);
         }
     }
    
    可以看出,这个方法根据传入的参数safe来判断执行removeAllFutureMessagesLocked()或removeAllMessagesLocked()。
     private void removeAllMessagesLocked() {
         Message p = mMessages;
         while (p != null) {
             Message n = p.next;
             p.recycleUnchecked();
             p = n;
         }
         mMessages = null;
     }
    
    如果不是安全退出,执行removeAllMessagesLocked(),该方法就是遍历Message链表,移除所有信息的回调,并重置为null。
     private void removeAllFutureMessagesLocked() {
         final long now = SystemClock.uptimeMillis();
         Message p = mMessages;
         if (p != null) {
             if (p.when > now) {
                 removeAllMessagesLocked();
             } else {
                 Message n;
                 for (;;) {
                     n = p.next;
                     if (n == null) {
                         return;
                     }
                     if (n.when > now) {
                         break;
                     }
                     p = n;
                 }
                 p.next = null;
                 do {
                     p = n;
                     n = p.next;
                     p.recycleUnchecked();
                 } while (n != null);
             }
         }
     }
    
    如果是安全的退出,执行removeAllFutureMessagesLocked(),该方法,根据Message.when这个属性,判断我们当前消息队列是否正在处理消息,没有处理消息的话,直接移除所有的回调,正在处理的话,等待该消息处理完毕再退出该循环。因此说quiteSafe()是安全的,而quit()是不安全的,因为quit()不管是否正在处理,直接移除所有的回调。

你可能感兴趣的:(九、HandlerThread解析)