栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

AsyncTask的基本使用

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

AsyncTask的基本使用

1. Thread 基本使用

Java 中可以使用 Thread 对象来处理异步逻辑:

Thread thread = new Thread(new Runnable() {
        @override
        public void run(){
            // logic code...
        }
    });
thread.start();

但是使用 Thread 时需要处理的逻辑比较复杂,比如:

  1. 线程的创建和释放;
  2. 线程的开启和停止;
  3. 线程池管理;

所以,类似于 iOS 中也一般不适用 NSThread,在 Android 中一般也不使用 Thread 对象来处理一步逻辑,因为封装度不够,实用性太差;

2. AsynTask

使用步骤:

  1. 创建一个类,继承自 AsyncTask;
  2. 设置 AsyncTask 的第一个参数,表示参数类型。不能使用 java 原始数据类型,比如 int、char,要使用对象类型,比如 String、Integer、model,当然也可以使用 Void 来表示无参数;
  3. 第二个参数表示进度,即向外界传递出去的数据类型,即 onProgressUpdate 方法中的入参类型;
  4. 第三个参数表示返回数据的类型;
  5. 创建并调用 execute(param)方法;

AsyncTask 中方法的含义:

  1. onPreExcute:线程任务执行之前,进行一些初始化操作;
  2. OnPostExcute:线程任务执行完毕之后,做一些清除的工作,比如数据库连接。入参类型和方法中的返回参数类型相对应,可以获取到线程任务的执行结果;
  3. doInBackground:唯一一个在异步线程执行的方法,异步代码需要写在该方法中;
  4. publishProgress:可以使用在 doInBackground 中,实时向外界(主线程)传送任务的执行进度;
  5. onProgressUpdate:调用 publishProgress 方法后可以在该方法中获取进度的回调,进而可以执行一些 UI 操作;
  6. onPostExecute:任务执行完毕,即 doInBackground 执行完毕后该方法会被调用,且 doInBackground 中 return 的值会被传递到该方法中;

示例代码如下:

public class MainActivity extends AppCompatActivity {

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

        asyncTask = new MainAsyncTask();
        // 入参会被传递到doInBackground方法中,可以传递多个值
        asyncTask.execute(100);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (asyncTask != null) {
            asyncTask.cancel(true);
        }
    }

    public class MainAsyncTask extends AsyncTask {

        TextView textView;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();

            // 该方法在线程任务开始执行之前被调用
            textView = findViewById(R.id.textView);
        }

        @Override
        protected String doInBackground(Integer... integers) {
            // 只有该方法在子线程执行,所以耗时逻辑需要在这里实现

            for (int i = 0; i < integers[0]; i++) {
                // 将当前任务的进度传递出去,这里可以传递多个值
                publishProgress(i);

                // 模拟耗时
                SystemClock.sleep(100);

            }
            return "Task Finished";
        }

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

            // 该方法会接收到publishProgress中传递的进度
            // values数组元素个数和publishProgress传递的个数一样
            textView.setText("loading:" + values[0] + "%......");
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);

            // 任务执行完毕,即doInBackground方法return,之后会调用该方法,入参为doInBackground方法return的值
            textView.setText(s);
        }
    }
}

特别注意:

  • 只有 doInBackground 方法在其他线程执行,剩余方法都是在 UI 线程执行;

因此,可以直接在 onProgressUpdate 或者是 onPostExecute 方法中进行 UI 操作;

3. AsyncTask中内存泄漏的处理

当 Activity 被 Destory 时,需要主动 cancle 对应的 AsyncTask,否则会造成内存泄漏,需要在 onDestroy 方法中主动清除:

@Override
protected void onDestroy() {
    super.onDestroy();
    if (asyncTask != null) {
        if (!asyncTask.isCancelled()) {
            asyncTask.cancel(true);
        }
    }
}

PS:有资料说即使 cancel 方法的参数 mayInterruptIfRunning 为 True,AsyncTask 也不会中断,此时需要在 doInBackground 中加入 while() 判断:

@Override
protected String doInBackground(Integer... integers) {
    // 只有该方法在子线程执行,所以耗时逻辑需要在这里实现

    while(!this.isCancelled()){
        for (int i = 0; i < integers[0]; i++) {
            // 将当前任务的进度传递出去,这里可以传递多个值
            publishProgress(i);

            // 模拟耗时
            SystemClock.sleep(100);
        }
    }
    return "Task Finished";
}

当然,还可以将 AsyncTask 标记为 static,此时内部类变成了静态内部类。Java 中 文档中指出,一旦内部类使用static修饰,那么此时这个内部类就升级为顶级类。所以,从某种意义上说,静态内部类已经不是内部类的一种了。所以:

  1. 静态内部类不能再使用外部类中的实例方法、属性;
  2. 本质是静态内部类不再引用外部类了,因此也不存在 Activity 无法被释放的情况,也就不会造成内存泄漏,最多就是 Activity 被回收,AsyncTask 仍在执行;
4. 为什么 AsyncTask 会内存泄漏

AsyncTask之所以可能会产生内存泄露,是因为:

  1. 我们一般在组件内部,以内部类的方式创建AsyncTask,而java里面,内部类是默认持有外部类的引用。
  2. 我们的加载数据是在子线程中执行,但是java里面有没有提供很好的中断机制来中断线程 (有中断方法,但是如果你不针对性的处理,这个方法也没什么卵用),这样就导致组件生命周期已经结束,应该被GC回收,但是由于子线程正在执行,内部类无法回收,进而导致组件无法正常回收,所以造成了内存泄露 (Handler导致内存泄露也是类似的道理)。

来源:Android 中更安全的使用 AsyncTask

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/328852.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号