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 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;
    }
}

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

   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     @Override
11     protected void onLooperPrepared() {
12         super.onLooperPrepared();
13         mHandler = new Handler(){
14             @Override
15             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             @Override
31             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             @Override
17             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

 

posted @ 2015-10-08 11:58  fallblank  阅读(3030)  评论(0编辑  收藏  举报