Android中handler的使用及原理---学习笔记

一、Handler类的基本介绍以及使用:

Android中UI操作是线程不安全的操作,如果有多个线程并发操作UI组件,就会出现线程安全问题,所以Android中制定了一个规则:在Android中只允许主线程(UI线程)修改Activity中的UI组件,但是现在问题又来了,在开发中我们会需要在子线程中更新UI组件的情况,那怎么进行处理呢?其实Handler就是为了解决这种问题而生的。

Handler类的主要作用有两个:

1.在新启动的线程中发送消息

2.在主线程中获取,处理消息

Handler类中用于发送、处理消息的方法:

1. void handleMessage(Message msg):处理消息的方法。该方法通常用于被重写

2. boolean hasMessages(int what):检查消息队列中是否包含what属性为指定值得消息

3. boolean hasMeesages(int what,Object obj):检查消息队列中时候包含what属性为指定值且object属性为指定对象的消息

4. 多个重载的Message obtainMessage():获取消息

5. sendEmptyMessage(int what):发送空消息

6. boolean sendEmptyMessageDelayed(int what,long delayMillis):指定多少毫秒之后发送空消息

7. boolean sendMessage(Message msg):立即发送消息

8. boolean sendMessageDelayed(Message msg,long delayMillis):指定多少毫秒之后发送消息

下面是一个使用Handler类更新UI组件的一个使用小例子:


  
  
  1. package com.my.Mytimetest;  
  2.   
  3. import java.util.Timer;  
  4. import java.util.TimerTask;  
  5.   
  6. import android.app.Activity;  
  7. import android.os.Bundle;  
  8. import android.os.Handler;  
  9. import android.os.Message;  
  10. import android.widget.ImageView;  
  11.   
  12. public class MainActivity extends Activity {  
  13.     private ImageView imageview;  
  14.       
  15.     private int[] images = {R.drawable.image1,R.drawable.image2,R.drawable.image3,R.drawable.image4};  
  16.       
  17.     private int index;  
  18.   
  19.     @Override  
  20.     protected void onCreate(Bundle savedInstanceState) {  
  21.         super.onCreate(savedInstanceState);  
  22.         setContentView(R.layout.activity_main);  
  23.         imageview = (ImageView) findViewById(R.id.id_images);  
  24.           
  25.         final Handler mHandler = new Handler(){  
  26.             @Override  
  27.             public void handleMessage(Message msg) {  
  28.                 if(msg.arg1==123){  
  29.                     index++;  
  30.                     imageview.setImageResource(images[index%4]);  
  31.                 }  
  32.             }  
  33.         };  
  34.           
  35.         //定义一个计时器,设置为延迟0ms后执行,每隔1s执行一次(这里如果设置为 timer.schedule(task,1000)表示执行一次)  
  36.         new Timer().schedule(new TimerTask(){  
  37.             @Override  
  38.             public void run() {  
  39.                 Message message = new Message();  
  40.                 message.arg1 = 123;  
  41.                 mHandler.sendMessage(message);  
  42.             }  
  43.         }, 0, 1000);  
  44.           
  45.           
  46.     }  
  47. }  

效果如图: 

上边的案例,就是简单的用到了Handler类来实现一个图片轮播的效果。

二、Handler的实现原理:

与Handler一起工作的几个组件:

1.Message:Handler接收和处理的消息对象

2.Looper:每个线程只能拥有一个Looper.它的loop方法负责读取MessageQueue中的消息,

读到信息之后就把消息交给发送该消息的Handler进行处理。

3.MessageQueue:消息队列,它采用先进先出的方式来管理Message.

程序创建Looper对象时会在他的构造器中创建Looper对象。

Looper提供的构造器源代码如下:


  
  
  1. private Looper() {  
  2.         mQueue = new MessageQueue();  
  3.         mRun = true;  
  4.         mThread = Thread.currentThread();  
  5.     }  

从源代码中可以看出:

(1).  构造方法是私有的,所以不允许我们自己创建Looper对象

