Reputation: 1002
I have a phonegap application (Android). I make use of the plugin Downloader to download xml files. When I download a file my application "pauses" until the download is finished. I can't click on anything, my loaders don't work etc.
It use to work fine but I had to upgrade my app from cordova 1.8.0 to a new version (2.7.0).
I also altered the plugin itself to work with the new cordova.
I don't know what is causing this. Any ideas?.
-------EDIT: ADDED CODE---------
Here is my Downloader plugin class
public class Downloader extends CordovaPlugin {
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
if (!action.equals("downloadFile")){
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.INVALID_ACTION));
return true;
}
try {
String fileUrl = args.getString(0);
JSONObject params = args.getJSONObject(1);
String fileName = params.has("fileName") ?
params.getString("fileName"):
fileUrl.substring(fileUrl.lastIndexOf("/")+1);
String dirName = params.has("dirName") ?
params.getString("dirName"):
Environment.getExternalStorageDirectory().toString();
Boolean overwrite = params.has("overwrite") ? params.getBoolean("overwrite") : false;
callbackContext.sendPluginResult(this.downloadUrl(fileUrl, dirName, fileName, overwrite, callbackContext));
return true;
} catch (JSONException e) {
e.printStackTrace();
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage()));
return false;
} catch (InterruptedException e) {
e.printStackTrace();
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, e.getMessage()));
return false;
}
}
private PluginResult downloadUrl(String fileUrl, String dirName, String fileName, Boolean overwrite, CallbackContext callbackContext) throws InterruptedException, JSONException {
try {
Log.d("PhoneGapLog", "Downloading "+fileUrl + " into " + dirName + "/" + fileName);
File dir = new File(dirName);
if (!dir.exists()) {
Log.d("PhoneGapLog", "directory " + dirName + " created");
dir.mkdirs();
}
File file = new File(dirName, fileName);
if (!overwrite && file.exists()) {
Log.d("DownloaderPlugin", "File already exist");
JSONObject obj = new JSONObject();
obj.put("status", 1);
obj.put("total", 0);
obj.put("file", fileName);
obj.put("dir", dirName);
obj.put("progress", 100);
return new PluginResult(PluginResult.Status.OK, obj);
}
URL url = new URL(fileUrl);
HttpURLConnection ucon = (HttpURLConnection) url.openConnection();
ucon.setRequestMethod("GET");
ucon.connect();
Log.d("PhoneGapLog", "Download start");
InputStream is = ucon.getInputStream();
byte[] buffer = new byte[1024];
int readed = 0,
progress = 0,
// totalReaded = 0,
fileSize = ucon.getContentLength();
FileOutputStream fos = new FileOutputStream(file);
while ((readed = is.read(buffer)) > 0) {
fos.write(buffer, 0, readed);
//totalReaded += readed;
//int newProgress = (int) (totalReaded*100/fileSize);
//if (newProgress != progress)
// progress = informProgress(fileSize, newProgress, dirName, fileName, callbackId);
}
fos.close();
Log.d("PhoneGapLog", "Download finished");
JSONObject obj = new JSONObject();
obj.put("status", 1);
obj.put("total", fileSize);
obj.put("file", fileName);
obj.put("dir", dirName);
obj.put("progress", progress);
return new PluginResult(PluginResult.Status.OK, obj);
}
catch (FileNotFoundException e) {
Log.d("PhoneGapLog", "File Not Found: " + e);
return new PluginResult(PluginResult.Status.ERROR, 404);
}
catch (IOException e) {
Log.d("PhoneGapLog", "Error: " + e);
return new PluginResult(PluginResult.Status.ERROR, e.getMessage());
}
}
}
Here is my Downloader plugin javascript
function Downloader() {}
Downloader.prototype.downloadFile = function(fileUrl, params, win, fail) {
//Make params hash optional.
if (!fail) win = params;
return cordova.exec(win, fail, "Downloader", "downloadFile", [fileUrl, params]);
};
if(!window.plugins) {
window.plugins = {};
}
if (!window.plugins.downloader) {
window.plugins.downloader = new Downloader();
}
And when I call it
$.mobile.showPageLoadingMsg();
window.plugins.downloader.downloadFile("URL",
{overwrite: true,
dirName: dir, fileName: "File.xml"},
function() {
alert("finished");
}, function(error) {
alert("fail");
);
The loader that apears because of showPageLoadingMsg will either freeze until the download is finish or only show up once the download is finished
Upvotes: 0
Views: 868
Reputation: 4178
PhoneGap plugin methods are called on UI thread of whole application, you should not perform long activities in UI thread, otherwise it gets blocked, no UI updates and even whole app becomes unresponsible. Please read docs - you should perform long tasks in separate thread, releasing the UI thread to PhoneGap. It is made in 2 steps - you start a new thread and return
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
r.setKeepCallback(true);
callContext.sendPluginResult(r);
with a flag that it will be a async plugin call. When the thread finishes, you finish the call with
callContext.success(json);
EDIT:
I was wrong that Cordova Plugin methods are called on UI thread, they are called on WebCore thread which is not the same as the UI one (and it is important to remember if you need to show some UI in plugin). Anyway you should not block the WebCore thread as well, see documentation:
Threading
JavaScript in the WebView does not run on the UI thread. It runs on the WebCore thread. The execute method also runs on the WebCore thread.
http://docs.phonegap.com/en/2.2.0/guide_plugin-development_android_index.md.html
Upvotes: 1