说到线程,大家都知道,可以当作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
- package xiaohang.zhimeng;
- import android.app.Activity;
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.os.SystemClock;
- import android.widget.TextView;
- import android.widget.Toast;
- /**
- * 一个使用异步任务的例子。一般来说一个异步任务只执行一次,这个例子有点非主流,任务结束后会触发下一次任务执行。
- * 由任务task在屏幕上打印数字,第一次任务执行由主Activity的onCreate触发,每次任务结束后
- * 设定下一次触发的时间,共执行5次。对于任务来说doInBackground()接收任务的参数params,并执行产生数字的动作,每一个数字
- * 产生后调用一次publishProgress()来更新UI,这个函数本身也是异步的只是用来发个消息调用完成后立即返回,
- * 而产生数字的动作在继续进行。更新界面的操作在onProgressUpdate()中设定。 所有的on函数都由系统调用,不能用户调用。
- * 代码中使用Handler是为了能触发任务执行,android规定这种异步任务每次执行完就结束,若要重新执行需要new一个新的。
- * 异步任务只能在UI线程里面创建和执行
- */
- public class testAsync extends Activity {
- private final int MSG_TIMER = 10000;
- private TextView vText = null;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- super.onCreate(savedInstanceState);
- setContentView(R.layout.test);
- vText = (TextView) findViewById(R.id.TextView01);
- vText.setText("Num...");
- new task().execute("->");
- }
- // 接收任务task发来的消息,触发一个新的任务
- private final Handler handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- // TODO Auto-generated method stub
- super.handleMessage(msg);
- System.out.println("Handler name -----------> " + Thread.currentThread().getName());
- System.out.println("Handler id ------------> " + Thread.currentThread().getId());
- switch (msg.what) {
- case MSG_TIMER:
- new task().execute("->");
- break;
- }
- }
- };
- // 任务执行次数
- private static int times = 1;
- // AsyncTask<>的参数类型由用户设定,这里设为三个String
- // 第一个String代表输入到任务的参数类型,也即是doInBackground()的参数类型
- // 第二个String代表处理过程中的参数类型,也就是doInBackground()执行过程中的产出参数类型,通过publishProgress()发消息
- // 传递给onProgressUpdate()一般用来更新界面
- // 第三个String代表任务结束的产出类型,也就是doInBackground()的返回值类型,和onPostExecute()的参数类型
- private class task extends AsyncTask<String, String, String> {
- // 后台执行的耗时任务,接收参数并返回结果
- // 当onPostExecute()执行完,在后台线程中被系统调用
- @Override
- protected String doInBackground(String... params) {
- System.out.println("doInBackground name -----> " + Thread.currentThread().getName());
- System.out.println("doInBackground id -----> " + Thread.currentThread().getId());
- // TODO Auto-generated method stub
- // 在这里产生数据,送给onProgressUpdate以更新界面
- String pre = params[0];
- System.out.println("pre is ----->" + pre);
- for (int i = 0; i < 5; i++) {
- System.out.println("note i am begin sleep ");
- publishProgress(pre + i);
- // 这里是否需要停顿下
- System.out.println("hua li de bu zhuo " + pre + i);
- SystemClock.sleep(1000);
- }
- return "任务结束";
- }
- // 任务执行结束后,在UI线程中被系统调用
- // 一般用来显示任务已经执行结束
- @Override
- protected void onPostExecute(String result) {
- // TODO Auto-generated method stub
- System.out.println("onPostExecute name --------> " + Thread.currentThread().getName());
- System.out.println("onPostExecute id --------> " + Thread.currentThread().getName());
- super.onPostExecute(result);
- Toast.makeText(testAsync.this, result, Toast.LENGTH_SHORT).show();
- // 任务执行5次后推出
- if (times > 5) {
- return;
- }
- // 设定下一次任务触发时间
- Message msg = Message.obtain();
- msg.what = MSG_TIMER;
- handler.sendMessageDelayed(msg, 10000L);
- }
- // 最先执行,在UI线程中被系统调用
- // 一般用来在UI中产生一个进度条
- @Override
- protected void onPreExecute() {
- // TODO Auto-generated method stub
- System.out.println("onPreExecute id -------> " + Thread.currentThread().getId());
- System.out.println("onPreExecute name -------> " + Thread.currentThread().getName() );
- super.onPreExecute();
- Toast.makeText(testAsync.this, "开始执行第" + times + "次任务: " + this,
- Toast.LENGTH_SHORT).show();
- times++;
- }
- // 更新界面操作,在收到更新消息后,在UI线程中被系统调用
- @Override
- protected void onProgressUpdate(String... values) {
- // TODO Auto-generated method stub
- System.out.println("onProgressUpdate id ---------> " + Thread.currentThread().getId());
- System.out.println("onProgressUpdate name -------> " + Thread.currentThread().getName());
- super.onProgressUpdate(values);
- vText.append(values[0]);
- }
- }
- }
这个例子,写得很好,里面写了很多关于它的一些使用的方法,注意在使用execute(XXX)里面的参数,就是对应到下面几个方法里面的参数,AsyncTask<Params, Progress, Result>,这个就是相应的映射的参数表。