一个 AsynckTask 的多个回调
Posted
技术标签:
【中文标题】一个 AsynckTask 的多个回调【英文标题】:Multiple callbacks for one AsynckTask 【发布时间】:2017-06-20 14:06:21 【问题描述】:我正在编写一个应用程序,其中我在 ViewPager 中有不同的片段。在每个片段中,我使用几个 AsyncTask 从 Web 服务器获取数据。一些片段需要调用相同的 AsynTask(service),但如果其中一个已经调用它,因为服务需要一段时间才能响应,我想防止再次调用它,而是让 AsyncTask 发送结果到所有调用它的片段。当用户更新片段(即SwipeToRefresh)时,我还需要更新所有片段中的数据。我今天使用的方法是一个函数,我验证服务是否已被调用,如果不是,则保存一个标志以指示该服务已被调用,并使用接收回调接口的 AsyncTask 调用服务以发送结果到请求的 Fragmnet,如果在另一方面,服务已经被调用,则将 Callback 添加到 Callback 列表中,稍后在 AsyncTask.onPostExecute 中遍历该列表以将结果发送到所有 Fragmnet。
最大的问题是当我多次请求时,比如用户在一段时间后打开应用程序时,会导致内存泄漏(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);
我希望你能帮助我,对于我可能犯的任何拼写错误或语法错误,我深表歉意。
【问题讨论】:
【参考方案1】:在当前片段可见时进行 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;
我希望,这样你就可以在fragment内部管理api调用并轻松更新。
【讨论】:
【参考方案2】:我也遇到了和你一样的问题。我还有一个回调,它由想要使用数据的每个视图/片段实现。然后我有一个加载数据的异步任务。当我收到响应时,我将对象保存到一个管理器类中,其中包括我必须通知以进行视图更新的回调列表。所以所有实现回调的视图/片段都必须自己在管理器上注册。
代码示例: Example
【讨论】:
【参考方案3】:您可以像这样在 java(1.5 或更高版本)中使用枚举:-
enum Tasks
task1, task2
并在您的接口方法中传递“任务”类型的参数,如下所示:-
interface Callback
void onPreExecute(Tasks task);
void onPostExecute(Tasks task, Object object);
并像这样使用它:-
callback.onPreExecute(Tasks.task1); or callback.onPostExecute(Tasks.task1, object);
【讨论】:
以上是关于一个 AsynckTask 的多个回调的主要内容,如果未能解决你的问题,请参考以下文章
我可以在破折号情节回调中使用多个输入,但只有一个触发回调吗?