Add a buffer queue for Android Downloader to prevent out of memory

When the AssetManagerEx start downloading, it used to create all the
download tasks all at once. When the app has a large number of asset
files, it is likely to crash due to out of memory when creating
threads for each of the download tasks. This commit adds a buffer
queue to the downloader to use the `countOfMaxProcessingTasks`
property from hints, preventing all the tasks from starting all at once.
This commit is contained in:
Ce Zheng 2015-12-01 16:25:50 +09:00
parent 6db6e596bb
commit d174a98afa
2 changed files with 29 additions and 5 deletions

View File

@ -70,7 +70,7 @@ namespace cocos2d { namespace network {
if (JniHelper::getStaticMethodInfo(methodInfo,
JCLS_DOWNLOADER,
"createDownloader",
"(II" JARG_STR ")" JARG_DOWNLOADER))
"(II" JARG_STR "I)" JARG_DOWNLOADER))
{
jobject jStr = methodInfo.env->NewStringUTF(hints.tempFileNameSuffix.c_str());
jobject jObj = methodInfo.env->CallStaticObjectMethod(
@ -78,7 +78,8 @@ namespace cocos2d { namespace network {
methodInfo.methodID,
_id,
hints.timeoutInSeconds,
jStr
jStr,
hints.countOfMaxProcessingTasks
);
_impl = methodInfo.env->NewGlobalRef(jObj);
DLLOG("android downloader: jObj: %p, _impl: %p", jObj, _impl);

View File

@ -99,6 +99,10 @@ class FileTaskHandler extends FileAsyncHttpResponseHandler {
@Override
public void onFinish() {
// onFinish called after onSuccess/onFailure
Runnable taskRunnable = _downloader.dequeue();
if (taskRunnable != null) {
Cocos2dxHelper.getActivity().runOnUiThread(taskRunnable);
}
}
@Override
@ -166,7 +170,9 @@ public class Cocos2dxDownloader {
private int _id;
private AsyncHttpClient _httpClient = new AsyncHttpClient();
private String _tempFileNameSufix;
private int _countOfMaxProcessingTasks;
private HashMap _taskMap = new HashMap();
private Queue<Runnable> _taskQueue = new LinkedList<Runnable>();
void onProgress(final int id, final long downloadBytes, final long downloadNow, final long downloadTotal) {
DownloadTask task = (DownloadTask)_taskMap.get(id);
@ -202,7 +208,7 @@ public class Cocos2dxDownloader {
});
}
public static Cocos2dxDownloader createDownloader(int id, int timeoutInSeconds, String tempFileNameSufix) {
public static Cocos2dxDownloader createDownloader(int id, int timeoutInSeconds, String tempFileNameSufix, int countOfMaxProcessingTasks) {
Cocos2dxDownloader downloader = new Cocos2dxDownloader();
downloader._id = id;
@ -214,6 +220,7 @@ public class Cocos2dxDownloader {
downloader._httpClient.allowRetryExceptionClass(javax.net.ssl.SSLException.class);
downloader._tempFileNameSufix = tempFileNameSufix;
downloader._countOfMaxProcessingTasks = countOfMaxProcessingTasks;
return downloader;
}
@ -222,7 +229,7 @@ public class Cocos2dxDownloader {
final String url = url_;
final String path = path_;
Cocos2dxHelper.getActivity().runOnUiThread(new Runnable() {
Runnable taskRunnable = new Runnable() {
@Override
public void run() {
DownloadTask task = new DownloadTask();
@ -269,7 +276,13 @@ public class Cocos2dxDownloader {
downloader._taskMap.put(id, task);
}
}
});
};
if (downloader._taskQueue.size() < downloader._countOfMaxProcessingTasks) {
Cocos2dxHelper.getActivity().runOnUiThread(taskRunnable);
downloader._taskQueue.add(null);
} else {
downloader._taskQueue.add(taskRunnable);
}
}
public static void cancelAllRequests(final Cocos2dxDownloader downloader) {
@ -291,6 +304,16 @@ public class Cocos2dxDownloader {
});
}
public Runnable dequeue() {
if (!_taskQueue.isEmpty() && _taskQueue.element() == null) {
_taskQueue.remove();
}
if (!_taskQueue.isEmpty()) {
return _taskQueue.remove();
}
return null;
}
native void nativeOnProgress(int id, int taskId, long dl, long dlnow, long dltotal);
native void nativeOnFinish(int id, int taskId, int errCode, String errStr, final byte[] data);
}