必威体育Betway必威体育官网
当前位置:首页 > IT技术

多线程编程——AsyncTask

时间:2019-10-02 06:15:34来源:IT技术作者:seo实验室小编阅读:73次「手机版」
 

asynctask

接上文

https://blog.csdn.net/nishigesb123/article/details/89134696


AsyncTask

概述

上文提到了handler,可以解决线程之间的消息传递问题。不过Android其实提供了一个更加轻量级的工具,也可以完成类似的工作,那就是AsyncTask。

下面是API中的描述:

AsyncTask enables proper and easy use of the UI thread. This class allows you to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.

AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as ExecutorThreadPoolExecutor and FutureTask.

An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 3 generic types, called paramsprogress and Result, and 4 steps, called onPreExecutedoInBackground,onProgressUpdate and onPostExecute.

  • 它使创建需要与用户界面交互的长时间运行的任务变得更简单。
  • 它是轻量级的,适用于简单的异步处理,不需要借助线程和Handler即可实现。
  • AsyncTask是抽象类,定义了三种泛型类型Params, Progress和Result。
  1. Params, the type of the parameters sent to the task upon execution.
  2. Progress, the type of the progress units published during the background computation.
  3. Result, the type of the result of the background computation.

Params——启动任务执行的输入参数,比如,HTTP 请求的URL。

Progress——后台任务执行的百分比。

Result——后台执行任务最终返回的结果,比如String。

执行步骤

在API中,AsyncTask被划分为4个执行步骤,每一步对应一个回调方法。

步骤的具体内容将会在接下来的部分叙述,当然也可以直接阅读下面的API文档。

When an asynchronous task is executed, the task goes through 4 steps:

  1. onPreExecute(), invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
  2. doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in theonProgressUpdate(Progress...) step.
  3. onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
  4. onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.

 准备工作

一个Button

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="AsyncTask"
        android:onClick="AsyncTask"
        android:id="@+id/AsyncTask"
        APP:layout_constraintTop_toTopOf="parent"/>

还需要一个TextView,在代码中并注册,细节不表。 

定义一个静态类,继承AsyncTask。

    //定义一个类继承AsyncTask AsyncTask<Params, Progress和Result>
    private static class MyAsyncTask extends AsyncTask<String,integer,String> {
        @Override
        protected String doInBackground(String... strings) {
            return null;
        }
    }

onPreExecute

被UIThread调用,该方法用来做一些准备工作,如在界面上显示一个进度条

        //执行任务之前触发的事件方法,在该方法中做一些初始化工作
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            System.out.println("onPreExecute");
            activity.textView.setText("开始执行任务...");
        }

dolnBackground

在onPreExecute之后执行,运行在后台线程中。

负责执行耗时工作,可以通过调用publishProgress方法来更新实时任务进度。

        //执行后台任务的方法,类似于线程,注意不能再该方法中访问UI组件,返回值由Result决定
        @Override
        protected String doInBackground(String... strings) {
            for (int i=0;i<10;i++){
                System.out.println(i);
                publishProgress(i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printstacktrace();
                }
            }
            //写的是String,所以返回一个String
            return "success";
        }

onProgressUpdate

在publishProgress方法被调用后,UIThread将调用该方法在界面上展示任务的进展情况,如通过一个进度条进行展示。

        //更新进度值
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            activity.textView.setText("当前的值为:"+values[0]);
        }

onPostExecute

在doInBackground执行完成后,onPostExecute方法将被UIThread调用,后台的计算结果将通过该方法传递到UIThread。

        //当doInBackground方法返回后被调用,最后处理结果
        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            activity.textView.setText(s);
        }

完整代码

package com.example.a4_9asynctask;

import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.Textview);
    }

    public void AsyncTask(View v){
        new MyAsyncTask(this).execute();
    }
    //通过一个AsyncTask实现一个异步任务

    //定义一个类继承AsyncTask AsyncTask<Params, Progress和Result>
    private static class MyAsyncTask extends AsyncTask<String,Integer,String> {
        //传一个activity
        private  MainActivity activity;
        public MyAsyncTask(MainActivity activity){
            this.activity = activity;
        }
        //执行任务之前触发的事件方法,在该方法中做一些初始化工作
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            System.out.println("onPreExecute");
            activity.textView.setText("开始执行任务...");
        }
        //执行后台任务的方法,类似于线程,注意不能再该方法中访问UI组件,返回值由Result决定
        @Override
        protected String doInBackground(String... strings) {
            for (int i=0;i<10;i++){
                System.out.println(i);
                publishProgress(i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //写的是String,所以返回一个String
            return "success";
        }

        //更新进度值
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            activity.textView.setText("当前的值为:"+values[0]);
        }

        //当doInBackground方法返回后被调用,最后处理结果
        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            activity.textView.setText(s);
        }
    }
}