(2). 程序在初始化Looper时会创建一个与之关联的MessageQueue,这个MessageQueue就负责管理消息。

4.Handler:

简而言之,Handler的作用:Handler的构造方法,其实就是在Handler中持有一个指向该Looper.mQueue对象,

当handler调用sendMessage方法时,其实就是往该mQueue中去插入一个message,然后Looper.loop()就会取出执行。

作用有两个-----发送消息和处理消息,程序中使用Handler发送消息,

被Handler发送的消息必须被送到指定的MessageQueue。

也就是说,如果希望Handler正常工作,必须在当前的线程中有一个MessageQueue,

否则消息就没有MessageQueue进行保存了。不过MessageQueue是由Looper负责管理的,

也就是说,如果希望Handler正常工作,必须在当前的线程中有一个Looper对象,

为了当前线程中有Looper对象,可以分为两种情况处理:

(1).主UI线程中,系统已经初始化了一个Looper对象,因此程序直接创建Handler即可,

然后就可以通过Handler来发送消息,处理消息了。

(2).在自己启动的子线程中,必须自己创建一个Looper对象,并启动它。

------创建Looper对象调用它的prepare()方法即可。

Looper类中prepare()方法的源码: 


  
  
  1. public static final void prepare() {  
  2.         if (sThreadLocal.get() != null) {  
  3.             throw new RuntimeException("Only one Looper may be created per thread");  
  4.         }  
  5.         sThreadLocal.set(new Looper());  
  6.     }  

 prepare()方法保证每个线程最多只有一个Looper对象。

然后调用Looper的静态loop()方法来启动它。loop()方法使用一个死循环不断的取出MessageQueue中的消息,

并将取出的消息分给该消息对应的Handler进行处理。

Looper类中loop()方法的源码:


  
  
  1. public static final void loop() {  
  2.        Looper me = myLooper();  
  3.        MessageQueue queue = me.mQueue;  
  4.        while (true) {  
  5.            Message msg = queue.next(); // might block  
  6.            //if (!me.mRun) {  
  7.            //    break;  
  8.            //}  
  9.            if (msg != null) {  
  10.                if (msg.target == null) {  
  11.                    // No target is a magic identifier for the quit message.  
  12.                    return;  
  13.                }  
  14.                if (me.mLogging!= null) me.mLogging.println(  
  15.                        ">>>>> Dispatching to " + msg.target + " "  
  16.                        + msg.callback + ": " + msg.what  
  17.                        );  
  18.                msg.target.dispatchMessage(msg);  
  19.                if (me.mLogging!= null) me.mLogging.println(  
  20.                        "<<<<< Finished to    " + msg.target + " "  
  21.                        + msg.callback);  
  22.                msg.recycle();  
  23.            }  
  24.        }  
  25.    }  
 

Looper,MessageQueue,Handler各自的作用如下:

Looper:每个线程只用一个Looper,负责管理MessageQueue,会不断的从MessageQueue中取出消息,

并将消息分给对应的Handler处理。

MessageQueue:由Looper负责管理,它采用先进先出的方式管理Message。

Handler: 它能把消息发送给Looper管理的MessageQueue,并负责处理Looper分给它的消息。

简而言之:

Handler负责发送消息,

Looper负责接收Handler发送的消息并直接把消息回传给Handler自己,

MessageQueue就是一个存储消息的容器。

三、在线程中使用Handler的步骤如下:

1. 调用Looper的prepare()方法为当前的线程创建Looper对象,

创建Looper对象时,Looper的构造方法中会创建与之配套的MessageQueue.

2. 有了Looper对象之后,创建Handler子类的实例,重写handleMessage()方法,

该方法负责处理来自于其他线程的消息。

3. 调用Looper的loop()方法启动Looper。

下面对比一下在主线程中和在子线程中使用Handler的区别:

