AsyncTask和Handler处理异步消息

Android系统中的视图组件并不是线程安全的,如果要更新视图,必须在主线程中更新,不可以在子线程中执行更新的操作。(子线程一般肩负起比较繁重的任务),所以引入了Handler和AsyncTask机制。

Handler机制

public class NewThread3 extends Activity {
    public static final int  UZI=0;
    private Button btn;
    private TextView text1;

    private Handler handler=new Handler(){
        public void handleMessage(Message msg) {
            if(msg.what==UZI){
                text1.setText("finally");

            }

        };

    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        text1 = (TextView) findViewById(R.id.text1);
        btn = (Button) findViewById(R.id.btn1);
        btn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub

                new MyThread().start();

            }
        });
    }

    private class MyThread extends Thread {
        @Override
        public void run() {
            // TODO Auto-generated method stub
            super.run();
            //处理比较耗时的操作
            Message msg=new Message();
            msg.what=UZI;
            handler.handleMessage(msg);

        }

    }

}

子线程处理繁重的任务,然后通过Handler传送Message通知主线程更新ui,主线程拿到message后再处理并更新ui。

Android的消息循环是针对线程的,每个线程都可以有自己的消息队列和消息循环。

Android系统中的Looper负责管理线程的消息队列和消息循环。通过Looper.myLooper()得到当前线程的Looper对象,通过Looper.getMainLooper()得到当前进程的主线程的Looper对象。
,一个线程可以存在一个消息队列和消息循环,特定线程的消息只能分发给本线程,不能跨线程和跨进程通讯。但是创建的工作线程默认是没有消息队列和消息循环的
所以需要用Looper.prepare()来创建消息队列,然后调用Looper.loop()进入消息循环
创建工作线程如下:

class MyThread extends Thread {  
      public Handler mHandler;  

      public void run() {  
          Looper.prepare();  

          mHandler = new Handler() {  
              public void handleMessage(Message msg) {  
                  // 处理收到的消息  
              }  
          };  

          Looper.loop();  
      }  
  }  

此时工作线程也有自己的消息处理机制了;
***Ui线程,也就是主线程,系统会默认分配消息队列和消息循环
了解了上面Handler和loop的关系后,再来看一个Ui线程和工作线程间进行消息传递的例子。

public class MainActivity extends ActionBarActivity {
    private int mCount = 0;
    private Handler mHandlerThr = null;
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Log.d(null, ">>>>>>>>>>>>>UI# mHandler--handleMessage--msg.what="+msg.what);
            //接收发送到UI线程的消息,然后向线程中的Handler发送msg 1。
            mHandlerThr.sendEmptyMessage(1);
            mCount++;
            if (mCount >= 3) {
                //由于mHandlerThr是在Child Thread创建,Looper手动死循环阻塞,所以需要quit。
                mHandlerThr.getLooper().quit();
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initData();
    }

    @Override
    protected void onStop() {
        super.onStop();
        //删除所有call与msg
        mHandler.removeCallbacksAndMessages(null);
    }

    private void initData() {
        Log.d(null, ">>>>>>>>>>>>>UI# begin start thread!!!");
        new Thread() {
            @Override
            public void run() {
                super.run();
                Looper.prepare();
                mHandlerThr = new Handler() {
                    @Override
                    public void handleMessage(Message msg) {
                        super.handleMessage(msg);
                        Log.d(null, ">>>>>>>>>>>>>Child# mHandlerThr--handleMessage--msg.what=" + msg.what);
                        //接收发送到子线程的消息,然后向UI线程中的Handler发送msg 0。
                        mHandler.sendEmptyMessage(0);
                    }
                };

                Log.d(null, ">>>>>>>>>>>>>Child# begin start send msg!!!");
                //Activity中启动Thread,在Thread结束前发送msg 0到UI Thread。
                mHandler.sendEmptyMessage(0);

                Looper.loop(); //不能在这个后面添加代码,程序是无法运行到这行之后的。
            }
        }.start();
    }
}

运行结果如下:

>>>>>>>>>>>>>UI# begin start thread!!!
>>>>>>>>>>>>>Child# begin start send msg!!!
>>>>>>>>>>>>>UI# mHandler--handleMessage--msg.what=0
>>>>>>>>>>>>>Child# mHandlerThr--handleMessage--msg.what=1
>>>>>>>>>>>>>UI# mHandler--handleMessage--msg.what=0
>>>>>>>>>>>>>Child# mHandlerThr--handleMessage--msg.what=1
>>>>>>>>>>>>>UI# mHandler--handleMessage--msg.what=0

Handler与Looper实例化总结

在主线程中可以直接创建Handler对象,而在子线程中需要先调用Looper.prepare()才能创建Handler对象,否则运行抛出”Can’t create handler inside thread that has not called Looper.prepare()”异常信息。

每个线程中最多只能有一个Looper对象,否则抛出异常。

可以通过Looper.myLooper()获取当前线程的Looper实例,通过Looper.getMainLooper()获取主(UI)线程的Looper实例。

一个Looper只能对应了一个MessageQueue。

一个线程中只有一个Looper实例,一个MessageQueue实例,可以有多个Handler实例。

继续看看Handler消息收发机制源码

通过Handler发消息到消息队列

比较sendMessageAtTime()和sendMessageAtFrontOfQueue()方法

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

再看看sendMessageAtFrontOfQueue()方法

    public final boolean sendMessageAtFrontOfQueue(Message msg) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, 0);
    }

Handler发送消息实质就是把消息Message添加到MessageQueue消息队列中的过程而已。

既然消息都存入到了MessageQueue消息队列,当然要取出来消息吧,不然存半天有啥意义呢?我们知道MessageQueue的对象在Looper构造函数中实例化的;一个Looper对应一个MessageQueue,所以说Handler发送消息是通过Handler构造函数里拿到的Looper对象的成员MessageQueue的enqueueMessage方法将消息插入队列,也就是说出队列一定也与Handler和Looper和MessageQueue有关系。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值