2017-02-03 5 views
2

Я пишу приложение, в котором у меня есть другой фрагмент в ViewPager. В каждом фрагменте я использую несколько AsyncTask для получения данных с веб-сервера. Некоторым фрагментам нужно вызывать одну и ту же AsynTask (услугу), но если один из них уже вызвал ее, так как службе требуется некоторое время для ответа, я хочу, чтобы ее не вызывали, вместо этого я хочу, чтобы AsyncTask отправил результат для всех фрагментов, которые его назвали. Мне также необходимо обновить данные во всех фрагментах, когда пользователь обновляет фрагмент (SwipeToRefresh i.e.). Апроверк, который у меня есть сегодня, - это функция, в которой я проверяю, была ли вызвана услуга, если это не так, сохраняет флаг, указывающий, что служба была вызвана, и вызовите службу, используя AsyncTask, которая получает интерфейс обратного вызова для отправки результат для запрашивающей Fragmnet, если, с другой стороны, служба уже вызвана, добавьте Обратный вызов в список обратного вызова, который затем проходит в AsyncTask.onPostExecute, чтобы отправить результ во все фрагменты.Несколько обратных вызовов для одного AsynckTask

Самая большая проблема заключается в том, что когда я делаю несколько запросов, как когда пользователь открывает приложение через некоторое время, это приводит к утечке памяти (GC работает слишком много, и приложение зависает), и приложение прекращается. Он также не решает проблему обновления всех фрагментов за один вызов.

Это код процедуры я уже говорил ранее (только в качестве примера):

public class Test { 

private static List<Integer> calledServices = new ArrayList<>(); 
private static Map<Integer, List<Callback>> callbacksMap = new HashMap<>(); 

public static void call(int serviceId, Callback callback) { 
    if (!hasBeenCalled(serviceId)) { 
     calledServices.add(serviceId); //saves flag 
     ServiceAsyncTask task = new ServiceAsyncTask(serviceId, callback); 
     task.execute(); 
    } else { 
     callback.onPreExecute(); 
     if (callbacksMap.containsKey(serviceId)) { 
      callbacksMap.get(serviceId).add(callback); 
     } else { 
      List<Callback> callbacks = new ArrayList<>(); 
      callbacks.add(callback); 
      callbacksMap.put(serviceId, callbacks); 
     } 
    } 
} 

private static boolean hasBeenCalled(int serviceId) { 
    return calledServices.contains(serviceId); 
} 

interface Callback { 
    void onPreExecute(); 

    void onPostExecute(Object object); 
} 

static class ServiceAsyncTask extends AsyncTask<Object, Object, Object> { 
    private final int serviceId; 
    private final Callback mCallback; 

    ServiceAsyncTask(int serviceId, Callback callback) { 
     this.serviceId = serviceId; 
     this.mCallback = callback; 
    } 

    @Override 
    protected void onPreExecute() { 
     mCallback.onPreExecute(); 
    } 

    Object doInBackground(Object... params) { 
     return WebService.call(serviceId); 
    } 

    @Override 
    protected void onPostExecute(Object o) { 
     mCallback.onPostExecute(o); 

     if (!callbacksMap.containsKey(serviceId)) return; 

     for (Callback callback : callbacksMap.get(serviceId)) { 
      callback.onPostExecute(o); 
     } 

     callbacksMap.remove(serviceId); 
     calledServices.remove(serviceId); 
    } 
} 

}

Я надеюсь, что вы можете помочь мне, и я приношу извинения за любые опечатки или грамматические ошибки, я, возможно, сделанный.

ответ

0

Сделайте свой API-вызов, когда отображается текущий фрагмент.

Например,

private boolean hasLoadedOnce= false; 
    @Override 
    public void setUserVisibleHint(boolean isFragmentVisible) { 
    super.setUserVisibleHint(true); 
    if (this.isVisible()) { 
     // we check that the fragment is becoming visible 
     if (isFragmentVisible && !hasLoadedOnce) { 
      new ServiceAsyncTask().execute(); 
      hasLoadedOnce = true; 
     } 
    } 
    } 

Я надеюсь, что, таким образом, вы можете mangage апи вызов внутри fragement и обновить легко.

0

Рекомендую использовать EventBus библиотека. Подписаться на событие во всех фрагментах. Вызовите свою задачу один раз и когда вы получите сообщение о событии.

0

У меня была аналогичная проблема, как и вы. У меня также есть обратный вызов, который реализуется каждым представлением/фрагментом, который хочет использовать данные. Затем у меня есть asynctask, которая загружает данные. Когда я получаю ответ, я сохраняю объект в классе менеджера, который включает список обратных вызовов, которые я должен уведомить об обновлении вида. Таким образом, все представления/фрагменты, которые реализуют обратный вызов, должны быть зарегистрированы самим менеджером.

Код Пример: Example