开始执行后数字会不断变大,到9后变为success 

 

模拟下载

准备

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="下载"
        android:onClick="Download"
        android:id="@+id/Download"
        app:layout_constraintTop_toBottomOf="@id/Textview" />

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="33dp"
        app:layout_constraintTop_toBottomOf="@+id/Download"
         />

用到网络权限和写SD卡权限

<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

代码

package com.example.a4_9asynctask;

import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;

import java.io.Fileoutputstream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class MainActivity extends AppCompatActivity {

    private TextView textView;
    private ProgressBar progressBar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.Textview);
        progressBar = findViewById(R.id.progressBar);
    }

    public void Download(View v){
        new DownloadAsyncTask(this).execute("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1554803992281&di=f90bca0cd2a63a46c394337f9d74c54d&imgtype=0&src=http%3A%2F%2Ftaobao.90sheji.com%2F58pic%2F15%2F44%2F87%2F54k58PICWTM.png");
    }
    private static class DownloadAsyncTask extends AsyncTask<String, Integer, Integer> {
        private MainActivity activity;

        public DownloadAsyncTask(MainActivity activity) {
            this.activity = activity;
        }
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            activity.progressBar.setProgress(0);
        }

        @Override
        protected Integer doInBackground(String... strings) {
            String s = strings[0];
            try {
                //通过URL类
                URL url = new URL(s);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                //得到文件总大小
                int size = conn.getContentLength();
                //第一参数为标记,0表示需要更新最大进度值,1表示更新当前下载的进度值
                publishProgress(0, size);
                //流...
                byte[] bytes = new byte[20];
                int len = -1;
                //读取
                InputStream in = conn.getInputStream();
                //..
                FileOutputStream out = new FileOutputStream("/sdcard/" + system.currenttimemillis() + ".png");
                while ((len = in.read(bytes)) != -1) {
                    out.write(bytes, 0, len);
                    //通过publishProgress更新进度
                    publishProgress(1, len);
                    out.flush();
                }
                out.close();
                in.close();
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return 200;
        }
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            switch (values[0]) {
                case 0:
                    //0表示需要更新最大进度值
                    activity.progressBar.setMax(values[1]);
                    break;
                case 1:
                    //1表示更新当前下载的进度值
                    activity.progressBar.incrementProgressBy(values[1]);
                    break;
            }
        }
        @Override
        protected void onPostExecute(Integer integer) {
            super.onPostExecute(integer);
            if (integer == 200) {
                activity.textView.setText("下载完成");
            }
        }
    }

    /********************到这里为止*********************/

    public void AsyncTask(View v){
        new MyAsyncTask(this).execute();
    }
    //通过一个AsyncTask实现一个异步任务

    //定义一个类继承AsyncTask AsyncTask<Params, Progress和Result>
    private static class MyAsyncTask extends AsyncTask<String,Integer,String> {
        //传一个activity
        private  MainActivity activity;
        public MyAsyncTask(MainActivity activity){
            this.activity = activity;
        }
        //执行任务之前触发的事件方法,在该方法中做一些初始化工作
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            System.out.println("onPreExecute");
            activity.textView.setText("开始执行任务...");
        }
        //执行后台任务的方法,类似于线程,注意不能再该方法中访问UI组件,返回值由Result决定
        @Override
        protected String doInBackground(String... strings) {
            for (int i=0;i<10;i++){
                System.out.println(i);
                publishProgress(i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //写的是String,所以返回一个String
            return "success";
        }

        //更新进度值
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            activity.textView.setText("当前的值为:"+values[0]);
        }

        //当doInBackground方法返回后被调用,最后处理结果
        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            activity.textView.setText(s);
        }
    }
}

小结

  1. AsyncTask的实例必须在UI Tread中创建。
  2. execute方法必须在UI Tread中调用。
  3. 不要手动去调用onPreExecute()、doInBackground(Params…)、onPostExecute(Result)、onProgressUpdate(Progress…)等方法,由事件自动的来调用。
  4. AsyncTask只能被执行一次,否则多次调用时将会出现异常。
  5. AsyncTask不能完全取代线程,在一些逻辑较为复杂或者需要在后台反复执行的逻辑就可能仍旧需要线程去实现。

     

相关阅读

AsyncTask

参考:Android AsyncTask完全解析,带你从源码的角度彻底理解Android源码分析—带你认识不一样的AsyncTaskAsyncTask的缺陷和问题 译

asyncTask详解

https://blog.csdn.net/gdutxiaoxu/article/details/57409326 api AsyncTask是个抽象类,需要子类继承,然后调用execute()方法,继

分享到:

栏目导航

推荐阅读

热门阅读