关于Android AsyncTask的一些总结

  根据Google自己的说法,AsyncTask只适用于数量不多且短暂的操作,至于原因嘛,可能是因为从Android 3.2开始,AsyncTask又被改成串行的了,这样如果你用AsyncTask执行很多任务,或者某个任务执行时间很长的话,那么后面的任务就没法及时执行了。下面先看它的一个典型用法,然后再具体展开说:

package com.whereru.testcode3;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;
import android.widget.ProgressBar;

import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private ImageView mImageView;
    private ProgressBar mProgressBar;
    private DownloadTask mDownloadTask;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        System.out.println("MainActivity onCreate");

        mImageView = (ImageView) findViewById(R.id.image_view);
        mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);

        URL[] urls = null;
        try {
            urls = new URL[]{
                    new URL("http://img4.imgtn.bdimg.com/it/u=2317499888,864114656&fm=21&gp=0.jpg"),
                    new URL("http://img0.imgtn.bdimg.com/it/u=4256573763,278547175&fm=21&gp=0.jpg"),
                    new URL("http://img2.imgtn.bdimg.com/it/u=546811603,943746655&fm=21&gp=0.jpg"),
                    new URL("http://img0.imgtn.bdimg.com/it/u=93040804,2971684664&fm=21&gp=0.jpg")
            };
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        mDownloadTask = new DownloadTask(this);
        mDownloadTask.execute(urls);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mDownloadTask.cancel(false);
        System.out.println("MainActivity onDestroy");
    }

    private static class DownloadTask extends AsyncTask<URL, Integer, List<Bitmap>> {

        private WeakReference<MainActivity> mMainActivityWeakReference;

        DownloadTask(MainActivity mainActivity) {
            mMainActivityWeakReference = new WeakReference<>(mainActivity);
        }

        @Override
        protected List<Bitmap> doInBackground(URL... urls) {
            //工作线程,负责下载图片,并转化成Bitmap
            HttpURLConnection httpURLConnection = null;
            List<Bitmap> bitmapList = new ArrayList<>();
            for (int i = 0; i < urls.length; i++) {
                System.out.println("正在下载图片:" + (i + 1));
                try {
                    httpURLConnection = (HttpURLConnection)
                            urls[i].openConnection();
                    InputStream inputStream = httpURLConnection.getInputStream();
                    if (httpURLConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                        throw new IOException(httpURLConnection.getResponseMessage() + ":with" +
                                urls[i]);
                    }
                    bitmapList.add(BitmapFactory.decodeStream(inputStream));
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (httpURLConnection != null) {
                        httpURLConnection.disconnect();
                    }
                }
                if (isCancelled()) {
                    break;
                }
                publishProgress((int) (((float) (i + 1) / urls.length) * 100));
            }

            return bitmapList;
        }

        @Override
        protected void onProgressUpdate(Integer... progress) {
            System.out.println("更新进度条");
            if (mMainActivityWeakReference.get() != null) {
                mMainActivityWeakReference.get().mProgressBar.setProgress(progress[0]);//更新进度条
            }
        }

        @Override
        protected void onPostExecute(final List<Bitmap> bitmapList) {
            System.out.println("图片下载完成,开始显示图片");
            //图片下载完成后,在UI线程中每隔两秒显示一张图片
            for (int i = 0; i < bitmapList.size(); i++) {
                final int finalI = i;
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if (mMainActivityWeakReference.get() != null) {
                            mMainActivityWeakReference.get().mImageView
                                    .setImageBitmap(bitmapList.get(finalI));
                        }
                    }
                }, 2000 * i);
                if (isCancelled()) {
                    break;
                }
            }
        }

    }

}

  布局文件:   

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <ProgressBar
        android:id="@+id/progress_bar"
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="300dp"
        android:layout_height="300dp"/>

</LinearLayout>

  上面代码实现的功能就是从网上下载了4张图片,然后有个进度条可以显示下载进度,下载完成后,每隔两秒钟显示一张图片。
  下面说下一些注意问题。

0.

  如果你觉得Activity被销毁后就不需要相应AsyncTask接着执行任务了,记得在onDestroy中执行cancel方法。

1.  

  不管在你下载图片还是显示图片的for循环中记得用下:  

if (isCancelled()) {
    break;
}  

  这样可以确保在你取消相应任务的时候,可以及时停止接着做无用功。

2.

  使用静态内部类和弱引用避免可能发生的内存泄露。(其实我觉得吧,其实如果内存不是很紧张,问题也不是很大,AsyncTask执行完了,自然Activity也就可以被回收了,而AsyncTask本来就不是用来执行长时间任务的,正常使用也不会长时间占着内存,个人看法。。。)

3.

  考虑个问题,我们跳到了另一个Acyivity,然后我们并没有取消原来Activity的AsyncTask,而原来的Activity又被销毁了,会怎么样?
  如果内存泄露的问题没解决,那程序肯定不会奔溃。那么采用了上面的方法解决了内存泄露,程序就一定会奔溃?其实也不一定,主要看那个被销毁的Activity是不是被GC回收了。不过为了安全起见,我们上面都做了WeakReference.get() != null的判断。
  
  相关阅读:
  Android多线程任务优化1:探讨AsyncTask的缺陷
  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值