实现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, 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***
“完成的消息”来自onPostExecute()。在进度对话框停止后1,2分钟后出现此消息。如您所见,文件未完全下载。
我使用eclipse的调试工具调试我的应用程序,我可以看到asynctask线程挂起此函数
OSNetworkSystem.receiveStreamImpl(FileDescriptor, byte[], int, int, int) line: not available [native method]
答案 0 :(得分:1)
您经常更新它无法及时显示更新并阻止ui线程。
考虑使用postDelayed处理程序来每隔一秒或2发送一次publishProgress更新。
或者你可以增加缓冲区大小,这样循环就不会经常发生,现在你有1024个字节,所以可能是半个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, 0, 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();
您会注意到我使用通知栏来进行更新而不是进度条,但其余部分应该相同。
答案 1 :(得分:0)
我同意更新过于频繁,但我没有用处理器对象来发布进度,我可能会用类似简单的整数数学来编写类似下面的东西。
它使用预先计算的tickSize(实际上是您希望显示进度更新的总大小的百分比),然后跟踪何时显示下一个进度,其中一些简单的整数除法不会太大(使用2 { {1}}而不是int
对象。)
Handler