Лучший способ вернуть данные в MainActivity из AsyncTask - PullRequest
0 голосов
/ 31 октября 2019

Я использую ASyncTask в своем приложении для получения данных (короткий URL) через REST API из веб-службы (Bitly).

Когда ASyncTask завершится, я хочупередать результат обратно в мой MainActivity.

Получение данных обратно в MainActivity достигается с помощью onPostExecute метода AsyncTask.

, который я прочитали прочитайте и прочитайте о том, как это сделать, и, кажется, есть два основных подхода.

Первоначально я использовал подход «WeakReference», в котором в начале класса AsyncTask вы создаете слабую ссылку на вашMainActivity следующим образом:

private class getShortURL extends AsyncTask<String, Void, String> {

    private WeakReference<MainActivity> mainActivityWeakReference;

    myASyncTask(MainActivity activity) {
        mainActivityWeakReference = new WeakReference<>(activity);
    }
{etc etc}

При таком подходе ваш класс AsyncTask находится за пределами вашего класса MainActivity, поэтому на многие вещи необходимо ссылаться по слабой ссылке.

Это работало нормально (за исключением того, что я подозревал - возможно, неправильно - что эта слабая ссылка могла быть причиной случайных NPE), но затем я нашел другой способ сделать что-то.

Этот второй подход включал перемещение ASyncTask класс внутри MainActivity классаs.

Таким образом, я смог получить доступ ко всему, что было доступно в классе MainActivity напрямую, включая элементы и методы пользовательского интерфейса, определенные в MainActivity. Это также означает, что я могу получить доступ к таким ресурсам, как строки и т. Д., И могу сгенерировать toasts, чтобы сообщить пользователю, что происходит.

В этом случае весь код WeakReference, приведенный выше, может быть удален, а *Класс 1036 * можно сделать приватным.

Затем я также могу делать такие вещи прямо в onPostExecute или сохранять это в методе в MainActivity, который я могу вызвать напрямую из onPostExecute: shorten_progress_bar.setIndeterminate (false);shorten_progress_bar.setVisibility (View.INVISIBLE);

    if (!shortURL.equals("")) {
        // Set the link URL to the new short URL
        short_link_url.setText(shortURL);
    } else {
        CommonFuncs.showMessage(getApplicationContext(), getString(R.string.unable_to_shorten_link));
        short_link_url.setHint(R.string.unable_to_shorten_link);

    }

(обратите внимание, что CommonFuncs.showMessage() - это моя собственная оболочка для функции тоста, чтобы упростить вызов).

НО, Android Studioзатем выдает предупреждение о том, что «класс AsyncTask должен быть статическим, иначе могут возникнуть утечки».

Если я сделаю метод статическим, я получу предупреждение о том, что метод из MainActivity, который я хочу вызватьиз onPostExecute нельзя вызвать, так как он нестатический.

Если я сделаю этот метод из MainActivity статическим методом, то он не сможет получить доступ к строковым ресурсам и любым другим методам, которые не являются статичными - и не работаюткроличья нора, я иду!

То же самое верно, как и следовало ожидать, если бы я просто переместил код из метода в MainActivity в метод onPostExecute. Итак ...

  • Является ли использование AsyncTask как нестатического метода действительно плохо? (Кажется, мое приложение работает нормально с этим предупреждением в AS, но я, очевидно, не хочу создавать утечку памяти в моем приложении.
  • Является ли appraoch WeakReference на самом деле более правильным и безопасным подходом?
  • Если я использую подход WeakReference, как я могу создавать такие вещи, как toasts, которые нужно запускать в потоке пользовательского интерфейса и получать доступ к строковым ресурсам и т. Д. Из MainActivity?

Я где-то читал о создании interface, но немного растерялся и не смог найти его снова. Кроме того, это не будет иметь такую ​​же зависимость от MainActivity, что WeakReference делает и состоит в том, чтоплохо?

Я действительно ищу рекомендации по передовой практике о том, как вернуть некоторые данные в MainActivity и поток пользовательского интерфейса из AsyncTask, который безопасен и не рискует утечки памяти.

1 Ответ

2 голосов
/ 31 октября 2019

Является ли использование AsyncTask как нестатического метода действительно плохой вещью? (Кажется, мое приложение работает нормально с этим предупреждением в AS, но я, очевидно, не хочу создавать утечку памяти в моем приложении.

Да, ваши Представления и ваш Контекст будут просачиваться.

Достаточно поворотов, и ваше приложение вылетит.

Является ли подход WeakReference более правильным и безопасным?

Это помада на мертвой свинье,Слабая ссылка в этом сценарии - скорее взлом, чем решение, определенно не правильное решение.

То, что вы ищете, это форма шины событий из что-то , который переживает действие.

Вы можете использовать для этого либо сохраненные фрагменты *, либо ViewModel компонента архитектуры Android.

И вам, вероятно, потребуется ввести шаблон Observer (но не обязательно LiveData).

Если я использую подход WeakReference, как я могу создавать такие вещи, как тосты, которые нужно запускать в потоке пользовательского интерфейса, получать доступ к строковым ресурсам и т. Д. Из MainActivity?

Не запускайте подобные вещи в doInBackground().

Я действительно ищу рекомендации по передовой практике о том, как вернуть некоторые данные в MainActivity и пользовательский интерфейспоток из AsyncTask, который безопасен и не рискует утечки памяти.

Самый простой способ сделать это - использовать эту библиотеку (или написать что-то, что делает то же самоеСамостоятельно, до вас), поместите EventEmitter в ViewModel, затем подпишитесь / отмените подписку на этот EventEmitter в вашей Деятельности.

public class MyViewModel: ViewModel() {
    private final EventEmitter<String> testFullUrlReachableEmitter = new EventEmitter<>();

    public final EventSource<String> getTestFullUrlReachable() {
        return testFullUrlReachableEmitter;
    }

    public void checkReachable() {
        new testFullURLreachable().execute() 
    }

    private class testFullURLreachable extends AsyncTask<Void, Void, String> { 
        ... 
        @Override
        public void onPostExecute(String result) {
            testFullUrlReachableEmitter.emit(result);
        }
    }
}

И в вашей Деятельности / Фрагменте

private MyViewModel viewModel;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
    // ...
}

private EventSource.NotificationToken subscription;

@Override
protected void onStart() { 
    super.onStart();
    subscription = viewModel.getTestFullUrlReachable().startListening((result) -> {
        // do `onPostExecute` things here
    });
}

@Override
protected void onStop() { 
    super.onStop();
    if(subscription != null) {
        subscription.stopListening();
        subscription = null;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...