《老罗Android》学习之 AsyncTask异步任务

1. AsyncTask 异步任务
 Android3.0之后的版本不允许在UI主线程当中访问网络,为了UI显示流畅,就需要开辟一个子线程来完成对网络的访问。UI主线程和这个子线程是异步的,子线程完成网络下载之后,可以把下载的内容显示在UI界面上。

在Android中实现异步任务机制有两种方式,Handler和AsyncTask。

Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较精细,但也是有缺点的,例如代码相对臃肿,在多个任务同时执行时,不易对线程进行精确的控制。

 下面这部分摘自:http://blog.csdn.net/wykwdy007/article/details/7847637

AsyncTask是在Android SDK 1.5之后推出的一个方便编写后台线程和UI线程交互的辅助类。它的实现是通过一个内部的线程池,每个后台任务装载到线程池中的一个线程,然后在执行该线程。AsyncTask抽象出后台线程运行的五个状态:1,准备运行。2,正在后台运行。3,进度更新。4,完成后台任务。5,取消任务。

AsyncTask是一个泛型类,原型为:android.os.AsyncTask<Params, Progress, Result>

Params:启动任务执行的输入参数,比如Http请求的URL。

Progress:后台任务执行的百分比。

Result:后台执行任务的最终返回结果,如String。

要实现的方法:

onPreExecute()------->准备阶段:该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。

doInBackground(Params...)------>正在后台运行:该回调函数由后台线程在onPreExecute()方法执行结束后立即调用。通常在这里执行耗时的后台计算。计算的结果必须由该函数返回,并被传递到onPostExecute()中。在该函数内也可以使用publishProgress(Progress...)来发布一个或多个进度单位(unitsof progress)。这些值将会在onProgressUpdate(Progress...)中被发布到UI线程。

onProgressUpdate(Progress...)--------->进度更新:该函数由UI线程在publishProgress(Progress...)方法调用完后被调用。一般用于动态地显示一个进度条。

onPostExcute(Result)-------->完成后台任务:当后台计算结束后调用。后台计算的结果会被作为参数传递给这一函数。

onCancelled()-------------->取消任务:在调用AsyncTask的cancel()方法时调用

为了正确的使用AsyncTask类,以下是几条必须遵守的准则: 
  1) Task的实例必须在UI thread中创建 
  2) execute方法必须在UI thread中调用 
  3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法 
  4) 该task只能被执行一次,否则多次调用时将会出现异常 
      doInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为doInBackground接受的参数,第二个为显示进度的参数,第第三个为doInBackground返回和onPostExecute传入的参数。

AsyncTask的本质是一个线程池,然后提交的异步任务将装载在一个线程中然后执行,当工作的线程需要更UI线程交互时,



