ANDROID异步调用

Andorid里面对界面的操作都是在UI主线程里面,可以简单的理解就是在你的Activity里重写的父类方法都是在主线程里,那么在这里面如果写一写比较耗时的计算或者http请求,这时候界面是不能响应的,所以对于这些耗时的任务我们一般都放在另外一个线程里面去执行,而界面还可以正常的响应用户的操作,这种异步调用可以通过AsyncTask,Handle,Service来实现。

AsyncTask是个泛型实现,提供三个泛型参数

1.Param 任务执行器需要的数据类型
2.Progress 后台计算中使用的进度单位数据类型
3.Result 后台计算返回结果的数据类型

四个方法:
1.onPreExecute() 执行预处理,它运行于UI线程,可以为后台任务做一些准备工作,比如绘制一个进度条控件。
2.doInBackground(Params…) 后台进程执行的具体计算在这里实现,doInBackground(Params…)是AsyncTask的关键,此方法必须重载。在这个方法内可以使用publishProgress(Progress…)改变当前的进度值。
3.onProgressUpdate(Progress…) 运行于UI线程。如果在doInBackground(Params…) 中使用了publishProgress(Progress…),就会触发这个方法。在这里可以对进度条控件根据进度值做出具体的响应。
4.onPostExecute(Result) 运行于UI线程,可以对后台任务的结果做出处理,结果就是doInBackground(Params…)的返回值。此方法也要经常重载,如果Result为null表明后台任务没有完成(被取消或者出现异常)。

一个简单的示例

// AsyncTask异步方式下载图片
class DownImageTask extends AsyncTask<String, Integer, Bitmap> {
	// 执行预处理
	@Override
	protected void onPreExecute() {
		super.onPreExecute();
		// 显示进度条
		progressBar.setVisibility(View.VISIBLE);
		progressBar.setMax(100);
	}
	// 后台进程的执行
	@Override
	protected Bitmap doInBackground(String... params) {
		try {
			URL url = new URL(params[0]);
			HttpURLConnection conn = (HttpURLConnection) url
					.openConnection();
			InputStream inputStream = conn.getInputStream();
			bitmap = BitmapFactory.decodeStream(inputStream);
			// 进度条的更新,我这边只是用一个循环来示范,在实际应用中要使用已下载文件的大小和文件总大小的比例来更新
			for (int i = 1; i <= 10; i++) {
				publishProgress(i * 10);
				Thread.sleep(200);
			}
			inputStream.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return bitmap;
	}
	// 运行于UI线程,对后台任务的结果做出处理,doInBackground方法执行的结果作为此方法的参数
	@Override
	protected void onPostExecute(Bitmap result) {
		super.onPostExecute(result);
		ImageView imageView = (ImageView) findViewById(R.id.image);
		imageView.setImageBitmap(result);
		progressBar.setVisibility(View.GONE);
	}
	// 运行于UI线程,如果在doInBackground(Params...)中使用了publishProgress(Progress...),就会触发此方法
	@Override
	protected void onProgressUpdate(Integer... values) {
		super.onProgressUpdate(values);
		progressBar.setProgress(values[0]);
	}
}

调用代码:

public class MainActivity extends Activity {  
    private Button button;
    private ProgressBar progressBar; 
      
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
          
        button = (Button)findViewById(R.id.button);
        progressBar = (ProgressBar)findViewById(R.id.progressBar);
          
        button.setOnClickListener(new OnClickListener() {  
              
            @Override  
            public void onClick(View v) {  
                ProgressBarAsyncTask asyncTask = new DownImageTask();  
                asyncTask.execute("http://www.baidu.com/img/baidu_jgylogo3.gif");
            }  
        });
    }

 

Handler:
Handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程中)
两个作用:
安排消息或Runnable 在某个主线程中某个地方执行
安排一个动作在不同的线程中执行

Handler中分发消息的方法:
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable,long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
*以上post开头的方法在主线程中调用。
*以上send开头的方法在其它线程中调用。

示例代码:

public class HandlerTestActivity extends Activity {

    private Button start;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.handlertest);
        start = (Button) findViewById(R.id.start);
        start.setOnClickListener(new startListener());

        System.out.println("Activity Thread:" + Thread.currentThread().getId());
    }

    Handler  handler = new Handler(){

        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            if (msg.what == 1) {
                //成功,做一些操作
            } else {
                //失败,..
            }
        }
        
    };
    Runnable thread  = new Runnable() {

                         @Override
                         public void run() {
                             // TODO Auto-generated method stub 
                             System.out.println("HandlerThread:" + Thread.currentThread().getId());
                             //Message message = new Message();
                             //message.what = 1;
                             //handler.sendMessage(message);

                         }
                     };

    class startListener implements OnClickListener {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub 
            handler.post(thread);
            //Thread t = new Thread(thread);
            //t.start();
        }
    }

}

这个程序看上去似乎实现了Handler的异步机制, handler.post(thread)似乎实现了新启线程的作用,不过通过执行我们发现,两个线程的ID相同!也就是说,实际上thread还是原来 的主线程,由此可见,handler.post()方法并未真正新建线程,只是在原线程上执行而已,我们并未实现异步机制。将startListener改写成如下代码就可以实现异步:

class startListener implements OnClickListener {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub 
            //handler.post(thread);
            Thread t = new Thread(thread);
            t.start();
        }
    }

将runnable放到新创建的线程中执行,这样就实现了异步调用,如果需要在调用完成后通知或修改主线程,需要在Runnable类的run方法中调用handler.sendMessage(message)

@Override
 public void run() {
     // TODO Auto-generated method stub 
     System.out.println("HandlerThread:" + Thread.currentThread().getId());
     Message message = new Message();
     message.what = 1;
     handler.sendMessage(message);
}