主线程中使用Handler计算一定范围之内的质数的例子:


    
    
  1. package com.my.Mytimetest;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import android.app.Activity;  
  7. import android.os.Bundle;  
  8. import android.os.Handler;  
  9. import android.os.Message;  
  10. import android.view.View;  
  11. import android.view.View.OnClickListener;  
  12. import android.widget.Button;  
  13. import android.widget.EditText;  
  14. import android.widget.TextView;  
  15. import android.widget.Toast;  
  16.   
  17. public class SecondActivity extends Activity implements OnClickListener {  
  18.     private EditText edt;  
  19.     private TextView textview;  
  20.     private Button stop_btn;  
  21.     private Handler mHandler;  
  22.     private List<Integer> nums = new ArrayList<Integer>();  
  23.   
  24.     @Override  
  25.     protected void onCreate(Bundle savedInstanceState) {  
  26.         super.onCreate(savedInstanceState);  
  27.         setContentView(R.layout.activity_main);  
  28.   
  29.         initView();  
  30.         setListener();  
  31.   
  32.         mHandler = new Handler() {  
  33.             @Override  
  34.             public void handleMessage(Message msg) {  
  35.                 if (msg.what == 123) {  
  36.                     int num = msg.getData().getInt("num");  
  37.                     //计算从2开始,到num的所有质数  
  38.                     outer: for (int i = 2; i < num; i++) {  
  39.                         //从i除以2开始,到i的平方根的所有数  
  40.                         for (int j = 2; j < Math.sqrt(i); j++) {  
  41.                             //如果可以整除,则表明这个数不是质数  
  42.                             if (!= 2 && i % j == 0) {  
  43.                                 continue outer;  
  44.                             }  
  45.                         }  
  46.                         nums.add(i);  
  47.   
  48.                     }  
  49.                       
  50.                     textview.setText(nums.toString());  
  51.                       
  52.                     nums.removeAll(nums);  
  53.                 }  
  54.             }  
  55.         };  
  56.   
  57.     }  
  58.   
  59.     private void setListener() {  
  60.         stop_btn.setOnClickListener(this);  
  61.   
  62.     }  
  63.   
  64.     private void initView() {  
  65.         edt = (EditText) findViewById(R.id.id_edt);  
  66.         textview = (TextView) findViewById(R.id.id_textview);  
  67.         stop_btn = (Button) findViewById(R.id.id_start);  
  68.     }  
  69.   
  70.     @Override  
  71.     public void onClick(View v) {  
  72.         int num = Integer.parseInt(edt.getText().toString());  
  73.         Message message = new Message();  
  74.         message.what = 123;  
  75.         Bundle bundle = new Bundle();  
  76.         bundle.putInt("num", num);  
  77.         message.setData(bundle);  
  78.         // 将消息发送给子线程中的Handler来处理  
  79.         mHandler.sendMessage(message);  
  80.   
  81.     }  
  82.   
  83. }  

