下载大文件时,AsynTask 仍在运行时 ProgrressDialog 冻结
我在实现 AsynTask 和 ProgressDialog 时有勒死行为。当我下载小文件时,一切正常,进度状态从 0% 更新到 100%。但是当我下载较大的文件时,ProgressDialog 上的数字运行到 6% 或 7%,然后不再更新。但 2.3 分钟后,我收到一条消息,表明 asynctask 任务完成了下载过程。
public class DownloadHelper extends AsyncTask<String, Integer, Long> implements DialogInterface.OnDismissListener{
private volatile boolean running = true;
private PhonegapActivity _ctx = null;
private ProgressDialog _progressDialog = null;
private String _title = null;
private File _root = null;
private File _destination = null;
private DatabaseHelper _dbHelper = null;
private Cursor _cursorMedia = null;
public DownloadHelper(String title, File root, File destination, DatabaseHelper dbHelper, PhonegapActivity ctx){
_title = title;
_ctx = ctx;
_root = root;
_destination = destination;
_dbHelper = dbHelper;
}
@Override
protected void onPreExecute() {
if (_progressDialog != null)
{
_progressDialog.dismiss();
_progressDialog = null;
}
_progressDialog = new ProgressDialog(_ctx);
_progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
_progressDialog.setTitle("Downloading");
_progressDialog.setMessage(_title);
_progressDialog.setCancelable(true);
_progressDialog.setMax(100);
_progressDialog.setProgress(0);
/*_progressDialog.setOnCancelListener(
new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
_progressDialog = null;
running = false;
}
});
_progressDialog.setOnDismissListener(
new DialogInterface.OnDismissListener() {
public void onDismiss(DialogInterface dialog) {
Log.d("DownloadHelper", "canceled inside listener");
_progressDialog = null;
running = false;
}
}
);*/
_progressDialog.show();
running = true;
}
@Override
protected Long doInBackground(String... sUrl) {
try {
Log.d("DownloadHelper", "Start download from url " + sUrl[0]);
long total = 0;
total = _download(sUrl[0], _destination);
return total;
} catch (Exception ex2) {
ex2.printStackTrace();
Log.d("DownloadHelper", "Failed to download test file from " + sUrl[0] + " to " + _destination.getAbsolutePath().toString());
_closeProgressDialog();
}
return null;
}
protected void onCancelled(Long result) {
Log.d("DownloadHelper", "CANCELLED result = " + result);
_closeProgressDialog();
}
protected void onProgressUpdate(Integer... progress) {
if (_progressDialog != null && running)
{
Log.d("DownloadHelper", "UPDATED progess = " + progress[0]);
_progressDialog.setProgress(progress[0]);
}
else //cancel the task
{
Log.d("DownloadHelper", "onProgressUpdate cancelled");
cancel(true);
}
}
protected void onPostExecute(Long result) {
Log.d("DownloadHelper", "FINISHED result = " + result);
// Close the ProgressDialog
_closeProgressDialog();
running = false;
if (result != null) //OK
{
_showAlertDialog("Test has been downloaded successfully.", "Message", "OK");
}
else // error
{
_showAlertDialog("Can not download the test. Please try again later.", "Error", "OK");
}
}
@Override
protected void onCancelled() {
running = false;
}
public void onDismiss(DialogInterface dialog) {
Log.d("DownloadHelper", "Cancelled");
this.cancel(true);
}
protected void _closeProgressDialog(){
if (_progressDialog != null)
{
_progressDialog.dismiss();
_progressDialog = null;
}
}
protected void _showAlertDialog(final String message, final String title, final String buttonLabel){
AlertDialog.Builder dlg = new AlertDialog.Builder(_ctx);
dlg.setMessage(message);
dlg.setTitle(title);
dlg.setCancelable(false);
dlg.setPositiveButton(buttonLabel,
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
dlg.create();
dlg.show();
}
protected Cursor _checkMedia() {
_dbHelper.openDatabase(_destination.getAbsolutePath());
Log.d("DownloadHelper", "Database is opened");
String[] columns = {"type, size, location, location_id, url"};
Cursor cursor = _dbHelper.get("media", columns);
_dbHelper.closeDatabase();
_dbHelper.close();
_dbHelper = null;
return cursor;
}
protected long _download(String sUrl, File destination) throws IOException {
URL url = new URL(sUrl);
URLConnection conexion = url.openConnection();
conexion.connect();
// this will be useful so that you can show a tipical 0-100% progress bar
int lenghthOfFile = conexion.getContentLength();
Log.d("DownloadHelper", "length of File = " + lenghthOfFile);
// downlod the file
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(destination);
byte data[] = new byte[1024];
long total = 0;
int count;
// Reset the progress
_progressDialog.setProgress(0);
// Start downloading main test file
while ((count = input.read(data)) != -1 && running) {
total += count;
Log.d("DownloadHelper", "total = " + total);
// publishing the progress....
this.publishProgress((int)(total*100/lenghthOfFile));
output.write(data, 0, count);
}
if (running == false)
{
this.cancel(true);
}
output.flush();
output.close();
input.close();
return total;
}
}
我还在 onProgressUpdate() 中添加了一条 Log.d 消息,调试消息会显示,直到进度达到 6% 或 7%,然后控制台中不再出现任何内容(但应用程序仍然可以工作,因为我没有收到任何错误消息,并且Gabrage Collector 的消息仍然显示在控制台中)。
这是我的代码
有人遇到问题吗?
已编辑
根据 DArkO 的建议,我将缓冲区大小更改为 1MB,但仍然不起作用。我认为我的 while 循环有问题。我在 while 循环中使用 log.d ,并在控制台中有一些类似的内容:
D/DownloadHelper( 1666): length = **3763782**; total = 77356; percent = 2; save_percent = 0
D/DownloadHelper( 1666): UPDATED progess = 2
D/DownloadHelper( 1666): length = 3763782; total = 230320; percent = 6; save_percent = 0
D/DownloadHelper( 1666): UPDATED progess = 6
D/dalvikvm( 1666): GC freed 10241 objects / 1087168 bytes in 88ms
*D/DownloadHelper( 1666): FINISHED result = **230320***
“FINISHED message”来自 onPostExecute()。进度对话框停止后 1.2 分钟后出现此消息。如您所见,文件未完全下载。
我用 Eclipse 的调试工具调试我的应用程序,我可以看到 asynctask 线程挂在这个函数上
OSNetworkSystem.receiveStreamImpl(FileDescriptor, byte[], int, int, int) line: not available [native method]
I have a strangle behavior when implementing AsynTask and ProgressDialog. When i download small file, everything works fine, the progress status is updated from 0% to 100%. But when i download larger files, the number on ProgressDialog runs to 6 or 7% then it is not updated anymore. But after 2,3 minutes, i receive a messge that asyntask task finished the downloading process.
public class DownloadHelper extends AsyncTask<String, Integer, Long> implements DialogInterface.OnDismissListener{
private volatile boolean running = true;
private PhonegapActivity _ctx = null;
private ProgressDialog _progressDialog = null;
private String _title = null;
private File _root = null;
private File _destination = null;
private DatabaseHelper _dbHelper = null;
private Cursor _cursorMedia = null;
public DownloadHelper(String title, File root, File destination, DatabaseHelper dbHelper, PhonegapActivity ctx){
_title = title;
_ctx = ctx;
_root = root;
_destination = destination;
_dbHelper = dbHelper;
}
@Override
protected void onPreExecute() {
if (_progressDialog != null)
{
_progressDialog.dismiss();
_progressDialog = null;
}
_progressDialog = new ProgressDialog(_ctx);
_progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
_progressDialog.setTitle("Downloading");
_progressDialog.setMessage(_title);
_progressDialog.setCancelable(true);
_progressDialog.setMax(100);
_progressDialog.setProgress(0);
/*_progressDialog.setOnCancelListener(
new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
_progressDialog = null;
running = false;
}
});
_progressDialog.setOnDismissListener(
new DialogInterface.OnDismissListener() {
public void onDismiss(DialogInterface dialog) {
Log.d("DownloadHelper", "canceled inside listener");
_progressDialog = null;
running = false;
}
}
);*/
_progressDialog.show();
running = true;
}
@Override
protected Long doInBackground(String... sUrl) {
try {
Log.d("DownloadHelper", "Start download from url " + sUrl[0]);
long total = 0;
total = _download(sUrl[0], _destination);
return total;
} catch (Exception ex2) {
ex2.printStackTrace();
Log.d("DownloadHelper", "Failed to download test file from " + sUrl[0] + " to " + _destination.getAbsolutePath().toString());
_closeProgressDialog();
}
return null;
}
protected void onCancelled(Long result) {
Log.d("DownloadHelper", "CANCELLED result = " + result);
_closeProgressDialog();
}
protected void onProgressUpdate(Integer... progress) {
if (_progressDialog != null && running)
{
Log.d("DownloadHelper", "UPDATED progess = " + progress[0]);
_progressDialog.setProgress(progress[0]);
}
else //cancel the task
{
Log.d("DownloadHelper", "onProgressUpdate cancelled");
cancel(true);
}
}
protected void onPostExecute(Long result) {
Log.d("DownloadHelper", "FINISHED result = " + result);
// Close the ProgressDialog
_closeProgressDialog();
running = false;
if (result != null) //OK
{
_showAlertDialog("Test has been downloaded successfully.", "Message", "OK");
}
else // error
{
_showAlertDialog("Can not download the test. Please try again later.", "Error", "OK");
}
}
@Override
protected void onCancelled() {
running = false;
}
public void onDismiss(DialogInterface dialog) {
Log.d("DownloadHelper", "Cancelled");
this.cancel(true);
}
protected void _closeProgressDialog(){
if (_progressDialog != null)
{
_progressDialog.dismiss();
_progressDialog = null;
}
}
protected void _showAlertDialog(final String message, final String title, final String buttonLabel){
AlertDialog.Builder dlg = new AlertDialog.Builder(_ctx);
dlg.setMessage(message);
dlg.setTitle(title);
dlg.setCancelable(false);
dlg.setPositiveButton(buttonLabel,
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
dlg.create();
dlg.show();
}
protected Cursor _checkMedia() {
_dbHelper.openDatabase(_destination.getAbsolutePath());
Log.d("DownloadHelper", "Database is opened");
String[] columns = {"type, size, location, location_id, url"};
Cursor cursor = _dbHelper.get("media", columns);
_dbHelper.closeDatabase();
_dbHelper.close();
_dbHelper = null;
return cursor;
}
protected long _download(String sUrl, File destination) throws IOException {
URL url = new URL(sUrl);
URLConnection conexion = url.openConnection();
conexion.connect();
// this will be useful so that you can show a tipical 0-100% progress bar
int lenghthOfFile = conexion.getContentLength();
Log.d("DownloadHelper", "length of File = " + lenghthOfFile);
// downlod the file
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(destination);
byte data[] = new byte[1024];
long total = 0;
int count;
// Reset the progress
_progressDialog.setProgress(0);
// Start downloading main test file
while ((count = input.read(data)) != -1 && running) {
total += count;
Log.d("DownloadHelper", "total = " + total);
// publishing the progress....
this.publishProgress((int)(total*100/lenghthOfFile));
output.write(data, 0, count);
}
if (running == false)
{
this.cancel(true);
}
output.flush();
output.close();
input.close();
return total;
}
}
I also add a Log.d message inside onProgressUpdate(), the debug messages show until the progress reaches 6 or 7% then nothing comes out anymore in the console (but the app still works because i don't receive any error messages and the message of Gabrage Collector still shows in the console).
Here is my code
Does anyone have the some problems?
Edited
I changed the buffer size to 1MB as suggestion of DArkO, but it still doesn't work. I think something is wrong with my while loop. I use log.d inside my while loop and have some like this in console:
D/DownloadHelper( 1666): length = **3763782**; total = 77356; percent = 2; save_percent = 0
D/DownloadHelper( 1666): UPDATED progess = 2
D/DownloadHelper( 1666): length = 3763782; total = 230320; percent = 6; save_percent = 0
D/DownloadHelper( 1666): UPDATED progess = 6
D/dalvikvm( 1666): GC freed 10241 objects / 1087168 bytes in 88ms
*D/DownloadHelper( 1666): FINISHED result = **230320***
The "FINISHED message" comes from onPostExecute(). This message came 1,2 minutes later after the progress dialog had stopped. As you can see the file is not downloaded completely.
I debug the my app with debug tool of eclipse, i can see that the asynctask thread hangs at this function
OSNetworkSystem.receiveStreamImpl(FileDescriptor, byte[], int, int, int) line: not available [native method]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你更新得太频繁了,它无法及时显示更新,并且会阻塞 ui 线程。
考虑使用带有 postDelayed 的处理程序来发送一次publishProgress更新,可能每秒或每两秒。
或者您可以增加缓冲区大小,这样循环就不会经常发生,现在您有1024字节,所以可能是半MB或类似的东西,但我仍然会使用处理程序方法。这样您的更新和内存消耗就不会依赖于更新进度。
编辑:
这是我在我的项目之一中使用的下载文件的代码。我已经用相当大的文件(50 到 100 MB 之间)对此进行了测试,所以它绝对有效。尝试一下。
您会注意到我使用通知栏而不是进度栏来进行更新,但其余部分应该是相同的。
you are updating it too often it cant display the updates in time and it blocks the ui thread.
consider using a handler with postDelayed to send a publishProgress update maybe every second or 2.
or alternatevely you can increase the buffer size so the loop isnt happening that often, right now you have it on 1024 bytes so maybe half a MB or something like that, but i would still go with the handler method instead. that way your updates and memory consumption doesnt depend on the progress updates.
EDIT:
here is the code i was using for one of my projects to download files. i have tested this with quite large files (between 50 and 100 mb) so it is definitely working. try it out.
you will notice i am using the notification's bar to do the updates instead of a progress bar but the rest should be the same.
我同意更新发生得太频繁,但我可能不会使用处理程序对象来发布进度,而是使用一些简单的整数数学来编写如下内容。
它使用预先计算的tickSize(实际上是您想要显示进度更新的总大小的百分比),然后使用一些计算量不太大的简单整数除法来跟踪何时显示下一个进度(使用 2
int
而不是Handler
对象)。I agree that the updates are occurring too often, but instead of a handler object to publish progress I'd probably write it something like the following with a bit of simple integer maths.
It uses a precalculated tickSize (effectively the percent of the total size you want to show progress updates), and then tracks when to show next progress with a bit of simple integer division that isn't too compute heavy (uses 2
int
s instead of aHandler
object).