【问题标题】:Android AsyncTask out of memory via http requestAndroid AsyncTask 通过 http 请求内存不足
【发布时间】:2013-04-04 02:23:53
【问题描述】:

所以基本上,让我设置场景:

List<Account> accounts = ...//Initialised with 2 accounts.

for( Account ac : accounts)
{
   new AsyncTask<...>(){ getTwitterTimeLine(amount);}.execute();
}

所以你可以在这里看到两个 AsyncTask 被一个接一个地调用。

现在是有趣的部分,

如果我将数量变量设置为 10。该方法调用 HTTP 请求,请求 10 个最新的提要项。这工作得很好,正常的行为是将返回的数据放入多个可能的列表视图之一中,(都可以通过 viewpager 查看,因此在这种情况下,2 个列表视图分别由 2 个异步任务填充)

但是

如果我把数量设置为 100,那么基本上更多的 JSON 数据,我得到以下;

   04-04 03:11:20.175: E/AndroidRuntime(4574): FATAL EXCEPTION: AsyncTask #1
04-04 03:11:20.175: E/AndroidRuntime(4574):     at android.os.AsyncTask$3.done(AsyncTask.java:299)
04-04 03:11:20.175: E/AndroidRuntime(4574):     at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
04-04 03:11:20.175: E/AndroidRuntime(4574):     at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
04-04 03:11:20.175: E/AndroidRuntime(4574):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
04-04 03:11:20.175: E/AndroidRuntime(4574):     at java.util.concurrent.FutureTask.run(FutureTask.java:137)
04-04 03:11:20.175: E/AndroidRuntime(4574):     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
04-04 03:11:20.175: E/AndroidRuntime(4574):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
04-04 03:11:20.175: E/AndroidRuntime(4574):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
04-04 03:11:20.175: E/AndroidRuntime(4574):     at java.lang.Thread.run(Thread.java:856)
04-04 03:11:20.175: E/AndroidRuntime(4574): Caused by: java.lang.OutOfMemoryError
04-04 03:11:20.175: E/AndroidRuntime(4574):     at 

java.lang.AbstractStringBuilder.enlargeBuffer(AbstractStringBuilder.java:94)
04-04 03:11:20.175: E/AndroidRuntime(4574):     at java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:145)
04-04 03:11:20.175: E/AndroidRuntime(4574):     at java.lang.StringBuilder.append(StringBuilder.java:216)
04-04 03:11:20.175: E/AndroidRuntime(4574):     at twitter4j.internal.org.json.JSONArray.join(JSONArray.java:363)
04-04 03:11:20.175: E/AndroidRuntime(4574):     at twitter4j.internal.org.json.JSONArray.toString(JSONArray.java:605)
04-04 03:11:20.175: E/AndroidRuntime(4574):     at twitter4j.internal.http.HttpResponse.asJSONArray(HttpResponse.java:192)
04-04 03:11:20.175: E/AndroidRuntime(4574):     at twitter4j.internal.json.StatusJSONImpl.createStatusList(StatusJSONImpl.java:381)
04-04 03:11:20.175: E/AndroidRuntime(4574):     at twitter4j.internal.json.z_T4JInternalJSONImplFactory.createStatusList(z_T4JInternalJSONImplFactory.java:74)
04-04 03:11:20.175: E/AndroidRuntime(4574):     at twitter4j.TwitterImpl.getHomeTimeline(TwitterImpl.java:127)

它直接指向我的 AsyncTask 的 doInBackground 方法,在该方法中调用 getTwitterTimeLine()。

我该如何解决这个问题?我希望能够引入大量数据,并将其泵送到多个列表视图等。 我阅读了很多内容,我想也许我需要将任务排队,以防其中一个占用大量内存,所以我研究并使用了Proper use of AsyncTask,但这没有任何效果,我仍然摆脱了困境内存问题。

无论如何如何解决/解决这个问题?我阅读了 LoaderManager,但我希望将其推迟到最后一次调用,因为它会导致重大的设计更改。

感谢您的帮助。

注意:getTwitterTimeLine 方法调用一个调用 api 的 twitter4j 方法。

【问题讨论】:

  • 您要返回多少数据?
  • 在 100 个场景中,大约有 100 个 json 对象,每个对象都包含来自推文的一些数据字符串。总而言之,体积很小。

标签: java android performance asynchronous android-asynctask


【解决方案1】:

您不想像这样在循环中触发 AsyncTask。有一个固定的线程池大小,虽然两个帐户左右不足以将其最大化,但最好不要这样做。相反,请确定如何在单个异步任务中加载所有这些数据。 doInBackground() 接受参数列表。例如,您可以使用在构造函数中设置的数量创建 AsyncTask 并传入帐户以加载数据。

@Override
protected Map<Account, Data> doInBackground(Accounts...params){
    Map<Account, Data> resultMap = new HashMap<Account, Data>();
    for (Account account : params) {
        // do whatever!
    }
    return resultMap;
}

【讨论】:

    【解决方案2】:

    你不能依赖AsyncTasks for parallel execution

    首次引入时,AsyncTask 是在单个后台线程上串行执行的。从 DONUT 开始,这被更改为允许多个任务并行运行的线程池。从 HONEYCOMB 开始,任务在单线程上执行,以避免并行执行导致的常见应用程序错误。

    至于 twitter4j...

    at java.lang.StringBuilder.append(StringBuilder.java:216)
    04-04 03:11:20.175: E/AndroidRuntime(4574):     at twitter4j.internal.org.json.JSONArray.join(JSONArray.java:363)
    

    ...它在内部使用 StringBuilder。在内存有限的设备上跨多个线程使用字符串连接必然会导致 OOM。如果您想节省这些 json 字符串占用的内存,请改用 JsonReader。至于并行执行,您可以使用由ThreadPool 支持的线程来并行执行它们。 AsyncTasks 在某些版本的 android 中是串行执行的。

    【讨论】:

      【解决方案3】:

      最终,这是因为位图没有被内存管理。尽管实现了 android 开发页面描述的 inSampleSize 框架以有效加载位图,但似乎适当地维护和管理它们是必要的。

      感谢所有回复的人,主题非常丰富。

      【讨论】:

      • 很高兴听到您找到了问题的根源。看看 android SDK 的示例文件夹下的 'bitmapfun' 项目。它有包-> com.example.android.bitmapfun.ui.ImageGridActivity。它提供了一些关于管理和加载图像的有用提示。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-30
      • 1970-01-01
      相关资源
      最近更新 更多