zoukankan      html  css  js  c++  java
  • 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的系统源码。(开源大法好!)如果你没有,那就“翻墙”下一份,如何快速更新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

  • 相关阅读:
    EF框架 处理decimal字段 Sum() 遇到NULL时的特殊处理
    RSA加密解密及RSA签名和验证
    SQL 类似switch的东东用法
    js抛物线动画
    MyBatis的结果映射(resultMap)
    mybatis中#和$符号的区别
    MyBatis 中Mapper.xml中注意事项
    MyBatis sql映射器 Mapper
    MyBatis的自定义别名和内置别名
    MyBatis简单认识(入门)
  • 原文地址:https://www.cnblogs.com/fallblank/p/4860575.html
Copyright © 2011-2022 走看看