子线程中使用Handler计算一定范围之内的质数的例子:

 

  
  
  1. package com.my.Mytimetest;  
  2.   
  3.   
  4. import java.util.ArrayList;  
  5. import java.util.List;  
  6.   
  7. import android.app.Activity;  
  8. import android.os.Bundle;  
  9. import android.os.Handler;  
  10. import android.os.Looper;  
  11. import android.os.Message;  
  12. import android.view.View;  
  13. import android.view.View.OnClickListener;  
  14. import android.widget.Button;  
  15. import android.widget.EditText;  
  16. import android.widget.TextView;  
  17. import android.widget.Toast;  
  18.   
  19. public class MainActivity extends Activity implements OnClickListener {  
  20.     private EditText edt;  
  21.     private Button stop_btn;  
  22.     private MyThread myThread;  
  23.       
  24.     @Override  
  25.     protected void onCreate(Bundle savedInstanceState) {  
  26.         super.onCreate(savedInstanceState);  
  27.         setContentView(R.layout.activity_main);  
  28.           
  29.         initView();  
  30.         setListener();  
  31.         myThread = new MyThread();  
  32.         //开启子线程  
  33.         myThread.start();  
  34.           
  35.           
  36.           
  37.     }  
  38.     private void setListener() {  
  39.         stop_btn.setOnClickListener(this);  
  40.           
  41.     }  
  42.     private void initView() {  
  43.         edt = (EditText) findViewById(R.id.id_edt);  
  44.         stop_btn = (Button) findViewById(R.id.id_start);  
  45.     }  
  46.     @Override  
  47.     public void onClick(View v) {  
  48.         int num = Integer.parseInt(edt.getText().toString());  
  49.         Message message = new Message();  
  50.         message.what = 123;  
  51.         Bundle bundle = new Bundle();  
  52.         bundle.putInt("num", num);  
  53.         message.setData(bundle);  
  54.         //将消息发送给子线程中的Handler来处理  
  55.         myThread.mHandler.sendMessage(message);  
  56.           
  57.     }  
  58.       
  59.     class MyThread extends Thread{  
  60.           
  61.         public Handler mHandler;  
  62.         private List<Integer> nums = new ArrayList<Integer>();  
  63.         @Override  
  64.         public void run() {  
  65.             Looper.prepare();  
  66.             mHandler = new Handler(){  
  67.                 @Override  
  68.                 public void handleMessage(Message msg) {  
  69.                     if(msg.what==123){  
  70.                         int num = msg.getData().getInt("num");  
  71.                         outer:  
  72.                             for (int i = 2; i < num; i++) {  
  73.                                 for (int j = 2; j < Math.sqrt(i); j++) {  
  74.                                     if(i!=2&&i%j==0){  
  75.                                         continue outer;  
  76.                                     }  
  77.                                 }  
  78.                                 nums.add(i);  
  79.                                   
  80.                             }  
  81.                         Toast.makeText(MainActivity.this, nums.toString(), Toast.LENGTH_LONG).show();  
  82.                         nums.removeAll(nums);  
  83.                     }  
  84.                 }  
  85.   
  86.                   
  87.             };  
  88.             Looper.loop();  
  89.         }  
  90.           
  91.               
  92.         }  
  93.           
  94.     }  

效果图:


四、HandlerThread类的使用:

介绍:

HandlerThread继承自Thread,当线程开启时,也就是它run方法运行起来后,

线程同时创建了一个含有消息队列的Looper,并对外提供自己这个Looper对象的get方法,这就是它和普通Thread唯一不同的地方。 

好处:

为什么要使用HandlerThread。

1.开发中如果多次使用类似new Thread(){...}.start()

这种方式开启一个子线程,会创建多个匿名线程,使得程序运行起来越来越慢,

而HandlerThread自带Looper使他可以通过消息来多次重复使用当前线程,节省开支;

2.android系统提供的Handler类内部的Looper默认绑定的是UI线程的消息队列,

对于非UI线程又想使用消息机制,那么HandlerThread内部的Looper是最合适的,它不会干扰或阻塞UI线程。

 

用法:

HandlerThread既然本质是Thread,为何前面加了一个Handler?

android中Handler类本质上就是从它内部的Looper中不断取消息,

然后触发它内部的Callback接口的handleMessage方法,让用户去实现对消息的具体处理。

而HandlerThread本身自带Looper,只要它实现了Callback接口,

那么HandlerThread也可以在自己线程内处理自己线程发出的消息,

充分实现非UI线程中较低开支下的消息处理。

HandlerThread类的使用:


    
    
  1. package com.my.Mytimetest;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.os.Handler;  
  6. import android.os.HandlerThread;  
  7. import android.os.Message;  
  8. import android.util.Log;  
  9.   
  10. public class FourActivity extends Activity{  
  11.       
  12.       
  13.       
  14.     @Override  
  15.     protected void onCreate(Bundle savedInstanceState) {  
  16.         super.onCreate(savedInstanceState);  
  17.         setContentView(R.layout.activity_main);  
  18.           
  19.         HandlerThread handlerThread = new HandlerThread("handler thread");  
  20.         handlerThread.start();  
  21.           
  22.         Handler mHandler = new Handler(handlerThread.getLooper()){  
  23.             @Override  
  24.             public void handleMessage(Message msg) {  
  25.                 Log.i("tag", "当前的线程:"+Thread.currentThread());  
  26.             }  
  27.         };  
  28.         mHandler.sendEmptyMessage(1);  
  29.           
  30.     }  
  31.   
  32. }  

