深入认识AsyncTask
1、概述
在Android开发中是采用单线程模型,主线程通常称为UI线程,由于UI线程的操作不是线程安全的,因此android规定有关更新界面的操作必须在主线程中进行,其他线程直接报错。
如果我们把所有操作都放在UI线程中也是不行的,因为这时候会出现ANR(Activity Not Respone),为了强化用户体验android在UI线程中不建议有超过5s的事件,当用户输入事件5s内没有得到响应(广播接收者的onReceive()执行时间超过10s)将弹出ANR对话框,因此一些耗时操作通常放在子线程中处理,这里通常使用AsyncTask或者Handler,本篇重点介绍前者,通常AsyncTask非常适合需要将中间值和最终结果返回给用户的情形。
2、如何使用AsyncTask
分为以下3步:
2.1、继承AsyncTask
AsyncTask是一个抽象类,我们在使用它之前需要继承AsyncTask类,有3个泛型参数(三个参数可以是任何类型),
第一个参数:传入doInBackground()方法的参数类型,本例是String类型的URL地址
第二个参数:传入onProgressUpdate()方法的参数类型,本例是Integer
第三个参数:传入onPostExecute()方法的参数类型,也是doInBackground()方法返回的类型。本例是Bitmap下载显示的图片
2.2、重写方法
【onPreExecute()】该方法将在执行实际的后台操作前被UI thread调用。这个方法只是做一些准备工作,如在界面上显示一个进度条。
【doInBackground(Params...)】, 将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将只能负责执行那些很耗时的后台计算工作,不能进行UI操作。
【publishProgress】 该方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。
【onProgressUpdate(Progress...)】 在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,可以通过一个进度条进行展示。
【onPostExecute(Result)】, 在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread.,可以更新UI
可以借用一张图来表示他们之间的关系
2.3、在UI中使用
要注意以下几点:
【1】 Task的实例必须在UI thread中创建
【2】execute方法必须在UI thread中调用
3、代码实例
使用AsyncTask在网上下载图片
布局很简单垂直的LinearLayout,放了一个button,progressbar,imageView,记得在配置清单文件加上网络访问权限,需要从网上下载图片,这里就不展示了,后面有demo下载
主要看下Mativity.Java,里面有详细注释
- <span style="font-size:18px;">public class MainActivity extends AppCompatActivity {
- private ImageView image;
- private Button showButton;
- private ProgressBar mProgressBar;
- private int number;
- List<String> imageUrl;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- //布局控件
- image = (ImageView) findViewById(R.id.imagePic);
- showButton = (Button) findViewById(R.id.myButton);
- mProgressBar = (ProgressBar) findViewById(R.id.processbar);
- //button绑定监听器
- showButton.setOnClickListener(new showButtonListener());
- //添加下载图片的URL
- imageUrl = new ArrayList<String>();
- imageUrl.add("http://image.tianjimedia.com/uploadImages/2011/266/AIO90AV2508S.jpg");
- imageUrl.add("http://image.tianjimedia.com/uploadImages/2012/090/063N2L5N2HID.jpg");
- imageUrl.add("http://comic.sinaimg.cn/2011/0824/U5237P1157DT20110824161051.jpg");
- imageUrl.add("http://image.tianjimedia.com/uploadImages/2012/090/1429QO6389U8.jpg");
- imageUrl.add("http://new.aliyiyao.com/UpFiles/Image/2011/01/13/nc_129393721364387442.jpg");
- }
- public class showButtonListener implements View.OnClickListener {
- @Override
- public void onClick(View v) {
- MyAsyncTask myAsyncTask = new MyAsyncTask(getApplicationContext());
- myAsyncTask.execute(imageUrl.get(number % imageUrl.size()));//这样可以循环下载url图片
- number++;
- }
- }
- //String:uri,Integer进度,Bitmap 图片
- private class MyAsyncTask extends AsyncTask<String, Integer, Bitmap> {
- public MyAsyncTask(Context context) {
- mProgressBar.setVisibility(View.VISIBLE);
- image.setVisibility(View.GONE);
- }
- /*
- *onPreExecute() 该方法将在执行实际的后台操作前被UI thread调用。这个方法只是做一些准备工作,
- * 如在界面上显示一个进度条。
- *doInBackground(Params...), 将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。
- * 这里将主要负责执行那些很耗时的后台计算工作。
- *publishProgress 该方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。
- *onProgressUpdate(Progress...), 在publishProgress方法被调用后,
- * UI thread将调用这个方法从而在界面上展示任务的进展情况,可以通过一个进度条进行展示。
- *onPostExecute(Result), 在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,
- * 后台的计算结果将通过该方法传递到UI thread.
- */
- @Override
- protected Bitmap doInBackground(String... params) {
- Bitmap bitmap = null;
- //根据输入的URL下载对应的图片
- try {
- URL mUrl = new URL(params[0]);
- URLConnection urlConnection = mUrl.openConnection();
- urlConnection.connect();
- InputStream inputStream = urlConnection.getInputStream();
- bitmap = BitmapFactory.decodeStream(inputStream);
- // Toast.makeText(getApplicationContext(),"图片下载完成",Toast.LENGTH_LONG).show();该方法是非UI线程中,
- // 如果加上这句会报错,体现了非UI线程不能更新UI界面
- inputStream.close();
- } catch (MalformedURLException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return bitmap;
- }
- /*
- *在doInBackground方法执行完成后调用,onPreExecute方法被UI线程调用,后台的计算结
- *果通过该方法传递到UI线程
- * */
- @Override
- protected void onPostExecute(Bitmap bitmap) {
- mProgressBar.setVisibility(View.GONE);
- image.setVisibility(View.VISIBLE);
- if (bitmap != null) {
- image.setImageBitmap(bitmap);
- } else {
- Toast.makeText(getApplicationContext(), "网络异常", Toast.LENGTH_SHORT).show();
- }
- }
- @Override
- protected void onPreExecute() {
- // 任务启动
- Toast.makeText(getApplicationContext(), "任务开始......", Toast.LENGTH_SHORT).show();
- }
- }
- }
- </span>
4、AsyncTask的缺陷
【1】生命周期
AsyncTask不会随着Activity的销毁而销毁。它会一直 执行, 直到doInBackground()方法执行完毕。然后,如果 cancel(boolean)被调用, 那么onCancelled(Result result) 方法会被执行;否则,执行onPostExecute(Result result) 方法。如果我们的Activity销毁之前,没有取消 AsyncTask,这有可能让我们的AsyncTask崩溃(crash)。 另外,即使我们正确地调用了cancle() 也未必能真正地取消任务。因为如果在doInBackgroud里有一个不可中断的操作,比如BitmapFactory.decodeStream(),那么这个操作会继续下去。
【2】内存泄露
如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会保留一个对创建了AsyncTask的Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄露。
【3】并行还是串行
在Android 1.6之前的版本,AsyncTask是串行的,在1.6至2.3的版本,改成了并行的。在2.3之后的版本又做了修改,可以支持并行和串行,当想要串行 执行时,直接执行execute()方法,如果需要并行执行,则要执行executeOnExecutor(Executor)。
【4】结果丢失
屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。
【5】薄弱的并发性能(大于128个线程直接FC)
- private static final int CORE_POOL_SIZE =5;//5个核心工作线程
- private static final int MAXIMUM_POOL_SIZE = 128;//最多128个工作线程
- private static final int KEEP_ALIVE = 1;//空闲线程的超时时间为1秒
- private static final BlockingQueue<Runnable> sWorkQueue =
- new LinkedBlockingQueue<Runnable>(10);//等待队列
- private static final ThreadPoolExecutorsExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
- MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue,sThreadFactory);//线程池是静态变量,所有的异步任务都会放到这个线程池的工作线程内执行。
通过以上线程池参数可以知道
1、线程池中的工作线程少于5个时,将会创建新的工作线程执行异步任务
2、线程池中已经有5个线程,缓冲队列未满,异步任务将会放到缓冲队列中等待
3、线程池中已经有5个线程,缓冲队列已满,那么线程池将新开工作线程执行异步任务
4、线程池中已经有128个线程,缓冲队列已满,如果此时向线程提交任务,将会抛出RejectedExecutionException
如果我们使用超过它的范围直接就不行了
详细可以参看这篇http://blog.****.net/mylzc/article/details/6784415#
本练习dome地址http://download.****.net/detail/xsf50717/9194849
转载:http://blog.****.net/xsf50717/article/details/49255509