Android AsyncTask API устарел в Android 11. Какие есть альтернативы?

21

РЕДАКТИРОВАТЬ : Этот вопрос не является дубликатом, как

  1. Всего пару дней назад AOSP коммит на амортизацию был сделан.
  2. Другой вопрос касается использования AsyncTaskLoader поверх AsyncTask.


Google не поддерживает Android AsyncTask API в Android 11 и предлагает использовать 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.concurrent. Это статический внутренний класс Деятельности. Я ищу то, что будет работать сminSdkVersion 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) ;
        }     


    }
Zeeshan
источник
5
«Устаревший» означает, что Google рекомендует вам перейти на что-то другое. Это не означает, что класс будет удален в ближайшее время. В частности, AsyncTaskне может быть удален без нарушения обратной совместимости.
CommonsWare
Возможный дубликат AsyncTask устарела теперь с AsyncTaskLoader?
Стиль-7
2
@ Style-7 это не так.
EpicPandaForce
Не существует такого понятия, как «статический внутренний класс». Вы имеете в виду статический вложенный класс.
beroal

Ответы:

23
private WeakReference<MyActivity> activityReference;

Хорошо, что это устарело, потому что это WeakReference<Context>был взлом, а не правильное решение .

Теперь у людей будет возможность дезинфицировать свой код.


AsyncTask<String, Void, MyPojo> 

Основанный на этом коде, Progressфактически не нужен, и есть Stringвход + MyPojoвыход.

На самом деле это довольно легко сделать без использования 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);
    }); 
}

В этом примере используется однопоточный пул, который подходит для записи в БД (или сериализованных сетевых запросов), но если вы хотите что-то для чтения БД или нескольких запросов, вы можете рассмотреть следующую конфигурацию Executor:

private static final Executor THREAD_POOL_EXECUTOR =
        new ThreadPoolExecutor(5, 128, 1,
                TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
EpicPandaForce
источник
Я получаю сообщение об ошибке на executor.post. Не
Крис Б
@ KrisB, по-видимому, это называется execute()вместоpost()
EpicPandaForce
Знаете ли вы, если это нормально, чтобы передать Contextэто? Я знаю, что передача Contextв AsyncTaskбыла одной из проблем.
Крис Б
Вам по-прежнему нужно запускать это в ViewModel, сохраненном фрагменте, синглтоне или чем-то еще, как вы обычно делаете с любой асинхронностью в Android.
EpicPandaForce
1
newSingleThreadExecutorлучше для записи, но вы обязательно должны использовать THREAD_POOL_EXECUTORв конце поста для чтения базы данных.
EpicPandaForce
3

Google рекомендует использовать среду параллелизма Java или Kotlin Coroutines. но у Rxjava гораздо больше гибкости и возможностей, чем у Java-параллелизма, поэтому он приобрел немалую популярность.

Ваххаб хан жадон
источник