AsyncTask API 在 Android 11 中已弃用。有哪些替代方案?

Google正在Android 11中弃用Android AsyncTask API,并建议改用。你可以在这里查看提交java.util.concurrent

 *
 * @deprecated Use the standard <code>java.util.concurrent</code> or
 *   <a href="https://developer.android.com/topic/libraries/architecture/coroutines">
 *   Kotlin concurrency utilities</a> instead.
 */
@Deprecated
public abstract class AsyncTask<Params, Progress, Result> {

如果您在Android中维护具有异步任务的旧代码库,则将来可能不得不对其进行更改。我的问题是,应该使用正确替换下面显示的代码片段。它是活动的静态内部类。我正在寻找一些可以工作的东西java.util.concurrentminSdkVersion 16

private static class LongRunningTask extends AsyncTask<String, Void, MyPojo> {
        private static final String TAG = MyActivity.LongRunningTask.class.getSimpleName();
        private WeakReference<MyActivity> activityReference;

        LongRunningTask(MyActivity context) {
            activityReference = new WeakReference<>(context);
        }

        @Override
        protected MyPojo doInBackground(String... params) {
            // Some long running task
            
        }

        @Override
        protected void onPostExecute(MyPojo data) {

            MyActivity activity = activityReference.get();
            activity.progressBar.setVisibility(View.GONE);
            populateData(activity, data) ;
        }     


    }

答案 1

您可以直接从包中使用。Executorsjava.util.concurrent

我也搜索了它,并在这个Android Async API中找到了一个解决方案,已弃用的帖子。

不幸的是,这篇文章使用的是Kotlin,但经过一些努力,我把它转换成了Java。所以这是解决方案。

ExecutorService executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());

executor.execute(new Runnable() {
    @Override
    public void run() {

        //Background work here

        handler.post(new Runnable() {
            @Override
            public void run() {
                //UI Thread work here
            }
        });
    }
});

很简单吧?如果您在项目中使用 Java 8,则可以进一步简化它。

ExecutorService executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());

executor.execute(() -> {
    //Background work here
    handler.post(() -> {
        //UI Thread work here
    });
});

尽管如此,它还是不能打败kotlin的代码简洁性,但比以前的java版本更好。

希望这会帮助你。谢谢


答案 2
private WeakReference<MyActivity> activityReference;

很好的谜语,它被弃用了,因为弱引用<Context>总是一个黑客,而不是一个合适的解决方案

现在,人们将有机会清理他们的代码。


AsyncTask<String, Void, MyPojo> 

基于此代码,其实是不需要的,并且有一个输入+输出。ProgressStringMyPojo

这实际上很容易实现,而无需使用任何AsyncTask。

public class TaskRunner {
    private final Executor executor = Executors.newSingleThreadExecutor(); // change according to your requirements
    private final Handler handler = new Handler(Looper.getMainLooper());

    public interface Callback<R> {
        void onComplete(R result);
    }

    public <R> void executeAsync(Callable<R> callable, Callback<R> callback) {
        executor.execute(() -> {
            final R result = callable.call();
            handler.post(() -> {
                callback.onComplete(result);
            });
        });
    }
}

如何传入字符串?这样:

class LongRunningTask implements Callable<MyPojo> {
    private final String input;

    public LongRunningTask(String input) {
        this.input = input;
    }

    @Override
    public MyPojo call() {
        // Some long running task
        return myPojo;
    }
}

// in ViewModel
taskRunner.executeAsync(new LongRunningTask(input), (data) -> {
    // MyActivity activity = activityReference.get();
    // activity.progressBar.setVisibility(View.GONE);
    // populateData(activity, data) ;

    loadingLiveData.setValue(false);
    dataLiveData.setValue(data);
});

// in Activity
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main_activity);

    viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
    viewModel.loadingLiveData.observe(this, (loading) -> {
        if(loading) {
            progressBar.setVisibility(View.VISIBLE);
        } else {
            progressBar.setVisibility(View.GONE);
        }
    });

    viewModel.dataLiveData.observe(this, (data) -> {
        populateData(data);
    }); 
}

此示例使用了一个单线程池,该池适用于数据库写入(或序列化网络请求),但如果您需要数据库读取或多个请求,则可以考虑以下执行器配置:

private static final Executor THREAD_POOL_EXECUTOR =
        new ThreadPoolExecutor(5, 128, 1,
                TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());

推荐