Android开发-AsyncTask异步下载

目录

1.同步与异步

1.同步

2.异步

2. AsyncTask

2.1 AsyncTask定义

2.2 AsyncTask目的

2.3 AsyncTask执行步骤方法       

2.4 注意事项


1.同步与异步

1.同步

2.异步

          顾名思义,异步就是UI主线程运行的时候,异步的完成一些操作。执行一个异步的任务在后台。我们可以将耗时的操作放在异步任务当中来执行,并随时将任务执行的结果返回给我们的UI线程来更新我们的UI控件。通过异步我们可以轻松的解决多线程之间的通信问题

        如果有多个任务执行的话,异步任务是按照顺序一个个执行的。

        在Android中实现异步任务机制有两种方式,Handler和AsyncTask

Handler

Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息

完成界面的更新,这种方式对于整个过程的控制比较精细,但也是有缺点的,例如代码相对臃肿

在多个任务同时执行时,不易对线程进行精确的控制

AsyncTask使创建异步任务变得更加简单,不再需要编写任务线程和Handler实例即可完成相同的任务。

 

2. AsyncTask

2.1 AsyncTask定义

         定义一个类来继承AsyncTask这个抽象类,并实现其唯一的一个 doInBackgroud 抽象方法。

public class DownloadAsyncTask extends AsyncTask<String,Integer,Boolean>{
    //在异步任务之前,在主线程中
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        //可操作UI
    }
    /**
     * @param strings:表示可变参数(传入的参数)
     * @return 结果
     */
    @Override
    protected Boolean doInBackground(String... strings) {
        return null;
    }
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        //收到进度结果,然后处理,在UI线程中
    }
    @Override
    protected void onPostExecute(Boolean aBoolean) {
        super.onPostExecute(aBoolean);
        //在主线程中,执行结果和处理
    }
    @Override
    protected void onCancelled() {
        super.onCancelled();
    }
    @Override
    protected void onCancelled(Boolean aBoolean) {
        super.onCancelled(aBoolean);
    }
}

         泛型参数详解:

Params这个泛型指定的是我们传递给异步任务执行时的参数的类型
Progress 这个泛型指定的是我们的异步任务在执行的时候将执行的任务进度返回给UI线程的参数的类型
Result这个泛型指定的异步任务执行完后返回给UI线程的结果的类型

           在特定场合下,并不是所有类型都被使用,如果没有被使用,可以用java.lang.Void类型代替

为什么我们的AsyncTask抽象类只有一个 doInBackground 的抽象方法呢

原因是,我们如果要做一个异步任务,我们必须要为其开辟一个新的Thread,

让其完成一些操作,而在完成这个异步任务时,我可能并不需要弹出要给

ProgressDialog,我并不需要随时更新我的ProgressDialog的进度条,

我也并不需要将结果更新给我们的UI界面,所以除了 doInBackground 方法之外的三个方法,都不是必须有的,因此我们必须要实现的方法是 doInBackground 方法。

2.2 AsyncTask目的

目的方便后台线程操作后更新UI。
实现Thread和Handler进行了封装。
实质Handler异步的消息处理机制,封装简化了异步操作。

2.3 AsyncTask执行步骤方法       

        步骤方法如下:

execute(Params... params)

执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行要在主线程

中执行。

onPreExecute()

是在主线程当中执行的,在execute(Params... params)被调用后立即执行,

做一些UI控件的初始化的操作,例如弹出要给ProgressDialog

doInBackground(Params... params)

在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收

输入参数和返回计算结果。Android操作系统会在后台的线程池当中开启一个

worker thread来执行我们的这个方法,所以这个方法是在worker thread当

中执行的,在执行过程中可以调用

publishProgress(Progress... values)来更新进度信息。

onProgressUpdate(Progress... values)

这个方法也是在UI线程当中执行的,我们在异步任务执行的时候,有时候

需要将执行的进度返回给我们的UI界面,例如下载一张网络图片,我们需要

时刻显示其下载的进度,就可以使用这个方法来更新我们的进度。这个方法在

调用之前,我们需要在 doInBackground 方法中调用一个

publishProgress(Progress) 的方法来将我们的进度时时刻刻传递给

onProgressUpdate 方法来更新

onPostExecute(Result result)

这个方法也是在主线程当中执行的。当后台操作结束时,此方法将会被调用,

将计算结果做为参数传递到此方法中,直接将结果显示到UI组件上。

onCancelled(Boolean aBoolean)

我们可以在任何时刻来取消我们的异步任务的执行,通过调用

onCancelled(boolean)方法,调用完这个方法后系统会随后调用 isCancelled()

