问题描述
||
在实现AsynTask和ProgressDialog时,我有一个扼杀行为。当我下载小文件时,一切正常,进度状态从0%更新为100%。但是,当我下载较大的文件时,ProgressDialog上的数字将达到6或7%,然后不再更新。但是,在2,3分钟后,我收到一条消息,表明asyntask任务已完成下载过程。
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,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***
\“完成消息\”来自onPostExecute()。进度对话框停止后的1,2分钟后,出现此消息。如您所见,文件未完全下载。
我使用eclipse的调试工具调试了我的应用程序,我可以看到asynctask线程挂在此函数上
OSNetworkSystem.receiveStreamImpl(FileDescriptor,byte[],int,int) line: not available [native method]
解决方法
您更新的频率太高,它无法及时显示更新,并且阻止了ui线程。
考虑使用带有postDelayed的处理程序来发送publishProgress更新,也许每秒或2。
或者,您可以增加缓冲区的大小,以使循环不会经常发生,现在,它具有1024个字节,因此可能只有0.5 MB或类似的大小,但是我仍然会使用处理程序方法。这样,您的更新和内存消耗就不会取决于进度更新。
编辑:
这是我用于我的项目之一的用于下载文件的代码。我已经用很大的文件(介于50和100 mb之间)测试了它,因此它肯定可以正常工作。试试看。
try {
// this is the file to be downloaded
final URL url = new URL(Url); // set the download URL,a url that
// points to a file on the internet
// create the new connection
final HttpURLConnection urlConnection = (HttpURLConnection) url
.openConnection();
// set up some things on the connection and connect!
urlConnection.setRequestMethod(\"GET\");
urlConnection.setDoOutput(true);
urlConnection.setConnectTimeout(4500); // Connection timeout in
// miliseconds
urlConnection.connect();
Log.i(TAG,\"Connected\");
// set the path where we want to save the file
// in this case on root directory of the
// sd card.
File directory = new File(Environment.getExternalStorageDirectory().getAbsoluteFile()+MUSIC_VIDEOS_PATH+artist);
// create a new file,specifying the path,and the filename
// which we want to save the file as.
directory.mkdirs(); // If we want to save the file in another
// directory on the SD card
// we need to make the directories if they dont exist.
// you can download to any type of file ex: (image),(text file),// (audio file)
Log.i(TAG,\"File Name:\" + filename);
final File file = new File(directory,filename);
if (file.createNewFile()) {
file.createNewFile();
}
// this will be used to write the downloaded data into the file we
// created
final FileOutputStream fileOutput = new FileOutputStream(file);
// this will be used in reading the data from the internet
final InputStream inputStream = urlConnection.getInputStream();
// this is the total size of the file
final int totalSize = urlConnection.getContentLength();
// variable to store total downloaded bytes
int downloadedSize = 0;
// a buffer
final byte[] buffer = new byte[1024*1024];
int bufferLength = 0; // used to store a temporary size of the
// buffer
int lastProgress = 0,progress = 0;
// now,read through the input buffer and write the contents to the
// file
while ((bufferLength = inputStream.read(buffer)) > 0) {
// add the data in the buffer to the file in the file output
// stream (the file on the sd card
fileOutput.write(buffer,bufferLength);
// add up the size so we know how much is downloaded
downloadedSize += bufferLength;
// this is where you would do something to report the prgress,// like this maybe
// Log.i(\"Progress:\",\"downloadedSize:\"+String.valueOf((int)((downloadedSize/(double)totalSize)*100))+\" % totalSize:\"+
// totalSize) ;
progress = (int) ((downloadedSize / (double) totalSize) * 100);
if (progress != lastProgress && progress % 10 == 0) {
notification.contentView.setProgressBar(R.id.ProgressBar01,100,progress,false);
// inform the progress bar of updates in progress
nm.notify(id,notification);
Log.i(TAG,String.valueOf(progress));
}
lastProgress = progress;
}
// close the output stream when done
fileOutput.flush();
fileOutput.close();
您会注意到我使用通知栏而不是进度栏来进行更新,但其余部分应该相同。
, 我同意更新的发生频率很高,但是我可能会使用一些简单的整数数学来编写类似以下内容的内容,而不是发布进度的处理程序对象。
它使用预先计算的tickSize(实际上是您想要显示进度更新的总大小的百分比),然后使用不太复杂的简单整数除法来跟踪何时显示下一个进度(使用2int
而不是一个Handler
对象)。
int lengthOfFile = conexion.getContentLength(); // note spelling :)
int tickSize = 2 * lengthOfFile / 100; // adjust to how often you want to update progress,this is 2%
int nextProgress = tickSize;
// ...
while ((count = input.read(data)) != -1 && running) {
total += count;
if (total >= nextProgress) {
nextProgress = (total / tickSize + 1) * tickSize;
this.publishProgress((int)(total*100/lengthOfFile));
}
output.write(data,count);
}
// ...