【问题标题】:Am I using AsyncTask correctly?我正确使用 AsyncTask 吗?
【发布时间】:2019-05-03 22:56:07
【问题描述】:

我正在阅读“Professional Android”一书,他们对AsyncTask 说以下内容:

请务必注意,异步任务对其运行的组件的生命周期没有内置的理解。这意味着如果您在Activity 中创建Async Task,为避免内存泄漏,您应该将其定义为静态(并确保它不持有对Activity 或其Views 的强引用)。

为了测试Async Task,我编写了以下代码,它应该在后台反转一个字符串,并通过更新TextView 显示正在逐步构建的字符串。我在这里使用强引用吗?

package com.example.leo.test01;

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

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    private TextView textView;
    private ProgressBar progressBar;

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

        textView = findViewById(R.id.text_view_reversed_string);

        new reverseStringAsync(textView).execute("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    }

    private static class reverseStringAsync extends AsyncTask<String, String, String> {

        private TextView textView;

        reverseStringAsync(TextView textView) {
            this.textView = textView;
        }

        @Override
        protected void onPreExecute() {
            Log.d(TAG, "onPreExecute()");
            textView.setText("");
        }

        @Override
        protected String doInBackground(String... strings) {
            Log.d(TAG, "doInBackground()");
            int n = strings[0].length();
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 1; i  <= n; i++) {
                stringBuilder.append(strings[0].charAt(n - i));
                publishProgress(stringBuilder.toString());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return stringBuilder.toString();
        }

        @Override
        protected void onProgressUpdate(String... values) {
            Log.d(TAG, "onProgressUpdate()");
            textView.setText(values[0]);
        }

        @Override
        protected void onPostExecute(String s) {
            Log.d(TAG, "onPostExecute()");
            textView.setText(s);
        }
    }
}

【问题讨论】:

    标签: android android-asynctask


    【解决方案1】:

    你真的不应该在这样的 AsyncTask 上睡觉。原因 - 所有 AsyncTask 共享同一个线程(除非您调用 executeOnExecutor)。这意味着如果一个任务正在运行,系统中的其他 AsyncTask 将在其完成之前运行。因此,AsyncTask 应该非常快速且独立。每次一秒钟要睡 N 次的东西不应该是异步任务。

    对于这样的事情,正确的答案可能只是将延迟消息发布到处理程序并在每次延迟时在 UI 线程上运行它。

    对于实际执行 CPU 密集型工作但需要像这样休眠的东西,请使用线程。

    【讨论】:

      【解决方案2】:

      是的,您的异步任务正在捕获对ActivityTextView 的强引用。或许为了避免内存泄漏,您应该用WeakReference&lt;TextView&gt; 包装TextView 实例。

      更多信息在这里:How to use WeakReference in Java and Android development?

      【讨论】:

      • 如果 AsyncTask 的长度是有界的,这并不是真正的问题。是的,它可能对 Activity 的引用持续了几秒钟,但在实践中,这通常不值得努力防范(如果它的时间长到足以成为潜在问题,则不应在AsyncTask 其他原因)。
      猜你喜欢
      • 2013-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-28
      • 2015-06-25
      • 2022-01-08
      • 2011-08-07
      相关资源
      最近更新 更多