方法并且返回true。如果调用了这个方法,那么在 doInBackgroud() 方法执行完之后,

就不会调用 onPostExecute() 方法了,取而代之的是调用 onCancelled() 方法。为了

确保Task已经被取消了,我们需要经常调用 isCancelled() 方法来判断,如果有必要的话。

onCancelled() 
泛型参数<Params,Progress,Result>
UI操作

onPreExecute

onPostExcute

后台线程操作doInBackground

输入

输出

Params

Result

进度条显示onProgressUpdate

2.4 注意事项

异步任务的实例必须在UI线程中创建。
execute(Params... params)方法必须在主线程中调用
不要手动调用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values),onPostExecute(Result result)这几个方法。
不能在doInBackground(Params... params)中更改UI组件的信息

AsyncTask任务只能被执行一次,如果执行第二次将会抛出异常

 

3.AsyncTask异步下载文件案例

3.1 未封装前

        (1)AndroidManifest.xml:申请权限

?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.administrator.asynctaskexample">
    <!-- 申请权限 -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <application
       ......
    </application>

</manifest>

        (2)MainActivity

/**
 * 1.网络上请求数据:申请网络权限,读写储存权限
 * 2.布局layout
 * 3.下载之前做什么  UI处理
 * 4.下载中做什么    数据树立
 * 5.下载后做什么    UI处理
 */
public class MainActivity extends AppCompatActivity {
    private final int INIT_PROGRESS = 0;
    private final String APK_URL = "http://download.sj.qq.com/upload/connAssitantDownload/upload/MobileAssistant_1.apk";
    private final String FILE_NAME = "example.apk";
    private Button downloadStartBtn;
    private TextView downloadText;
    private ProgressBar downloadProgress;
    private String filePath;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化视图
        initView();
        //设置按钮点击监听
        setListener();
        //初始化数据
        setData();
    }
    //初始化视图
    private void initView() {
        downloadStartBtn = findViewById(R.id.download_start);
        downloadText = findViewById(R.id.download_text);
        downloadProgress = findViewById(R.id.download_progressbar);
    }
    //设置按钮点击监听
    private void setListener() {
        downloadStartBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                DownloadAsyncTask asyncTask = new DownloadAsyncTask();
                //传入URL
                asyncTask.execute(APK_URL);
            }
        });
    }
    //初始化数据
    private void setData() {
        downloadStartBtn.setText(R.string.click_download);
        downloadText.setText(R.string.ready_download);
        downloadProgress.setProgress(INIT_PROGRESS);
    }
    /**
     * 定义类继承AsyncTask
     * String:入参
     * Integer:进度值
     * Boolean:结果
     */
    public class DownloadAsyncTask extends AsyncTask<String,Integer,Boolean>{
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            downloadStartBtn.setText(R.string.downloading);
            downloadText.setText(R.string.downloading);
            downloadProgress.setProgress(INIT_PROGRESS);
        }
        @Override
        protected Boolean doInBackground(String... strings) {
            if(strings == null && strings.length <=0){
                return false;
            }
            String apkUrl = strings[0];
            try {              
                URL url = new URL(apkUrl);
                //构造链接,并打开
                URLConnection urlConnection = url.openConnection();
                InputStream inputStream = urlConnection.getInputStream();
                //获得下载内容的总长度
                int contentLength = urlConnection.getContentLength();
                //准备放置下载文件的路径目录
                filePath = Environment.getExternalStorageDirectory()
                        + File.separator + FILE_NAME;
                //对下载地址进行处理
                File apkFile = new File(filePath);
                if(apkFile.exists()){
                    if(apkFile.delete()){
                        return false;
                    }                  
                }
                //当前文件内容已经下载大小长度
                int downloadSize = 0;
                byte[] bytes = new byte[1024];
                int length;
                //创建一个输入管道
                OutputStream outputStream = new FileOutputStream(filePath);
                while ((length = inputStream.read(bytes)) != -1){
                    outputStream.write(bytes,0,length);
                    downloadSize += length;
                    //发送下载进度值
                    publishProgress(downloadSize * 100/contentLength);
                }
                inputStream.close();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
                return false;
            }
            return true;
        }
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            if(values != null && values.length > 0) {
                downloadProgress.setProgress(values[0]);
            }
        }
        @Override
        protected void onPostExecute(Boolean aBoolean) {
            super.onPostExecute(aBoolean);
            downloadStartBtn.setText("下载完成");
            downloadText.setText(aBoolean == true? "下载完成"+filePath:"下载失败");
        }

    }
}

 

3.2 封装后

           (1)定义OnDownloadListener接口:

