AsyncTask的理解和使用

首先,我们来和之前学过的Handler机制进行比较。

AsyncTask和Handler对比

一、AsyncTask实现的原理,和适用的优缺点

AsyncTask,是Android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.

使用的优点:
1、 简单,快捷

2、 过程可控

使用的缺点:
1、在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.

二、Handler异步实现的原理和适用的优缺点

在Handler 异步实现时,涉及到 Handler, Looper, Message,Thread四个对象,实现异步的流程是主线程启动Thread(子线程),Thread(子线程)运行并生成Message,Looper获取Message并传递给Handler,Handler逐个获取Looper中的Message,并进行UI变更。

使用的优点:
1、结构清晰,功能定义明确

2、对于多个后台任务时,简单,清晰

使用的缺点:
1、在单个后台异步处理时,显得代码过多,结构过于复杂(相对性)

AsyncTask介绍

线程分为主线程和子线程,主线程主要处理和界面相关的事情,而子线程往往用于执行耗时操作。我们今天所说的AsyncTask其实是一个轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程中更新UI。我们首先了解一下AsyncTask提供的四个核心方法,然后举一个小例子加深一下印象。

public abstract class AsyncTask<Params,Progress,Result>

AsyncTask定义了三种泛型类型 ParamsProgressResult
Params 启动任务执行的输入参数,比如HTTP请求的URL。
Progress 后台任务执行的百分比。
Result 后台执行任务最终返回的结果,比如String。

AsyncTask的四个核心方法:

1、onPreExecute(),在主线程中执行,在异步任务执行之前次方法会调用,一般用于做一些准备工作。

2、doInBackground(Params…params),此方法用于异步任务,params参数表示异步任务的输入参数,在此方法中可以通过publicProgress()方法来更新任务的进度,publicProgress方法会调用onProgressUpdate方法。另外此方法需要返回计算结果给onPostExecute方法。

3、onProgressUpdate(Progress…values),在主线程中执行,当后台任务发生变化时会调用次方法。

4、onPostExecute(Result result),在主线程中执行,在异步任务完成之后,此方法会被调用,其中,result参数是后台任务返回值,即doInBackground的返回值。

上面的几种方法,onPreExecute()先执行,接着是doInBackground,之后是onPostExecute方法。

Threading rules

Android API中的解释:

There are a few threading rules that must be followed for this class to work properly:

 1. The task instance must be created on the UI thread.

 2. execute(Params...) must be invoked on the UI thread.    

 3. Do not call onPreExecute(), onPostExecute(Result),
        doInBackground(Params...), onProgressUpdate(Progress...) manually.

 4. The task can be executed only once (an exception will be thrown if
        a second execution is attempted.)

翻译如下:
使用AsyncTask类,以下是几条必须遵守的准则:

1、Task的实例必须在UI thread中创建;

2、execute方法必须在UI thread中调用;

3、不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;

4、该task只能被执行一次,否则多次调用时将会出现异常;

AsyncTask的使用

先上两张图:
1、连接的 URL 引用的资源的内容长度可以获得时
这里写图片描述

2、连接的 URL 引用的资源的内容长度未知时
这里写图片描述

下面是一个使用AsyncTask的小demo,代码中有详细的注释

public class AsyncTaskActivity extends AppCompatActivity implements View.OnClickListener {
    Button sure, cancel;
    ProgressBar progressBar;
    TextView textView;
    final String TAG = "AsyncTaskTest";
    MyTask myTask;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_async_task);
        init();
    }

    private void init() {
        sure = (Button) findViewById(R.id.sure);
        cancel = (Button) findViewById(R.id.cancel);
        progressBar = (ProgressBar) findViewById(R.id.progressbar);
        textView = (TextView) findViewById(R.id.textview);
        sure.setOnClickListener(this);
        cancel.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.sure:
                //点击下载按钮开始下载
                myTask = new MyTask();
//              myTask.execute("http://www.tngou.net/api/drug/classify");//可以计算length长度的网址
                myTask.execute("http://www.baidu.com");//不可以计算length长度的网址
                sure.setEnabled(false);
                cancel.setEnabled(true);
                break;
            case R.id.cancel:
                //点击取消按钮取消下载
                myTask.cancel(true);
                break;
        }
    }

    public class MyTask extends AsyncTask<String, Integer, String> {


        //onPreExecute方法用于在执行后台任务前做一些UI操作
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            Log.e(TAG, "onPreExecute");
            textView.setText("Loading...");
            progressBar.setProgress(0);
        }

        //doInBackground方法内部执行后台任务,不可在此方法内修改UI
        @Override
        protected String doInBackground(String[] params) {
            Log.e(TAG, "doInBackground");
            try {
                URL url = new URL(params[0]);
                HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
                httpURLConnection.setRequestMethod("GET");
                httpURLConnection.connect();
                InputStream in = httpURLConnection.getInputStream();
                //此连接的 URL 引用的资源的内容长度,或者如果内容长度未知,则返回 -1.有些网站计算不出长度,则会返回-1,出现错误。
                int length = httpURLConnection.getContentLength();
                //如何url的长度已知,则是按照内容的读取比例进行显示progressbar。
                if (length != -1) {
                    byte[] bytes = new byte[1024];
                    int len = 0;
                    int total = 0;
                    //int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
                    //返回值:读入缓冲区的总字节数;如果因为已经到达流末尾而不再有数据可用,则返回 -1。
                    while ((len = in.read(bytes)) != -1) {
                        total += len;
                        publishProgress(((total * 100) / length));
                        Thread.sleep(1000);
                    }
                    String string = new String(bytes);
                    //关闭输入流,和httpUrlConnection连接
                    in.close();
                    httpURLConnection.disconnect();
                    return string;
                } else {
                    //如果未知,则按50 %,100 % 显示progressbar。
                    publishProgress(50);
                    BufferedReader bufferReader = new BufferedReader(new InputStreamReader(in));
                    String lines = null;
                    StringBuffer stringBuffer = new StringBuffer("");
                    while ((lines = bufferReader.readLine()) != null) {
                        stringBuffer.append(lines);
                    }
                    //关闭输入流,和httpUrlConnection连接
                    in.close();
                    httpURLConnection.disconnect();
                    Thread.sleep(1000);
                    publishProgress(100);
                    return stringBuffer.toString();
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return null;
        }

        //onProgressUpdate方法用于更新进度信息
        @Override
        protected void onProgressUpdate(Integer[] values) {
            super.onProgressUpdate(values);
            Log.e(TAG, "onProgressUpdate");
            progressBar.setProgress(values[0]);
            textView.setText("loading..." + values[0] + "%");
        }

        //onPostExecute方法用于在执行完后台任务后更新UI,显示结果
        @Override
        protected void onPostExecute(String o) {
            super.onPostExecute(o);
            Log.e(TAG, "onPostExecute");
            textView.setText(o);
            sure.setEnabled(true);
            cancel.setEnabled(false);
        }

        //onCancelled方法用于在取消执行中的任务时更改UI
        @Override
        protected void onCancelled() {
            super.onCancelled();
            Log.e(TAG, "onCancelled");
            textView.setText("cancel");
            progressBar.setProgress(0);
            sure.setEnabled(true);
            cancel.setEnabled(false);
        }
    }
}

其实AsyncTask类中就是使用的Handler机制来实现的,当单个后台异步处理时,使用AsyncTask较为方便,在使用多个异步操作和并需要进行UI变更时,选择Handler。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值