AsyncTask的使用

1、AsyncTask可以操作耗时操作,也可以进行UI更新,是Thread与Handler的结合,内部通过线程池来封装,不熟悉异步操作机制(Handler,Message,Looper)的朋友,可以先了解下Handler的异步机制,可以参考鸿洋大神的这篇博客:http://blog.csdn.net/lmj623565791/article/details/38377229,以及郭神的这篇从源码解析HandHandler机制http://blog.csdn.net/guolin_blog/article/details/9991569

2、来,先shan上代码,简单的例子,通过URL获取一张图片并显示

class ImageTask extends AsyncTask<String,Void,Bitmap>{
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            mImageView.setVisibility(View.GONE);
            mProgressBar.setVisibility(View.VISIBLE);
        }

        @Override
        protected Bitmap doInBackground(String... strings) {
            Log.e("zzz", "ImageTask--doInBackground");
            String url = strings[0];
            Bitmap bitmap = null;
            URLConnection connection = null;
            InputStream is = null;
            BufferedInputStream bis = null;
            try {
                Thread.sleep(3000);
                connection = new URL(url).openConnection();
                is = connection.getInputStream();
                bis = new BufferedInputStream(is);
                bitmap = BitmapFactory.decodeStream(bis);
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                try {
                    is.close();
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //返回bitmap对象
            return bitmap;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            Log.e("zzz", "ImageTask--onPostExecute");
            Message message = mHandler2.obtainMessage();
            message.sendToTarget();
            if(bitmap != null){
                mImageView.setImageBitmap(bitmap);
                mProgressBar.setVisibility(View.GONE);
                mImageView.setVisibility(View.VISIBLE);
            }
        }
    }

3、继承AsyncTask时三个参数

1)、第一个参数是传递给doInBackground方法(参数列表);这里传入的是图片的URL,即String类型

2)、第二个参数是进度条参数,在后台进行任务操作时,需要在当前界面显示进度;这里传入的是Void类型,不需要显示进度

3)、第三个参数是doInBackground执行完以后返回的类型,也就是传递给onPostExecute方法参数,这里是Bitmap,

4、AsyncTask中的方法

1)、doInBackground(Params...)是继承AsyncTask必须实现的方法,该方法是在子线程中执行,可以执行耗时操作,接收第一个参数的泛型,执行的结果返回给onPostExecute方法参数,另外在doInBackground调用publishProgress(第二个参数泛型),可以更新操作进度;

2)、onPreExecute()是在执行耗时操作(doInBackground)之前调用,可以显示UI提示,比如加载对话框;

3)、onPostExecute(Result) 在doInBackground方法执行完返回结果会调用,返回的结果作为数据传递给该方法的参数,可以做一些UI操作,比如关闭对话框,任务操作的结果显示;

4)、onProgressUpdate(Progress..)当在后台任务方法doInBackground方法中diao调用了publishProgress这个方法,则hui 调用该方法,参数是publishProgress中传递过来的数据,可以刷新UI进度显示,

5、在Async中模拟进度显示,代码如下

public class ProgressBarTest extends AppCompatActivity {
    private ProgressBar mProgressBar;
    private ProgressBarTask mTask;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.progressbar_activty);
        mProgressBar = findViewById(R.id.progress_bar);
        mTask = new ProgressBarTask();
        mTask.execute();
    }

    @Override
    protected void onStop() {
        super.onStop();
        //将AsyncTask线程标记为取消状态
        if(mTask != null && mTask.getStatus() == AsyncTask.Status.RUNNING){
            //发送一请求,但并不是真正的取消线程,线程仍在执行,相当于一信号量
            mTask.cancel(true);
        }
    }

    /**
     * 三个参数,第一个参数是doInBackground方法中的参数,
     * 第二个参数是进度条中的参数
     * 第三个参数是onPostExecute方法中的参数,是由doInBackground方法执行完返回的
     */
    class ProgressBarTask extends AsyncTask<Void,Integer,Void>{

        @Override
        protected Void doInBackground(Void... voids) {
            for(int i = 0; i < 100; i++){
                if (isCancelled()){
                    break;
                }
                //进度传递
                publishProgress(i);
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            if(isCancelled()){
                return;
            }
            mProgressBar.setProgress(values[0]);
        }
    }
}

注意☆☆☆☆☆:会出现一个问题,当进入该界面,模拟进度显示正常,然后退出,再进入,发现进度显示没有刷新,为什么会这样?

mTask.execute();这是前一个线程没有执行完,后一个线程在等待前一个执行后才会执行,其内部是相当于单线程操作,知道原因了,怎么解决?

将AsyncTask与Activity或者Fragment的生命周期绑在一起,调用AsyncTask的quxi取消方法,如在Activity中的onPause()方法这么操作

if(mTask != null && mTask.getStatus() == AsyncTask.Status.RUNNING){
            //发送一请求,但并不是真正的取消线程,线程仍在执行,相当于一信号量
            mTask.cancel(true);
        }

重新运行,发现依旧是上述现象,第一次执行进度更新,退出,再进入进度又没有刷新,发现mTask.cancel(true);只是将该线程标记为取消,而没有真正取消,线程依旧还在执行,在AsyncTask中的doInBackground方法进行如下判断

if (isCancelled()){
                    break;
                }

这样线程就会执行中断,执行其他的线程,或者如果觉得这样操作太麻烦,可以改调用方式如下:

//        mTask.execute();
        mTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

这样也有一个问题就是当线程数达到核心线程数时,会进入队列等待,所以推荐使用第一种方法跟Activity或Fragment声明周期绑定的方式取消AsyncTask的任务,也可以使用自定义线程池的方式,

6、AsyncTask遇到的坑,

new ImageTask().execute(URL);
new ProgressBarTask().execute();

同时执行两AsyncTask时,发现必须等第一个AsyncTask的任务执行完以后,才会执行第二个AsyncTask

日志如下图:

E/zzz: ImageTask--doInBackground
E/zzz: ImageTask--onPostExecute
E/zzz: values0
E/zzz: values1
E/zzz: values2
E/zzz: values3
E/zzz: values4
E/zzz: values5
E/zzz: values6

解决办法

//new ProgressBarTask().execute();        
new ProgressBarTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

这样就nice,至于为啥会这样,请看下篇AsyncTask源码分析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值