少年辛苦终身事,莫向光阴惰寸功。这篇文章主要讲述Android攻城狮AsyncTask相关的知识,希望能为你提供帮助。
构建AsyncTack子类的参数 AsyncTask< Params,Progress,Result> 是一个抽象类,通常用于被继承,继承AsyncTask需要指定如下三个泛型参数: params:启动任务时输入参数的类型。 progress:后台任务执行中,返回进度值的类型。 Result:后台执行任务完成后,返回结果的类型。 ------------------------ 如何构建AsyncTask子类的回调方法? 一个完整的AsyncTask通常需要指定如下几个方法: 1. doInBackground:这是AsyncTask子类所必须要重写的方法,异步执行后台线程将要完成的任务。我们所有的耗时操作都将在这个方法中进行操作。 2. onPreExecute:执行后台耗时操作之前被调用,通常是用户完成一些初始化操作。 3. onPostExecute:当doInBackground()完成后,系统会自动调用此方法,并将doInBackground()返回的值传给该方法,也就是展示处理完成的结果。 4. onProgressUpdate:在doInBackground()方法中调用publishProgrsss()更新任务的执行进度后,就会触发该方法(必须先调用publishProgrsss()),就可以知道当前耗时操作的完成进度。 ---------------------------------- 额外补充: 1. 注意这里的例子继承的是 AsyncTask< Void,Void,Void> ,需要带上三个泛型,定义Void泛型要注意V是大写。。。 2. 执行顺序:onPrRreExecute() --> doInBackground() --> onProgressUpdate()--> onPostExecute()。
AsyncTask< String,Void,Bitmap> 三个参数分别为:url类型,进度值类型,返回值类型。 这里的例子暂时不设置进度值,url设置为String类型,又因为我们加载的是一张Bitmap,所以返回的参数类型设置为 Bitmap。 1. doInBackground(String...params)传进来的是一个可变长数组,也就是说,我们可以传进不止一个参数(通过execute()传进来),这些参数依次存在于这个数组中。现在只有一个参数,所以只要写个params[0]取出对应的URL即可。 2. 定义一个Bitmap,也就是我们所要获取的Bitmap。 3. 定义一个访问网络的URLconnection,也就是一个网络连接对象connection。 4. 定义一个InputStream,用于获取数据的输入流。 5. 初始化connection:connection = new URL(url).openConnection(); 这里需要自行导入jar包:import java.net.URL; 另外需要try-catch包围。 6. 获取输入流:is = connection.getInputStream(); 7. 对输入流进行包装:BufferedInputStream bis = new BufferedInputStream(is); 8. 通过decodeStream()将输入流解析成 Bitmap:bitmap = BitmapFactory.decodeStream(bis); 9. 关闭输入流、返回 bitmap。
1 public class ImageTest extends Activity { 2private ImageView imageView; 3private ProgressBar progressBar; 4String URL = "http://p4.so.qhimgs1.com/sdr/1228_768_/t01f7ed810efbfe800a.jpg"; 5 6@Override 7protected void onCreate(Bundle savedInstanceState) { 8// TODO Auto-generated method stub 9super.onCreate(savedInstanceState); 10setContentView(R.layout.image); 11imageView = (ImageView) findViewById(R.id.image); 12progressBar = (ProgressBar) findViewById(R.id.bar); 13 14MyAsynctask1 task = new MyAsynctask1(); 15task.execute(URL); 16 17} 18 19// params:启动任务时输入参数的类型。 20// progress:后台任务执行中,返回进度值的类型。 21// Result:后台执行任务完成后,返回结果的类型。 22class MyAsynctask1 extends AsyncTask< String, Void, Bitmap> { 23@Override 24// 异步初始化 25protected void onPreExecute() { 26// TODO Auto-generated method stub 27super.onPreExecute(); 28// 显示进度条 29progressBar.setVisibility(View.VISIBLE); 30} 31 32@Override 33protected void onPostExecute(Bitmap result) { 34// TODO Auto-generated method stub 35super.onPostExecute(result); 36progressBar.setVisibility(View.GONE); 37imageView.setImageBitmap(result); 38 39} 40 41@Override 42protected Bitmap doInBackground(String... params) { 43// TODO Auto-generated method stub 44 45// 从params中取出参数值,传给url 46String url = params[0]; 47// 初始化参数 48Bitmap bitmap = null; 49URLConnection connection; 50InputStream inputStream; 51 52try { 53connection = new URL(url).openConnection(); 54inputStream = connection.getInputStream(); // 获取输入流 55BufferedInputStream bis = new BufferedInputStream(inputStream); 56Thread.sleep(3000); // 睡3秒 57// 通过decodeStream()解析输入流 58bitmap = BitmapFactory.decodeStream(bis); 59inputStream.close(); 60bis.close(); 61 62} catch (IOException e) { 63// TODO Auto-generated catch block 64e.printStackTrace(); 65} catch (InterruptedException e) { 66// TODO Auto-generated catch block 67e.printStackTrace(); 68} 69return bitmap; 70} 71 72} 73 74 }
反复执行上一节课的异步加载,而且是不等进度条满就后退再执行,会发现后面执行的进度条迟迟没有响应,为什么呢?这并非bug,而是 AsyncTask 所实行的一种机制。AsyncTask的底层是通过线程池去作用的。当一个线程没有完成的时候,后面的线程就无法开始。我们上一节课用了for()循环去执行进度条 的更新操作,必须等到for()循环结束后才会执行下一个Task。 --------- 那么,如何去解决这样的问题呢? 很简单,令AsyncTask的生命周期和Activity或者Fragment的生命周期保持一致就可以了。 回到ProgressBar,重写onPause(),在Activity执行onPause()的时候,对AsyncTask进行判断: 如果AsyncTask不为空且处于Running状态,我们就要取消该线程: protected void onPause() { super.onPause(); if(mTask!=null & & mTask.getStatus()==AsyncTask.Status.RUNNING){ mTask.cancel(true); } } cancle()方法只是将对应的AsyncTask标记为cancel状态,并不是真正地取消线程的执行。 另外,我们在Java中也是没办法直接粗暴地停止一个线程,我们必须要等一个线程执行完毕之后才能继续其他线程的操作。 -------------- 那要如何快速停止线程呢? 1. 在onPause()中标记取消状态:mTask.cancel(true); 既然我们已经标记了cancel状态,那么可以在AsyncTask中监测这样的改变,一旦当前状态改为cancelled,我们就要跳出循环,立刻结束当前操作,从而结束整个线程逻辑。 2. 在doInBackground()方法的for()循环内添加isCancelled()对线程的状态进行判断: if(isCancelled())break; 3. 同理,在onProgressUpdate()方法中也做类似的处理: if(isCancelled())return; 通过如上操作,我们就能快速停止当前线程,将处理权交给下一个AsyncTask。
1 public class ProgressBarTest extends Activity { 2 3ProgressBar progressBar; 4MyAsycnTask2 task; 5@Override 6protected void onCreate(Bundle savedInstanceState) { 7// TODO Auto-generated method stub 8super.onCreate(savedInstanceState); 9setContentView(R.layout.progressbar); 10progressBar = (ProgressBar) findViewById(R.id.progressBar1); 11 12task = new MyAsycnTask2(); 13task.execute(); 14} 15 16@Override 17protected void onPause() { 18// TODO Auto-generated method stub 19super.onPause(); 20if (task!=null& & task.getStatus()==AsyncTask.Status.RUNNING) { 21task.cancel(true); //cancel()只是将对应的task标记为cancel状态,并不是真正取消线程执行 22} 23} 24 25class MyAsycnTask2 extends AsyncTask< Void, Integer, Void> { 26 27@Override 28protected void onProgressUpdate(Integer... values) { 29// TODO Auto-generated method stub 30// 获取进度更新值 31super.onProgressUpdate(values); 32if (isCancelled()) { 33return; 34} 35progressBar.setProgress(values[0]); 36} 37 38@Override 39protected Void doInBackground(Void... params) { 40// TODO Auto-generated method stub 41 42// 模拟进度更新 43for (int i = 0; i < 100; i++) { 44if (isCancelled()) { 45break; 46} 47publishProgress(i); 48try { 49Thread.sleep(300); 50} catch (InterruptedException e) { 51// TODO Auto-generated catch block 52e.printStackTrace(); 53} 54} 55return null; 56} 57} 58 }
【Android攻城狮AsyncTask】
推荐阅读
- Android缓存处理
- 从CM刷机过程和原理分析Android系统结构
- Android 性能优化之内存泄漏检测以及内存优化(上)
- Android自定义view之view显示流程
- Android开发之深入理解Android Studio构建文件build.gradle配置
- Android获取桌面应用程序
- Android Stdio 如何自定义生成APK的名称
- Android NFC近场通信03----读写MifareClassic卡
- Android Intent Scheme URLs攻击