温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

怎么构建AsyncTask

发布时间:2022-10-18 16:29:39 来源:亿速云 阅读:127 作者:iii 栏目:编程语言

本篇内容主要讲解“怎么构建AsyncTask”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么构建AsyncTask”吧!

为什么要使用异步任务?

  • Android 单线程模型,多线程的操作系统

  • 耗时操作放在非主线程中运行

AsyncTask 为何而生?

  • 子线程中更新UI

  • 封装简化异步操作

构建AsyncTask子类的参数

AsyncTask

构建AsyncTask子类的的回调方法

doInBackground(): 必须重写,异步执行后台线程将要完成的任务

onPreExecute(): 执行后台线程前被调用,通常用来做一些初始化操作

onPostExecute(): 当doInBackground() 方法完成后系统会自动调 用,并将doInBackground() 方法的返回值作为参数春递给onPostExecute()方法

onProgressUpdate(): 在doBackground() 方法中调用publishProgress()方法更新任务的执行进度后,就会调用该方法

接下来我们写个程序测试一下这些方法的执行顺序

首先创建一个AsyncTask的子类 MyAsyncTask

public class MyAsyncTask extends AsyncTask<Void, Void, Void>{

    String LOGCAT = "LOGCAT";

    @Override
    protected Void doInBackground(Void... params) {
        Log.d(LOGCAT, "doInBackground------------");
        System.out.println("doInBackground------------");
        return null;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        Log.d(LOGCAT, "onPreExecute");

    }

    @Override
    protected void onPostExecute(Void result) {
        super.onPostExecute(result);
        Log.d(LOGCAT, "onPostExecute");

    }

    @Override
    protected void onProgressUpdate(Void... values) {
        super.onProgressUpdate(values);
        Log.d(LOGCAT, "onProgressUpdate");

    }

}

在 MainActivity 中进行测试

public class MainActivity extends Activity

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

        MyAsyncTask asyncTask = new

在模拟器上部署运行之后,查看Logcat 可以看到下面的日志

怎么构建AsyncTask

从日志中可以看到,几个方法的执行顺序依次为 : onPreExecute –>doInBackground –>onPostExecute

然后我们在doInBackground 方法中添加这句代码 publishProgress();

@Override
    protected Void doInBackground(Void... params) {
        Log.d(LOGCAT, "doInBackground------------");

        //调用该方法后,会执行 onPostExecute() 方法
        publishProgress();

        return null;
    }

再次运行,观察logcat 输出,可看到在 doInBackground() 方法中执行了 publishProgress()方法后会调用 onProgressUpdate() 方法,顾名思义就是更新进度条的方法

怎么构建AsyncTask

下面我们来看一个典型的异步操作的例子,网络操作,从 Android4.0 之后,网络操作就严禁被放入到主线程中执行.下面是一个采用在异步线程处理下载图像
在UI线程设置图像的例子

布局界面代码比较简单,如下

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    <ImageView
        android:id="@+id/iv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"

    <ProgressBar
        android:id="@+id/pb"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:visibility="gone"

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:onClick="loadImage"
        android:text="下载图片"

</RelativeLayout>

MainActivity代码如下

