Android中HandlerThread介绍与使用案列
2018-04-02 19:01
465 查看
HandlerThread 产生背景
1、开启Thread子线程进行耗时操作2、多次创建和销毁线程是很耗资源的
HandlerThread是什么
是handler+thread+looper结合,是一个thread内部有looper特点:
- 本质上是一个线程类,继承了thread,
- 其内部有自己的Looper对象,可以进行looper循环,
- 通过获取handlerthread的looper对象传递给handler对象,可以在handlermessage方法中执行异步任务
- 优点是不会堵塞,减少对性能的消耗。缺点是不能同时进行多任务的处理,需要等待进行处理。处理效率比较低。
- 与线程池注重并发不同的是,handlerthread是一个串行队列,handlerthread背后只有一个队列。
Handler使用场景
handlerthread源码:/** * Handy class for starting a new thread that has a looper. The looper can then be * used to create handler classes. Note that start() must still be called. */ public class HandlerThread extends Thread { int mPriority; int mTid = -1; Looper mLooper; public HandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAULT; } /** * Constructs a HandlerThread. * @param name * @param priority The priority to run the thread at. The value supplied must be from * {@link android.os.Process} and not from java.lang.Thread. */ public HandlerThread(String name, int priority) { super(name); mPriority = priority; } /** * Call back method that can be explicitly overridden if needed to execute some * setup before Looper loops. */ 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; } /** * This method returns the Looper associated with this thread. If this thread not been started * or for any reason is isAlive() returns false, this method will return null. If this thread * has been started, this method will block until the looper has been initialized. * @return The looper. */ public Looper getLooper() { if (!isAlive()) { return null; } // If the thread has been started, wait until the looper has been created. synchronized (this) { while (isAlive() && mLooper == null) { try { wait(); } catch (InterruptedException e) { } } } return mLooper; } /** * Quits the handler thread's looper. * <p> * Causes the handler thread's looper to terminate without processing any * more messages in the message queue. * </p><p> * Any attempt to post messages to the queue after the looper is asked to quit will fail. * For example, the {@link Handler#sendMessage(Message)} method will return false. * </p><p class="note"> * Using this method may be unsafe because some messages may not be delivered * before the looper terminates. Consider using {@link #quitSafely} instead to ensure * that all pending work is completed in an orderly manner. * </p> * * @return True if the looper looper has been asked to quit or false if the * thread had not yet started running. * * @see #quitSafely */ public boolean quit() { Looper looper = getLooper(); if (looper != null) { looper.quit(); return true; } return false; } /** * Quits the handler thread's looper safely. * <p> * Causes the handler thread's looper to terminate as soon as all remaining messages * in the message queue that are already due to be delivered have been handled. * Pending delayed messages with due times in the future will not be delivered. * </p><p> * Any attempt to post messages to the queue after the looper is asked to quit will fail. * For example, the {@link Handler#sendMessage(Message)} method will return false. * </p><p> * If the thread has not been started or has finished (that is if * {@link #getLooper} returns null), then false is returned. * Otherwise the looper is asked to quit and true is returned. * </p> * * @return True if the looper looper has been asked to quit or false if the * thread had not yet started running. */ public boolean quitSafely() { Looper looper = getLooper(); if (looper != null) { looper.quitSafely(); return true; } return false; } /** * Returns the identifier of this thread. See Process.myTid(). */ public int getThreadId() { return mTid; } }
首先我们可以看到HandlerThread继承自Thread,因此在run()中的逻辑都是在子线程中运行的。
接下来就是两个关键的方法,run()和getLooper():
run()中可以看到是很简单的创建Looper以及让Looper工作的逻辑。
run()里面当mLooper创建完成后有个notifyAll(),getLooper()中有个wait(),这有什么用呢?因为的mLooper在一个线程中执行创建,而我们的handler是在UI线程中调用getLooper()初始化的。
也就是说,我们必须等到mLooper创建完成,才能正确的返回。getLooper();wait(),notify()就是为了解决这两个线程的同步问题。
使用案例:
public class DownloadThread extends HandlerThread implements Handler.Callback{ private final String TAG = this.getClass().getSimpleName(); private final String KEY_URL = "url"; public static final int TYPE_START = 1; public static final int TYPE_FINISHED = 2; private Handler mWorkerHandler; private Handler mUIHandler; private List<String> mDownloadUrlList; public DownloadThread(final String name) { super(name); } @Override protected void onLooperPrepared() { //执行初始化任务 super.onLooperPrepared(); mWorkerHandler = new Handler(getLooper(), this); //使用子线程中的 Looper if (mUIHandler == null) { throw new IllegalArgumentException("Not set UIHandler!"); } //将接收到的任务消息挨个添加到消息队列中 for (String url : mDownloadUrlList) { Message message = mWorkerHandler.obtainMessage(); Bundle bundle = new Bundle(); bundle.putString(KEY_URL, url); message.setData(bundle); mWorkerHandler.sendMessage(message); } } public void setDownloadUrls(String... urls) { mDownloadUrlList = Arrays.asList(urls); } public Handler getUIHandler() { return mUIHandler; } //注入主线程 Handler public DownloadThread setUIHandler(final Handler UIHandler) { mUIHandler = UIHandler; return this; } /** * 子线程中执行任务,完成后发送消息到主线程 * * @param msg * @return */ @Override public boolean handleMessage(final Message msg) { if (msg == null || msg.getData() == null) { return false; } String url = (String) msg.getData().get(KEY_URL); //下载开始,通知主线程 Message startMsg = mUIHandler.obtainMessage(TYPE_START, "\n 开始下载 @" + DateUtils.getCurrentTime() + "\n" + url); mUIHandler.sendMessage(startMsg); SystemClock.sleep(2000); //模拟下载 //下载完成,通知主线程 Message finishMsg = mUIHandler.obtainMessage(TYPE_FINISHED, "\n 下载完成 @" + DateUtils.getCurrentTime() + "\n" + url); mUIHandler.sendMessage(finishMsg); return true; } @Override public boolean quitSafely() { mUIHandler = null; return super.quitSafely(); } }
MainActivity代码:
public class MainActivity extends AppCompatActivity implements Handler.Callback{ @BindView(R.id.tv_start_msg) TextView mTvStartMsg; @BindView(R.id.tv_finish_msg) TextView mTvFinishMsg; @BindView(R.id.btn_start_download) Button mBtnStartDownload; private Handler mUIHandler; private DownloadThread mDownloadThread; @Override protected void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); init(); } private void init() { mUIHandler = new Handler(this); mDownloadThread = new DownloadThread("下载线程"); mDownloadThread.setUIHandler(mUIHandler); mDownloadThread.setDownloadUrls("下载资源一", "下载资源二", "下载资源三"); } @OnClick(R.id.btn_start_download) public void startDownload() { mDownloadThread.start(); mBtnStartDownload.setText("正在下载"); mBtnStartDownload.setEnabled(false); } //主线程中的 Handler 处理消息的方法 @Override public boolean handleMessage(final Message msg) { switch (msg.what) { case DownloadThread.TYPE_FINISHED: mTvFinishMsg.setText(mTvFinishMsg.getText().toString() + "\n " + msg.obj); break; case DownloadThread.TYPE_START: mTvStartMsg.setText(mTvStartMsg.getText().toString() + "\n " + msg.obj); break; } return true; } }
布局文件:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:orientation="vertical" android:padding="8dp"> <TextView android:id="@+id/tv_start_msg" android:layout_width="match_parent" android:layout_height="200dp" android:text="下载开始信息"/> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="@color/colorAccent"/> <TextView android:id="@+id/tv_finish_msg" android:layout_width="match_parent" android:layout_height="200dp" android:layout_marginTop="8dp" android:text="下载完成信息"/> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="@color/colorAccent"/> <Button android:id="@+id/btn_start_download" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="开始下载"/> </LinearLayout>
相关文章推荐
- Android 开发中的 Handler ,Thread ,Message ,Runnable 的综合使用方法
- 在Android中使用Handler和Thread线程执行后台操作
- 在Android中使用Handler和Thread线程执行后台操作
- Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面
- Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面
- Android 开发中的 Handler ,Thread ,Message ,Runnable 的综合使用方法
- Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask
- Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask等
- Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面
- Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask等
- android之handler介绍和使用方法
- 在Android中使用Handler和Thread线程执行后台操作
- Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask等
- Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask等
- 在Android中使用Handler和Thread线程执行后台操作
- Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask等
- android handler和thread的使用
- Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask等
- Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask等
- Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask等