你的位置:首页 > 操作系统

[操作系统]Android多线程(三)


  上次讲了关于Android多线程中通信中Thread、Handler、Looper等的基础概念和基本用法,用现实世界两个人写信交流的过程来理解是再好不过了。但是不得不说这一套完整的细节的确很繁琐,好在Android中为我们提供了另一个简化的API——HandlerThread,通过使用HandlerThread,我们可以以一种简单的方式开启线程、进行线程通信。Let's do it!

三、HandlerThread

  1)参考文档:http://developer.android.com/reference/android/os/HandlerThread.html

  前面的连篇文章中我都贴出来相应内容的官方文档地址,也斗胆说了一下读文档的重要性。这次我们换一种方式——读源代码,好的代码本身就是一份文档,除了会写还得能读!如何找到Android的源码?不管你用的是不再更新的ADT+Eclipse还是AS(Android studio),你的电脑里一定得下载sdk,在sdk目录下有个叫sources的文件夹,里面放的就是Android的系统源码。(开源大法好!)如果你没有,那就“FQ”下一份,如何快速更新sdk我会在下一篇博客里写......

  2)HandlerThread源码:

  我在这把源码贴出来方便查看(我电脑上的源码是Android-22的)

package android.os;/** * 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;  //线程id  int mTid = -1;  //与线程绑定的Looper对象  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.   * 这里是你需要实现的部分,你的在这里实现对Handler的准备工作,定义你的Hadnler并实现   *handlerMessage(Message msg)方法。   */  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 >   * 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;  }}

  这里我们重点看两个方法:

   protected void onLooperPrepared() 这是一个在拓展类中需要重写的方法,它完成准备工作,一般是对Handelr进行定义。比如接受到主线程发来的消息时如何做出应对。在后面的示例中我就会对Handler进行定义,在handleMessage(Message msg)中定义行为。

  public void run() 再看这个方法里的内容是不是感到很熟悉,理解了Thread、Handler、Looper等概念后,是不是很容易就读懂了它的意思。对了,拓展HandlerThread时,如果要override run方法一定要记得调用父类的run() 。

  对于其他的方法,在这里就不赘述了,每个方法的前面的注释就详细说明了它们的作用。

  3)一个简单的示例:

  还是一样的,我用一个示例来说明HandlerThread的用法。还是一样的开启线程,等到接收到主线程发来的消息,然后打印打印日志。

布局:

 1 <TextView 2     android:layout_width="wrap_content" 3     android:layout_height="wrap_content" 4     android:layout_centerHorizontal="true" 5     android:text="HandlerThread"/> 6  7   <Button 8     android:id="@+id/button" 9     android:layout_width="match_parent"10     android:layout_height="wrap_content"11     android:layout_alignParentBottom="true"12     android:text="send message"/>

拓展的HandlerThread类:

 1 public class MyThread extends HandlerThread { 2  3   private static final String TAG = "MyThread"; 4   private Handler mHandler; 5  6   public MyThread() { 7     super(TAG); 8   } 9 10   @Override11   protected void onLooperPrepared() {12     super.onLooperPrepared();13     mHandler = new Handler(){14       @Override15       public void handleMessage(Message msg) {16         super.handleMessage(msg);17         if(msg.what == MainActivity.MSG_MAIN){18           handlerRequest(msg.obj);19         }20       }21     };22     return;23   }24 25   private void handlerRequest(Object obj){26     Log.d(TAG, "handlerRequest:" + obj + ",thread:" + Thread.currentThread().getName());27     Looper looper = Looper.getMainLooper();28     Handler handler = new Handler(looper);29     handler.post(new Runnable() {30       @Override31       public void run() {32         Log.d(TAG,"message is handled,thread:"+Thread.currentThread().getName());33         return;34       }35     });36     return;37   }38 39   public Handler getHandler() {40     return mHandler;41   }42 }

这次我使用了post方法很主线程进行通信。

Activity代码:

 1 public class MainActivity extends AppCompatActivity { 2  3   public static final int MSG_MAIN = 100; 4  5   @Override 6   protected void onCreate(Bundle savedInstanceState) { 7     super.onCreate(savedInstanceState); 8     setContentView(R.layout.activity_main); 9 10     final MyThread thread = new MyThread();11     thread.start();12     thread.getLooper();13 14     final Button sendButton = (Button) findViewById(R.id.button);15     sendButton.setOnClickListener(new View.OnClickListener() {16       @Override17       public void onClick(View view) {18         Handler handler = thread.getHandler();19         Message msg = handler.obtainMessage();20         msg.what = MainActivity.MSG_MAIN;21         msg.obj="testing HandlerThread";22         handler.sendMessage(msg);23         return;24       }25     });26   }27 }

  Logcat打印日志:

  10-08 11:45:47.152 13949-14004/comfallblank.github.handlerthread D/MyThread: handlerRequest:testing HandlerThread,thread:MyThread
  10-08 11:45:47.162 13949-13949/comfallblank.github.handlerthread D/MyThread: message is handled,thread:main

  这次我在日志中加入了线程名称,这样就可以看出任务执行的线程了。

  到这里,关于Android线程的内容算写完了,本来打算在国庆期间写完了,最后拖拖拉拉延迟了一天。还有国庆长假后第一天上课好累啊!就这样吧!下一篇关于如何快速更新sdk努力在这周写出来。

最后,欢迎大家交流,指正我不正确的地方。

邮箱:fallblank525@gmail.com  QQ:1054746297