总结线程交互
说到线程,大家都知道,可以当作android进程的一个轻量级的表现,只是不占有空间和资源。在android中,有一个线程是我们最常接触到的,当我们做的一个应用,在第一次进入的时候,进入第一个Activity的时候,android自身就会自动创建一个用于控制一些控件以及绘图的MainUI线程,也就是我们说的activity主线程。
说到这里,就不得不提到一个概念,它就是消息队列,由于activity 的主线程里面已经给我们准备好了消息队列,所以我们只需要在用的时候直接用就可以了,但在自己创建的子线程里面却不行,因为子线程本身并没有消息队列这个东西,在我们做线程交互的时候,刷新主界面的时候,往往是通过Handle来完成的,这里不得不提到另一个东东,它叫LOOP,当我们从子线程里面,通过handle来发送一个消息出来之后,LOOP会把这个消息发送回到主线程里面,然后通过消息队列的方法,来处理这些消息,最终达成我们刷新主界面的效果。
那如何在我们自己创建的子线程里面实现消息队列,很简单,调用Looper.prepare(),那么系统就会自动的为该线程建立一个消息队列,然后调用 Looper.loop();之后就进入了消息循环,这个之后就可以发消息、取消息、和处理消息。这个方法对于平常,我们自己一些用来控制线程交互的实现,非常有用,所以分享一下。
说到这里,可能大家时常会遇到一些handle之后,好像没用的现象,这是因为,handle之后,LOOP把消息传到了消息队列的尾部,这是没有问题的,但是在处理端的时候,就有可能会出现阻塞的现象,所以,用handle来处理一些复杂的图象更新的时候,有时候有出现一些不可靠的现象。但Handle本身有自己的优势,就是使用简单,易懂,而且对于一般应用来说,出错的情况并不是很频繁,所以使用也就特别多。
有可能大家会问,什么是可靠的呢,这里就不得不提到另一个东西,叫AsyncTask,简单来说,就是异步任务。
实现:
1) 子类化AsyncTask
2) 实现AsyncTask中定义的下面一个或几个方法
onPreExecute() 开始执行前的准备工作;
doInBackground(Params...) 开始执行后台处理,可以调用publishProgress方法来更新实时的任务进度;
onProgressUpdate(Progress...) 在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。
onPostExecute(Result) 执行完成后的操作,传送结果给UI 线程。
注意: 1) AsyncTask的实例必须在UI thread中创建;
2) AsyncTask.execute方法必须在UI thread中调用;
3)该task只能被执行一次,否则多次调用时将会出现异常。而且是不能手动停止
下面是一个例子,AsyncTask_eoe
- packagexiaohang.zhimeng;
- importandroid.app.Activity;
- importandroid.os.AsyncTask;
- importandroid.os.Bundle;
- importandroid.os.Handler;
- importandroid.os.Message;
- importandroid.os.SystemClock;
- importandroid.widget.TextView;
- importandroid.widget.Toast;
- /**
- *一个使用异步任务的例子。一般来说一个异步任务只执行一次,这个例子有点非主流,任务结束后会触发下一次任务执行。
- *由任务task在屏幕上打印数字,第一次任务执行由主Activity的onCreate触发,每次任务结束后
- *设定下一次触发的时间,共执行5次。对于任务来说doInBackground()接收任务的参数params,并执行产生数字的动作,每一个数字
- *产生后调用一次publishProgress()来更新UI,这个函数本身也是异步的只是用来发个消息调用完成后立即返回,
- *而产生数字的动作在继续进行。更新界面的操作在onProgressUpdate()中设定。所有的on函数都由系统调用,不能用户调用。
- *代码中使用Handler是为了能触发任务执行,android规定这种异步任务每次执行完就结束,若要重新执行需要new一个新的。
- *异步任务只能在UI线程里面创建和执行
- */
- publicclasstestAsyncextendsActivity{
- privatefinalintMSG_TIMER=10000;
- privateTextViewvText=null;
- @Override
- protectedvoidonCreate(BundlesavedInstanceState){
- //TODOAuto-generatedmethodstub
- super.onCreate(savedInstanceState);
- setContentView(R.layout.test);
- vText=(TextView)findViewById(R.id.TextView01);
- vText.setText("Num...");
- newtask().execute("->");
- }
- //接收任务task发来的消息,触发一个新的任务
- privatefinalHandlerhandler=newHandler(){
- @Override
- publicvoidhandleMessage(Messagemsg){
- //TODOAuto-generatedmethodstub
- super.handleMessage(msg);
- System.out.println("Handlername----------->"+Thread.currentThread().getName());
- System.out.println("Handlerid------------>"+Thread.currentThread().getId());
- switch(msg.what){
- caseMSG_TIMER:
- newtask().execute("->");
- break;
- }
- }
- };
- //任务执行次数
- privatestaticinttimes=1;
- //AsyncTask<>的参数类型由用户设定,这里设为三个String
- //第一个String代表输入到任务的参数类型,也即是doInBackground()的参数类型
- //第二个String代表处理过程中的参数类型,也就是doInBackground()执行过程中的产出参数类型,通过publishProgress()发消息
- //传递给onProgressUpdate()一般用来更新界面
- //第三个String代表任务结束的产出类型,也就是doInBackground()的返回值类型,和onPostExecute()的参数类型
- privateclasstaskextendsAsyncTask<String,String,String>{
- //后台执行的耗时任务,接收参数并返回结果
- //当onPostExecute()执行完,在后台线程中被系统调用
- @Override
- protectedStringdoInBackground(String...params){
- System.out.println("doInBackgroundname----->"+Thread.currentThread().getName());
- System.out.println("doInBackgroundid----->"+Thread.currentThread().getId());
- //TODOAuto-generatedmethodstub
- //在这里产生数据,送给onProgressUpdate以更新界面
- Stringpre=params[0];
- System.out.println("preis----->"+pre);
- for(inti=0;i<5;i++){
- System.out.println("noteiambeginsleep");
- publishProgress(pre+i);
- //这里是否需要停顿下
- System.out.println("hualidebuzhuo"+pre+i);
- SystemClock.sleep(1000);
- }
- return"任务结束";
- }
- //任务执行结束后,在UI线程中被系统调用
- //一般用来显示任务已经执行结束
- @Override
- protectedvoidonPostExecute(Stringresult){
- //TODOAuto-generatedmethodstub
- System.out.println("onPostExecutename-------->"+Thread.currentThread().getName());
- System.out.println("onPostExecuteid-------->"+Thread.currentThread().getName());
- super.onPostExecute(result);
- Toast.makeText(testAsync.this,result,Toast.LENGTH_SHORT).show();
- //任务执行5次后推出
- if(times>5){
- return;
- }
- //设定下一次任务触发时间
- Messagemsg=Message.obtain();
- msg.what=MSG_TIMER;
- handler.sendMessageDelayed(msg,10000L);
- }
- //最先执行,在UI线程中被系统调用
- //一般用来在UI中产生一个进度条
- @Override
- protectedvoidonPreExecute(){
- //TODOAuto-generatedmethodstub
- System.out.println("onPreExecuteid------->"+Thread.currentThread().getId());
- System.out.println("onPreExecutename------->"+Thread.currentThread().getName());
- super.onPreExecute();
- Toast.makeText(testAsync.this,"开始执行第"+times+"次任务:"+this,
- Toast.LENGTH_SHORT).show();
- times++;
- }
- //更新界面操作,在收到更新消息后,在UI线程中被系统调用
- @Override
- protectedvoidonProgressUpdate(String...values){
- //TODOAuto-generatedmethodstub
- System.out.println("onProgressUpdateid--------->"+Thread.currentThread().getId());
- System.out.println("onProgressUpdatename------->"+Thread.currentThread().getName());
- super.onProgressUpdate(values);
- vText.append(values[0]);
- }
- }
- }
这个例子,写得很好,里面写了很多关于它的一些使用的方法,注意在使用execute(XXX)里面的参数,就是对应到下面几个方法里面的参数,AsyncTask<Params, Progress, Result>,这个就是相应的映射的参数表。
更多相关文章
- [置顶] [Android基础]Android的消息机制
- Android消息机制源码解析(一)——消息的载体Message
- Android 消息推送(二)基于 MQTT 协议实现的推送功能
- Android异步消息机制Handler详解,源码剖析(API 23)
- Android 线程完全解析
- 主线程中Looper的轮询死循环为何没有阻塞主线程?