会飞的鱼

奇乐云
首页 » Android » AsyncTask模拟进度下载以及AsyncTask取消

AsyncTask模拟进度下载以及AsyncTask取消


AsyncTask

1.什么是AsyncTask

1.AsyncTask是Android提供的轻量级( 实现代码量少) 的异步类。 
2.为了降低异步通信的开发难度,提供了AsyncTask。 
3.AsyncTask直接继承于0bject类,位于android.os包中。 
4.使用AsyncTask可以忽略Looper、MessageQueue、Handler 
等复杂对象,更便捷的完成异步耗时操作。 
fe1f4dad9d8ce852f9da06f0c8bc927c_70.jpg

2.为什么要学习AsyncTask

1.Android中实现消息通信,需要掌握主线程的刷新机制,Thread,Looper,MessageQueue.Handler. 
Message等知识。 
2.当执行一个较为简单的耗时操作时(如:倒计时,下载等),AndroidSDK提供了一种轻量级的消息通信方法-AsyncTask。 
3.只需掌握几个方法即可完成消息通信,降低了消息通信难度。

如何使用AsyncTask

1.新建内部类继承AsyncTask 。 
2.定义Asyn cTask的三种泛型参数。 
3.重写dolnBackground抽象方法。 
4.重写onPreExecute方法。 
5.重写onProgressUpdate方法。 
6.重写onPostExecute方法。 
7.在需要启动的地方调用execute方法。

AsyncTask的泛型参数

Params: 启动任务执行的输入参数。 
Progress: 后台任务执行的百分比。 
Result: 后台执行任务最终返回的结果。

AsyncTask常用方法

onPreExecute方法:

1.异步任务开始执行时,系统最先调用此方法。 
2.此方法运行在主线程中,可以对控件进行初始化等操作。

dolnBackground方法:

1.执行完onPreExecute方法后,系统执行此方法 
2.此方法运行在子线程中,比较耗时的操作放在此方法中执行。

onProgressUpdate方法:

1.显示当前进度,适用于下载或扫描这类需要实时显示进度的需求。 
2.此方法运行在主线程中,可以修改控件状态,例如: 显示百分比。 
3.触发此方法,需要在dolnBackground中使用publishProgress方法。

publishProgress方法:

1.在doInBackground中使用。 
2.用于触发onProgressUpdate方法。

on PostExecute方法:

1.当异步任务执行完成后,系统会调用此方法。 
2.此方法运行在主线程中,可以修改控件状态,例如: 下载完成。

通过AsyncTask模拟下载进度,以及通过cancel进行状态标记,那么可以在AsyncTask中监测这样的改变,一旦当前状态改为cancelled,我们就要跳出循环,立刻结束当前操作,从而结束整个线程逻辑。

首先是一个按钮的布局文件

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/bt1"
        android:layout_gravity="center_vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="下载"/>
</LinearLayout>

4cb65cd7972ab4c205906f71cf43c792_70.png
在Activity实例化按钮并添加监听事件

MainActivity.java

package com.rui.pgasynctask;
 
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.View;
import android.widget.Button;
 
/**
 * Created by qqazl001 on 2018/3/29.
 */
 
public class MainActivity2 extends Activity{
    private Button bt;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bt = (Button)findViewById(R.id.bt1);
        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //跳转下载Activity
                Intent intent = new Intent(MainActivity.this,MainActivity.class);
                startActivity(intent);
            }
        });
    }
}

添加一个布局文件,存放一个ProgressBar和TextView,显示进度和数值

activity2_main.xml

ProgressBar中设置为水平方向显示进度条 style="?android:attr/progressBarStyleHorizontal"

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
   <ProgressBar
       android:id="@+id/pb"
       style="?android:attr/progressBarStyleHorizontal"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_centerVertical="true"
       android:max="100"
       />
   <TextView
       android:id="@+id/tv1"
       android:layout_below="@+id/pb"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:textSize="30sp"/>
</RelativeLayout>

接下里了就是重头戏了

MainActivity.java

package com.rui.pgasynctask;
 
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ProgressBar;
import android.widget.TextView;
 
public class MainActivity extends AppCompatActivity {
    //声明ProgressDialog,TextView,MyAsyncTask
    private ProgressBar pb;
    private TextView tv1;
    private MyAsyncTask mtask;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        //实例化pd和tv1
        pb = (ProgressBar)findViewById(R.id.pb);
        tv1 = (TextView)findViewById(R.id.tv1);
        //实例化内部类MyAsyncTask
        mtask = new MyAsyncTask();
        //启动异步加载
        mtask.execute();
    }
    //当Activity失去焦点的时候
    @Override
    protected void onPause() {
        //判断MyAsyncTask不为空,且状态是运行状态
        if(mtask!=null && mtask.getStatus() == AsyncTask.Status.RUNNING ){
            //AsyncTask标记为cancel状态,并不是真正地取消线程的执行。
            mtask.cancel(true);
        }
        super.onPause();
    }
    //创建一个异步加载内部类,继承AsyncTask
    public class MyAsyncTask extends AsyncTask<Void,Integer,Void>{
        //实现doInBackground方法
        @Override
        protected Void doInBackground(Void... voids) {
            //循环产生下载的效果
            for(int i=0;i<=100;i++){
                //判断是否被标记为true
                if(isCancelled()){
                    //被标记则中断循环
                    break;
                }
                //调用周期的下一个方法,传值进度
                publishProgress(i);
                //睡眠50毫秒,模拟下载
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
 
        //展示进度
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            //判断是否被标记,如果被标记则终止
            if(isCancelled()){
                return;
            }
            //进度赋值给Pd
            pb.setProgress(values[0]);
            //tv1显示进度
            tv1.setText("正在下载:"+values[0]+"%");
        }
    }
}

不等进度条满就后退再执行,会发现后面执行的进度条迟迟没有响应,为什么呢?这并非bug,而是 AsyncTask 所实行的一种机制。AsyncTask的底层是通过线程池去作用的。当一个线程没有完成的时候,后面的线程就无法开始。我们上一节课用了for()循环去执行进度条 的更新操作,必须等到for()循环结束后才会执行下一个Task。

79f0037bd1a6a88140853086182f73aa_20180329112026657.gif
令AsyncTask的生命周期和Activity或者Fragment的生命周期保持一致就可以了。
那要如何快速停止线程呢?
1. 在onPause()中标记取消状态:mTask.cancel(true);既然我们已经标记了cancel状态,那么可以在AsyncTask中监测这样的改变,一旦当前状态改为cancelled,我们就要跳出循环,立刻结束当前操作,从而结束整个线程逻辑。
2. 在doInBackground()方法的for()循环内添加isCancelled()对线程的状态进行判断:if(isCancelled())break;
3. 同理,在onProgressUpdate()方法中也做类似的处理:if(isCancelled())return;通过如上操作,我们就能快速停止当前线程,将处理权交给下一个AsyncTask。
79011b2c3198bfc21f8a21f5016d1722_20180329112159390.gif

文章如无特别注明均为原创! 作者: 奇乐云, 转载或复制请以 超链接形式 并注明出处 奇乐云-建站源码,网络技术,免空免域,模板主题,电脑软件,超级博客
原文地址《 AsyncTask模拟进度下载以及AsyncTask取消》发布于2019-3-4

分享到:
打赏

评论

游客

切换注册

登录

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录
切换登录

注册