public class MainActivity extends Activity

    private ImageView image;// 要展示的图片
    private ProgressBar pb;// 进度条
    // 要加载的图片的url
    String imageUrl = "https://www.baidu.com/img/2016_10_09logo_61d59f1e74db0be41ffe1d31fb8edef3.png";

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

        image = (ImageView) findViewById(R.id.iv);
        pb = (ProgressBar) findViewById(R.id.pb);

    }

    // 下载按钮的点击事件
    public void loadImage(View view) {

        AsyncTaskTest asyncTaskTest = new AsyncTaskTest();
        // execute()方法接受一个可变长数组的参数,可在 doInBackground()方法中获取
        asyncTaskTest.execute(imageUrl);

    }

    class AsyncTaskTest extends AsyncTask<String, Void, Bitmap> {

        Bitmap bitmap;

        // 下载开始前的一些初始化操作
        @Override
        protected void onPreExecute() {
            // TODO Auto-generated method stub
            super.onPreExecute();
            pb.setVisibility(View.VISIBLE);// 在下载之前将 Progress 显示出来
        }

        // 在此方法中进行网络耗时操作,下载完成后会执行 onPostExecute 方法,并把返回值传递给它
        @Override
        protected Bitmap doInBackground(String... params) {

            // 获取传递进来的参数
            String url = params[0];
            Bitmap btm = null;
            URLConnection connection;
            InputStream is;

            try {
                connection = new URL(url).openConnection();
                is = connection.getInputStream();
                BufferedInputStream bis = new BufferedInputStream(is);
                // 通过 BitmapFactory.decodeStream 方法吧输入流转换为 bitmap 对象
                bitmap = BitmapFactory.decodeStream(bis);

                is.close();
                bis.close();

            } catch (MalformedURLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            // 为了看清楚进度条,人为加一个延时操作,便于观察
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            return bitmap;
        }

        // doInBackground()方法执行完毕后会自动调用此方法, 此方法的参数是 doInBackground() 方法的返回值.
        @Override
        protected void onPostExecute(Bitmap result) {
            // TODO Auto-generated method stub
            super.onPostExecute(result);
            pb.setVisibility(View.GONE);// 隐藏进度条
            image.setImageBitmap(result);// 显示下载的网络图片

上面代码注释很详细,不再多做解释,只要搞懂了 AsyncTask 的几个方法的作用于执行周期,上面的代码很容易理解.

下面我们再通过一个模拟进度条的小例子,进一步认识AsyncTask 异步任务的用法

布局界面很简单,如下

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    <ProgressBar
        android:id="@+id/pb"
        android:padding="10dp"
        
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"

    <TextView
        android:id="@+id/tv_show"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/pb"
        android:layout_centerHorizontal="true"
        android:text="0%"
        android:textAppearance="?android:attr/textAppearanceSmall"

</RelativeLayout>

Activity 代码也很简单

public class progressBarTest extends Activity

    private ProgressBar pb;
    private TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.pro);
        pb = (ProgressBar) findViewById(R.id.pb);
        tv = (TextView) findViewById(R.id.tv_show);

        MyAsyncTask myAsyncTask = new MyAsyncTask();
        myAsyncTask.execute();

    }

    class MyAsyncTask extends AsyncTask<Void, Integer, Void> {

        @Override
        protected Void doInBackground(Void... params) {

            //模拟进度的更新
            for (int i = 0; i <= 100; i++) {
                // 更新进度条,重写 onProgressUpdate()方法,参数为 publishProgress(i)的参数
                publishProgress(i);// 此方法传入的参数就是 AsyncTask<Void, Integer,
                                    // Void>的第二个指定的参数类型

                // 睡眠200毫秒
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }

            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);

            // 更新显示数据
            tv.setText(values[0] + "%");

            // 更新进度条
            pb.setProgress(values[0]);// 水平进度条的进度为百分制

是不是很简单,但是不要高兴太早,对于这个程序,当我们点击下载,然后点击返回,然后再点击下载,进度条居然等了好久才开始更新

这是为啥呢?

其实AsyncTask 底层是通过线程池进行作用的,当一个线程没有作用完毕的时候,其它线程即必须进入线程池进行等待,等到前面的线程完事后,才会轮到自己执行,所以,当我们返回再次进入的时候,因为前一个线程正在执行更新进度条操作,所以当前线程必须等待前一个AsyncTask执行完毕后自己才可以执行.

那么如何解决这个问题呢?

其实很简单,AsyncTask 框架已经为我们考虑到了这个问题,我们可以通过 cancel() 方法来取消掉一个AsyncTask开启的一个异步任务.此方法接受一个布尔值的参数,

我们要做的很简单,重写Activity的 onPause() 方法,把AsyncTask的声明周期和Activity绑定到一起. 并且在 doInBackground() 方法中做异步判断.代码如下

@Override
        protected Void doInBackground(Void... params) {

            // 模拟进度的更新
            for (int i = 0; i <= 100; i++) {
                // 当收到取消请求时,不要在更新进度条,直接break结束for循环
                if (isCancelled()) {
                    break;

                }

                // 更新进度条,重写 onProgressUpdate()方法,参数为 publishProgress(i)的参数
                publishProgress(i);// 此方法传入的参数就是 AsyncTask<Void, Integer,
                                    // Void>的第二个指定的参数类型

                // 睡眠200毫秒
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }

            return null;
        }

并且在 onProgressUpdate () 方法中也做同样处理

@Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);

            // 当收到取消请求时,不要在更新进度条,直接return结束
            if (isCancelled()) {
                return;
            }

            // 更新显示数据
            tv.setText(values[0] + "%");

            // 更新进度条
            pb.setProgress(values[0]);// 水平进度条的进度为百分制

好了一切都做完了,我们再次运行程序可以看到

这里有一个注意事项,是关于AsyncTask 的 cancel(true);方法.其实当我们调用了 AsyncTask的cancel(true)方法时,并不会中断当前的线程,有人对此做出的解释是

AsyncTask不会不考虑结果而直接结束一个线程。调用cancel()其实是给AsyncTask设置一个”canceled”状态。这取决于你去检查AsyncTask是否已经取消,之后决定是否终止你的操作。对于mayInterruptIfRunning——它所作的只是向运行中的线程发出interrupt()调用。在这种情况下,你的线程是不可中断的,也就不会终止该线程。

说的不是很清楚,我们可以查看 cancel()方法的源代码

public boolean cancel(boolean mayInterruptIfRunning) {
        if (!(state == NEW &&
              U.compareAndSwapInt(this, STATE, NEW,
                  mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
            return false;
        try {    // in case call to interrupt throws exception
            if (mayInterruptIfRunning) {
                try {
                    Thread t = runner;
                    if (t != null)
                        t.interrupt();
                } finally { // final state
                    U.putOrderedInt(this, STATE, INTERRUPTED);
                }
            }
        } finally {
            finishCompletion();
        }
        return true;
    }

可以看到,这里只是调用了该线程的 t.interrupt(); 方法.对java线程中断机制的理解在此就显得非常重要了:

Java的中断是一种协作机制。也就是说调用线程对象的interrupt方法并不一定就中断了正在运行的线程,它只是要求线程自己在合适的时机中断自己

所以我们要想完全停掉这个线程,最好的做法是通过isCanceled()方法.做出显影的判断

到此,相信大家对“怎么构建AsyncTask”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI