AsyncTask和Handler处理异步消息

来源:互联网 发布:不定长度数组实现 编辑:程序博客网 时间:2024/04/29 05:01

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有关系。

1 0