效果图:


可以看出,打印的是子线程的信息。HandlerThread中加了同步锁,保证了线程的安全。

HandlerThread类的run()方法的源码:

 

  
  
  1. public void run() {  
  2.     mTid = Process.myTid();  
  3.     Looper.prepare();  
  4.     synchronized (this) {  
  5.         mLooper = Looper.myLooper();  
  6.         notifyAll();  
  7.     }  
  8.     Process.setThreadPriority(mPriority);  
  9.     onLooperPrepared();  
  10.     Looper.loop();  
  11.     mTid = -1;  
  12. }   

HandlerThread类中的getLooper()方法的源码:


  
  
  1. public Looper getLooper() {  
  2.         if (!isAlive()) {  
  3.             return null;  
  4.         }  
  5.           
  6.         // If the thread has been started, wait until the looper has been created.  
  7.         synchronized (this) {  
  8.             while (isAlive() && mLooper == null) {  
  9.                 try {  
  10.                     wait();  
  11.                 } catch (InterruptedException e) {  
  12.                 }  
  13.             }  
  14.         }  
  15.         return mLooper;  
  16.     } 
 
 

五、下面介绍一下主线程与子线程之间通过Handler传递消息的方法

主线程给子线程发送、子线程给主线程发送消息的代码: 

    
    
  1. package com.my.Mytimetest;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.os.Handler;  
  6. import android.os.HandlerThread;  
  7. import android.os.Message;  
  8. import android.util.Log;  
  9. import android.view.View;  
  10. import android.view.View.OnClickListener;  
  11. import android.widget.Button;  
  12.   
  13. public class ThreedActivity extends Activity implements OnClickListener {  
  14.   
  15.     private Button button1;  
  16.     private Button button2;  
  17.     private Handler threadHandler;  
  18.     private Message messageMain;  
  19.     private Message messageThread;  
  20.   
  21.     //创建主线程的handler  
  22.     private Handler mHandler = new Handler() {  
  23.         public void handleMessage(android.os.Message msg) {  
  24.             messageMain = new Message();  
  25.             Log.i("tag", "主线程中的Handler");  
  26.             //向子线程发送消息  
  27.             threadHandler.sendMessageDelayed(messageMain, 1000);  
  28.         };  
  29.   
  30.     };  
  31.       
  32.   
  33.     @Override  
  34.     protected void onCreate(Bundle savedInstanceState) {  
  35.         super.onCreate(savedInstanceState);  
  36.         setContentView(R.layout.three);  
  37.           
  38.         button1 = (Button) findViewById(R.id.id_btn1);  
  39.         button2 = (Button) findViewById(R.id.id_btn2);  
  40.         button1.setOnClickListener(ThreedActivity.this);  
  41.         button2.setOnClickListener(ThreedActivity.this);  
  42.   
  43.           
  44.         HandlerThread handlerThread = new HandlerThread("handler thread");  
  45.         handlerThread.start();  
  46.         //创建子线程的handler  
  47.         threadHandler = new Handler(handlerThread.getLooper()){  
  48.             @Override  
  49.             public void handleMessage(Message msg) {  
  50.                 messageThread = new Message();  
  51.                 Log.i("tag", "子线程中的Handler");  
  52.                 //向主线程发送消息  
  53.                 mHandler.sendMessageDelayed(messageThread, 1000);  
  54.             }  
  55.         };  
  56.   
  57.     }  
  58.   
  59.       
  60.     @Override  
  61.     public void onClick(View v) {  
  62.         switch (v.getId()) {  
  63.         case R.id.id_btn1:  
  64.             //主线程给子线程发送一个消息  
  65.             mHandler.sendEmptyMessage(1);  
  66.             break;  
  67.   
  68.         case R.id.id_btn2:  
  69.             break;  
  70.   
  71.         default:  
  72.             break;  
  73.         }  
  74.   
  75.     }  
  76.   
  77. }  

