Uploading a large file (> 100 MB) to Honeycomb in AsyncTask slows down the user interface, perhaps due to the GC?

I have my own inner class called DownloadFileAsyncTask in one of my actions. I added:

private class DownloadFileAsyncTask extends AsyncTask<URL, Integer, Boolean> { private static final String TAG = "DownloadFileAsyncTask"; @Override protected void onPreExecute() { WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE); mWifiLock = manager.createWifiLock("wifilock"); mWifiLock.acquire(); } @Override protected Boolean doInBackground(URL... params) { try { URLConnection urlConnection = params[0].openConnection(); urlConnection.connect(); InputStream in = urlConnection.getInputStream(); FileOutputStream out = openFileOutput("archive.zip", Context.MODE_PRIVATE); int fileSize = urlConnection.getContentLength(); if (fileSize == 0) { return false; } int downloadedSize = 0; byte[] data = new byte[1024]; int count = 0; while ((count = in.read(data)) != -1) { if (isCancelled()) { Log.d(TAG, "Download cancelled."); out.close(); in.close(); return false; } out.write(data, 0, count); downloadedSize += count; publishProgress(downloadedSize, fileSize); } out.close(); in.close(); } catch (Exception ex) { Log.e(TAG, "doInBackground()", ex); return false; } return true; } @Override protected void onProgressUpdate(Integer... values) { int downloadedSize = values[0]; int fileSize = values[1]; int progressPercent = ((int) ((downloadedSize / (float) fileSize) * 100)); mDownloadButton.setText(String.format("%.1f MB", downloadedSize / 1048576f)); mProgressBar.setProgress(progressPercent); } @Override protected void onPostExecute(Boolean result) { } @Override protected void onCancelled() { mWifiLock.release(); } } 

This code works. The file is loading and my ProgressBar is updating correctly. I also have a cancel button that the user can click to close the download. This also works, however, when I click the button, it takes a few seconds for the button to click to register (I am testing the hardware). When I look at logcat at boot time, I see a lot of junk collection. In fact, this seems permanent. I know that GC can cause delays in the user interface, and my theory is what is happening here. Has anyone experienced this before? Is there a better way to download a file?

EDIT:

The publishProgress () call at the end of each iteration of the main loop caused delays. Here is the updated code for doInBackground () to solve the problem:

 @Override protected Boolean doInBackground(URL... params) { try { URLConnection urlConnection = params[0].openConnection(); urlConnection.connect(); BufferedInputStream in = new BufferedInputStream(urlConnection.getInputStream()); BufferedOutputStream out = new BufferedOutputStream(openFileOutput("archive.zip", Context.MODE_PRIVATE)); int fileSize = urlConnection.getContentLength(); if (fileSize == 0) { return false; } int downloadedSize = 0; byte[] data = new byte[1024]; int count = 0; Calendar lastUpdate = Calendar.getInstance(); while ((count = in.read(data)) != -1) { if (isCancelled()) { Log.d(TAG, "Download cancelled."); out.close(); in.close(); return false; } out.write(data, 0, count); downloadedSize += count; Calendar now = Calendar.getInstance(); if (now.getTimeInMillis() - lastUpdate.getTimeInMillis() >= 500) { lastUpdate = now; publishProgress(downloadedSize, fileSize); } } out.close(); in.close(); } catch (Exception ex) { Log.e(TAG, "doInBackground()", ex); return false; } return true; } 
+4
source share
1 answer

First, you can get some speed by calling publishProgress (...) less often. Set the guard in doInBackground(...) , so it will only be called every 100, 500, X milliseconds.

I was unable to determine how many bytes are being read into your data buffer at a time. That is, in.read(data) only reads up to 1024 bytes at a time? You can use a BufferedInputStream instead.

And note: if the task completed successfully, you do not call mWifiLock.release();

+3
source

All Articles