Зниження API Android AsyncTask в Android 11. Які альтернативи?


21

EDIT : Це питання не є дублікатом

  1. Лише пару днів тому AOSP було здійснено зобов’язання щодо анулювання.
  2. Інше питання стосується використання AsyncTaskLoader через AsyncTask.


Google знецінює API AsyncTask для Android в 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) ;
        }     


    }

5
"Застаріле" означає, що Google рекомендує вам перейти на щось інше. Це не означає, що клас буде видалено незабаром. Зокрема, AsyncTaskїх не можна видалити без порушення сумісності.
CommonsWare


2
@ Style-7 це не так.
EpicPandaForce

Немає такого поняття, як "статичний внутрішній клас". Ви маєте на увазі статичний вкладений клас.
beroal

Відповіді:


22
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);
    }); 
}

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

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

Я отримую помилку executor.post. Неможливо вирішити метод
Kris B

@KrisB, мабуть, називається execute()замістьpost()
EpicPandaForce

Чи знаєте ви, чи нормально це передати Context? Я знаю, що проходження Contextв AsyncTaskодну з них було проблемою.
Кріс Б

Вам все одно потрібно запустити це в ViewModel, збереженому фрагменті, синглетоні або будь-якому іншому, як це зазвичай робиться з будь-якою асинхронізацією в Android.
EpicPandaForce

1
newSingleThreadExecutorкраще для запису, але ви обов'язково повинні використовувати THREAD_POOL_EXECUTORв кінці публікації для читання бази даних.
EpicPandaForce

3

Google рекомендує використовувати рамку Java Concurrency або Kotlin Coroutines. але Rxjava в кінцевому рахунку має набагато більшу гнучкість та можливості, а потім паралельність java набула зовсім небагато популярності.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.