六、Android中更新UI的几种方式

1.runOnUiThread

2.handler post

3.handler sendMessage

4.view post

代码:


    
    
  1. package com.my.Mytimetest;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.os.Handler;  
  6. import android.util.Log;  
  7. import android.view.View;  
  8. import android.view.View.OnClickListener;  
  9. import android.widget.Button;  
  10. import android.widget.TextView;  
  11.   
  12. public class FiveActivity extends Activity implements OnClickListener {  
  13.   
  14.     private TextView textview;  
  15.     private Button changeBtn1;  
  16.     private Button changeBtn2;  
  17.     private Button changeBtn3;  
  18.     private Button changeBtn4;  
  19.     private int index;  
  20.   
  21.     private Handler handler = new Handler() {  
  22.         public void handleMessage(android.os.Message msg) {  
  23.             textview.setText("handler sendMessage方式更新UI");  
  24.             Log.i("tag", "handler sendMessage方式更新UI");  
  25.         };  
  26.     };  
  27.   
  28.     @Override  
  29.     protected void onCreate(Bundle savedInstanceState) {  
  30.         super.onCreate(savedInstanceState);  
  31.         setContentView(R.layout.five);  
  32.   
  33.         textview = (TextView) findViewById(R.id.id_textview);  
  34.         changeBtn1 = (Button) findViewById(R.id.id_change1);  
  35.         changeBtn1.setOnClickListener(this);  
  36.         changeBtn2 = (Button) findViewById(R.id.id_change2);  
  37.         changeBtn2.setOnClickListener(this);  
  38.         changeBtn3 = (Button) findViewById(R.id.id_change3);  
  39.         changeBtn3.setOnClickListener(this);  
  40.         changeBtn4 = (Button) findViewById(R.id.id_change4);  
  41.         changeBtn4.setOnClickListener(this);  
  42.   
  43.         dealUI();  
  44.           
  45.           
  46.     }  
  47.       
  48.     private void dealUI(){  
  49.         // 在子线程中更新UI  
  50.                 new Thread() {  
  51.                     @Override  
  52.                     public void run() {  
  53.                         try {  
  54.                             Thread.sleep(2000);  
  55.                             switch (index) {  
  56.                             case 1:  
  57.                                 // 方式1  
  58.                                  handler1();  
  59.                                 break;  
  60.                             case 2:  
  61.                                  //方式2:  
  62.                                  handler2();  
  63.                                 break;  
  64.                             case 3:  
  65.                                  //方式3:  
  66.                                 updateUI();  
  67.                                 break;  
  68.                             case 4:  
  69.                                  //方式4:  
  70.                                  viewUI();  
  71.                                 break;  
  72.   
  73.                             default:  
  74.                                 System.out.println("不会吧");  
  75.                                 break;  
  76.                             }  
  77.                               
  78.                               
  79.                               
  80.                         } catch (InterruptedException e) {  
  81.                             e.printStackTrace();  
  82.                         }  
  83.                     }  
  84.                 }.start();  
  85.     }  
  86.   
  87.     /** 
  88.      * 方式1:handler post方式 
  89.      */  
  90.     private void handler1() {  
  91.         handler.post(new Runnable() {  
  92.   
  93.             @Override  
  94.             public void run() {  
  95.                 textview.setText("handler post方式更新UI");  
  96.                 Log.i("tag", "handler post方式更新UI");  
  97.             }  
  98.         });  
  99.     }  
  100.   
  101.     /** 
  102.      * 方式2:handler sendMessage方式 
  103.      */  
  104.     private void handler2() {  
  105.         handler.sendEmptyMessage(1);  
  106.           
  107.     }  
  108.   
  109.     /** 
  110.      * 方式三:runOnUiThread方式 
  111.      */  
  112.     private void updateUI() {  
  113.         runOnUiThread(new Runnable() {  
  114.   
  115.             @Override  
  116.             public void run() {  
  117.                 textview.setText("runOnUiThread方式更新UI");  
  118.                 Log.i("tag", "runOnUiThread方式更新UI");  
  119.             }  
  120.         });  
  121.     }  
  122.   
  123.     /** 
  124.      * 方式四:view post方式 
  125.      */  
  126.     private void viewUI() {  
  127.         textview.post(new Runnable() {  
  128.   
  129.             @Override  
  130.             public void run() {  
  131.                 textview.setText("view post方式更新UI");  
  132.                 Log.i("tag", "view post方式更新UI");  
  133.             }  
  134.         });  
  135.     }  
  136.   
  137.     @Override  
  138.     public void onClick(View v) {  
  139.         switch (v.getId()) {  
  140.         case R.id.id_change1:  
  141.             index=1;  
  142.             dealUI();  
  143.             break;  
  144.         case R.id.id_change2:  
  145.             index=2;  
  146.             dealUI();  
  147.             break;  
  148.         case R.id.id_change3:  
  149.             index=3;  
  150.             dealUI();  
  151.             break;  
  152.         case R.id.id_change4:  
  153.             index=4;  
  154.             dealUI();  
  155.             break;  
  156.   
  157.         default:  
  158.             break;  
  159.         }  
  160.           
  161.           
  162.     }  
  163.   
  164. }   