public interface OnDownloadListener{
    void onStart();
    void onSuccess(int code, File file);
    void onFail(int code,File file,String failMessage);
    void onProgress(int progress);
}

         (2)定义DownloadHelper类:里面实现异步下载方法

public class DownloadHelper {
    //定义开始执行下载任务方法:传入对应参数
    public static void download(String url, String filePath, OnDownloadListener listener){
        DownloadAsyncTask downloadAsyncTask = new DownloadAsyncTask(url,filePath,listener);
    }
    /**
     * 定义类继承AsyncTask
     * String:入参
     * Integer:进度值
     * Boolean:结果
     */
    public static class DownloadAsyncTask extends AsyncTask<String,Integer,Boolean> {
        String url;
        String filePath;
        OnDownloadListener listener;
        public DownloadAsyncTask(String url, String filePath, OnDownloadListener listener) {
            this.url = url;
            this.filePath = filePath;
            this.listener = listener;
        }
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            if(listener != null){
                listener.onStart();
            }
        }
        @Override
        protected Boolean doInBackground(String... strings) {
            String apkUrl = url;
            try {
                URL url = new URL(apkUrl);
                //构造链接,并打开
                URLConnection urlConnection = url.openConnection();
                InputStream inputStream = urlConnection.getInputStream();
                //获得下载内容的总长度
                int contentLength = urlConnection.getContentLength();
                //对下载地址进行处理
                File apkFile = new File(filePath);
                if(apkFile.exists()){
                    if(apkFile.delete()){
                        if(listener != null){
                            listener.onFail(-1,apkFile,"文件删除失败");
                        }
                        return false;
                    }
                }
                //当前文件内容已经下载大小长度
                int downloadSize = 0;
                byte[] bytes = new byte[1024];
                int length;
                //创建一个输入管道
                OutputStream outputStream = new FileOutputStream(filePath);
                while ((length = inputStream.read(bytes)) != -1){
                    outputStream.write(bytes,0,length);
                    downloadSize += length;
                    //发送下载进度值
                    publishProgress(downloadSize * 100/contentLength);
                }
                inputStream.close();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
                if(listener != null){
                    listener.onFail(-2,new File(filePath),e.getMessage());
                }
                return false;
            }
            if(listener != null){
                listener.onSuccess(0,new File(filePath));
            }
            return true;
        }
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            if(listener != null) {
               listener.onProgress(values[0]);
            }
        }
        @Override
        protected void onPostExecute(Boolean aBoolean) {
            super.onPostExecute(aBoolean);
            if(listener != null){
                if(aBoolean){
                    listener.onSuccess(0,new File(filePath));
                }else{
                    listener.onFail(-1,new File(filePath),"下载失败");
                }
            }
        }
    }
}

          (3)MainActivity中:创建Download对象,执行开始下载方法。

public class MainActivity extends AppCompatActivity {
    private final int INIT_PROGRESS = 0;
    private final String APK_URL = "http://download.sj.qq.com/upload/connAssitantDownload/upload/MobileAssistant_1.apk";
    private final String FILE_NAME = "example.apk";
    private Button downloadStartBtn;
    private TextView downloadText;
    private ProgressBar downloadProgress;
    private  String filePath = Environment.getExternalStorageDirectory() + File.separator + FILE_NAME;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化视图
        initView();
        //初始化数据
        setData();
        //设置按钮点击监听
        setListener();

    }
    //初始化视图
    private void initView() {
        downloadStartBtn = findViewById(R.id.download_start);
        downloadText = findViewById(R.id.download_text);
        downloadProgress = findViewById(R.id.download_progressbar);
    }
    //设置按钮点击监听
    private void setListener() {
        downloadStartBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //setData();
                DownloadHelper.download(APK_URL,filePath, new OnDownloadListener() {
                    @Override
                    public void onStart() {
                        Log.i("MainActivity", "开始下载");
                        downloadStartBtn.setText("下载中....");
                    }
                    @Override
                    public void onSuccess(int code, File file) {
                        if(code == 0){
                            Log.i("MainActivity", "下载成功:"+file.getAbsolutePath());
                        }
                    }
                    @Override
                    public void onFail(int code, File file, String failMessage) {
                        if(code == -1){
                            Log.i("MainActivity", "下载失败:"+failMessage);
                        }
                    }
                    @Override
                    public void onProgress(int progress) {
                        downloadProgress.setProgress(progress);
                    }
                });
            }
        });
    }
    //初始化数据
    private void setData() {
        downloadStartBtn.setText(R.string.click_download);
        downloadText.setText(R.string.ready_download);
        downloadProgress.setProgress(INIT_PROGRESS);
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luckyliuqs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值