在下载大文件时AsyncTask仍在运行时ProgressDialog冻结

时间:2011-06-21 19:26:25

标签: android cordova android-asynctask freeze progressdialog

实现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]    

2 个答案:

答案 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