效果图:

实际上,上边的这四种更新UI的方式都是使用到了handler机制来更新UI的,只是内部一些代码的处理不一样,看一下这四种方式的源码,我们就知道了。

源码对比:

handler post方式:


    
    
  1. public final boolean post(Runnable r)  
  2.    {  
  3.       return  sendMessageDelayed(getPostMessage(r), 0);  
  4.    }   

runOnUiThread方式:

 


    
    
  1. public final void runOnUiThread(Runnable action) {  
  2.       if (Thread.currentThread() != mUiThread) {  
  3.           mHandler.post(action);  
  4.       } else {  
  5.           action.run();  
  6.       }  
  7.   }   

view post方式: 


    
    
  1. public boolean post(Runnable action) {  
  2.        Handler handler;  
  3.        if (mAttachInfo != null) {  
  4.            handler = mAttachInfo.mHandler;  
  5.        } else {  
  6.            // Assume that post will succeed later  
  7.            ViewRoot.getRunQueue().post(action);  
  8.            return true;  
  9.        }  
  10.   
  11.        return handler.post(action);  
  12.    }   

其实都是通过handler机制来实现的。

七、最后,一些常见的异常的产生原因

1.Can't create handler inside thread that has not called Looper.prepare();

产生的原因:

是因为在子线程中创建Handler对象的时候没为创建的Handler指定Looper,

源码解析: 


    
    
  1.  public Handler() {  
  2.         if (FIND_POTENTIAL_LEAKS) {  
  3.             final Class klass = getClass();  
  4.             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&  
  5.                     (klass.getModifiers() & Modifier.STATIC) == 0) {  
  6.                 Log.w(TAG, "The following Handler class should be static or leaks might occur: " +  
  7.                     klass.getCanonicalName());  
  8.             }  
  9.         }  
  10.   
  11.         mLooper = Looper.myLooper();  
  12.         if (mLooper == null) {  
  13.             throw new RuntimeException(  
  14.                 "Can't create handler inside thread that has not called Looper.prepare()");  
  15.         }  
  16.         mQueue = mLooper.mQueue;  
  17.         mCallback = null;  
  18.     }  
  19.    

2.android.view.ViewRootImpl$CalledFromWrongThreadException: 

Only the original thread that created a view hierarchy can touch its views.

产生的原因:是因为在非UI线程中更新UI

 

由于本人初写博客,写的不好的地方还请大家能批评指正,希望能和大家相互学习、相互交流、共同成长。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GraysonWP

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值