实例1:
public class MainActivity extends Activity {
	private Button button;
	private ImageView imageview;
	private String image_path="http://e.hiphotos.baidu.com/image/" +
			"h%3D1050%3Bcrop%3D0%2C0%2C1680%2C1050/sign=a7bb27240db30f242a" +
			"9ae803fda5ea20/95eef01f3a292df53ccc2050be315c6034a8736c.jpg";
	private ProgressDialog dialog;
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		button=(Button)this.findViewById(R.id.button1);
		imageview=(ImageView)this.findViewById(R.id.imageView1);
		dialog=new ProgressDialog(this);
		dialog.setTitle("提示信息");
		dialog.setMessage("正在下载,请稍后...");
		button.setOnClickListener(new View.OnClickListener() {
		public void onClick(View v) {
		//执行异步任务的操作
		new MyTask().execute(image_path);
		}
		});	
	}	
	/**使用异步任务的规则:
	 * 1. 声明一个类继承AsyncTask标注三个参数的类型
	 * 2. 第一个参数表示要执行的任务通常是网络的路径 
	 * 第二个参数表示的是进度的刻度,第三个参数表示执行的返回结果
	 */
	public class MyTask extends AsyncTask<String, Void, Bitmap>{
		//表示完成耗时操作
	protected Bitmap doInBackground(String... params) {
		//使用网络链接类HttpClient类完成对网络数据的提取。
		HttpClient httpClient=new DefaultHttpClient();
		HttpGet httpGet=new HttpGet(params[0]);
		Bitmap bitmap=null;
		try {
		HttpResponse httpResponse=httpClient.execute(httpGet);
		if(httpResponse.getStatusLine().getStatusCode()==200){
		HttpEntity httpEntity=httpResponse.getEntity();
		byte[] data=EntityUtils.toByteArray(httpEntity);
		bitmap=BitmapFactory.decodeByteArray(data, 0, data.length);
		}
		} catch (Exception e) {
			e.printStackTrace();
		}			
		return bitmap;
		}
	protected void onPreExecute() {//表示任务执行之前的操作
		super.onPreExecute();
		dialog.show();	
             }		
		//主要是更新UI操作
	protected void onPostExecute(Bitmap result) {
		super.onPostExecute(result);
		imageview.setImageBitmap(result);
		dialog.dismiss();		
		}		
	}
}
以上就是一个简单的异步操作的例子,在AsyncTask中进行耗时操作,在onPostExecute中更新UI,它是明确的先后执行顺序。以上实例实现了从网络上下载一张图片,并显示的功能。
实例2:加入了进度条显示下载的进度
public class MainActivity extends Activity {
        ......
private String image_path="http://d.hiphotos.baidu.com/image/pic/item/d788d43f8794a4c2a63b262f0cf41bd5ad6e399e.jpg";
private ProgressDialog dialog;
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_main);
	button=(Button)this.findViewById(R.id.button1);
	imageview=(ImageView)this.findViewById(R.id.imageView1);
	dialog=new ProgressDialog(this);
	dialog.setTitle("提示信息");
	dialog.setMessage("正在下载,请稍后...");
	dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
	dialog.setCancelable(false);
	button.setOnClickListener(new View.OnClickListener() {
	public void onClick(View v) {
	//执行异步任务的操作
	new MyTask().execute(image_path);
	}
	});	
}
	/**使用异步任务的规则:
	 * 1. 声明一个类继承AsyncTask标注三个参数的类型
	 * 2. 第一个参数表示要执行的任务通常是网络的路径 
	 * 第二个参数表示的是进度的刻度,第三个参数表示执行的返回结果	 */
	public class MyTask extends AsyncTask<String, Integer, Bitmap>{
	//表示完成耗时操作
	protected Bitmap doInBackground(String... params) {
	//使用网络链接类HttpClient类完成对网络数据的提取。
	HttpClient httpClient=new DefaultHttpClient();
	HttpGet httpGet=new HttpGet(params[0]);
	ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
	InputStream inputStream=null;
	Bitmap bitmap=null;
	try {
	HttpResponse httpResponse=httpClient.execute(httpGet);
	if(httpResponse.getStatusLine().getStatusCode()==200){
		inputStream=httpResponse.getEntity().getContent();
		//先要获得文件的总长度
		long file_length=httpResponse.getEntity().getContentLength();
		int len=0;
		byte[] data=new byte[1024];
		int total_length=0;
		while((len=inputStream.read(data))!=-1){
		total_length+=len;
		int values=(int)((total_length/(float)file_length)*100);
		publishProgress(values);
		outputStream.write(data,0,len);
		}
		byte[] result=outputStream.toByteArray();
		bitmap=BitmapFactory.decodeByteArray(result, 0, result.length);
		}
		} catch (Exception e) {
		e.printStackTrace();
	}finally{
	if(inputStream!=null){
	try {
		inputStream.close();
	} catch (Exception e2) {
	e2.printStackTrace();
		}
	}
	}
			
	return bitmap;
	}
	protected void onPreExecute() {//表示任务执行之前的操作
	super.onPreExecute();
	dialog.show();	
		}
	protected void onProgressUpdate(Integer... values) {
	super.onProgressUpdate(values);
	dialog.setProgress(values[0]);			
	}	
	//主要是更新UI操作
	protected void onPostExecute(Bitmap result) {
	super.onPostExecute(result);
	imageview.setImageBitmap(result);
	dialog.dismiss();				
	}	
	}
}

  上面介绍了AsyncTask的基本应用,有些朋友也许会有疑惑,AsyncTask内部是怎么执行的呢,它执行的过程跟我们使用Handler又有什么区别呢?答案是:AsyncTask是对Thread+Handler良好的封装,在android.os.AsyncTask代码里仍然可以看到Thread和Handler的踪迹。

总结:Handler和AsyncTask都是为了主线程不被阻塞UI线程,但是UI的更新只能在UI主线程这个完成这是因为Android的单线程模型,所以要异步的完成。

AsyncTask 的优势体现在:
•线程的开销较大,如果每个任务都要创建一个线程,那么应用程 序的效率要低很多; 
•线程无法管理,匿名线程创建并启动后就不受程序的控制了,如果有很多个请求发送,那么就会启动非常多的线程,系统将不堪重负。

•另外,在新线程中更新UI还必须要引入handler,这让代码看上去非常臃肿。

概括来说,当我们调用execute(Params... params)方法后,execute方法会调用onPreExecute()方法,然后由ThreadPoolExecutor实例sExecutor执行一个FutureTask任务,这个过程中doInBackground(Params... params)将被调用,如果被开发者覆写的doInBackground(Params... params)方法中调用了publishProgress(Progress... values)方法,则通过InternalHandler实例sHandler发送一条MESSAGE_POST_PROGRESS消息,更新进度,sHandler处理消息时onProgressUpdate(Progress... values)方法将被调用;如果遇到异常,则发送一条MESSAGE_POST_CANCEL的消息,取消任务,sHandler处理消息时onCancelled()方法将被调用;如果执行成功,则发送一条MESSAGE_POST_RESULT的消息,显示结果,sHandler处理消息时onPostExecute(Result result)方法被调用。


进阶版:
Android实战技巧:深入解析AsyncTask




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值