2011-06-21 5 views
0

AsynTaskとProgressDialogを実装するときに私が首を絞めてしまいました。小さなファイルをダウンロードすると、すべて正常に動作し、進行状況は0%から100%に更新されます。しかし、大きなファイルをダウンロードすると、ProgressDialogの数字は6または7%になり、もう更新されません。しかし2,3分後、私はasyntaskタスクがダウンロードプロセスを終了するというメッセージを受け取ります。大きなファイルをダウンロードするときにAsynTaskが実行中にProgrressDialogがフリーズします

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のメッセージがコンソールに表示されます)。

ここに私のコードです

誰かに何か問題がありますか?

編集

私はダルコの提案として1メガバイトにバッファサイズを変更しましたが、それはまだ動作しません。私は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メッセージは、」onPostExecute(から来ています)。このメッセージは、進行ダイアログが停止してから1,2分後に表示されました。あなたが見ることができるように、ファイルは完全にダウンロードされていません。

私は日食のデバッグツールで私のアプリをデバッグ、私はあなたがあまりにも頻繁に、それは時間の更新とそのブロックに表示カント、それを更新している

OSNetworkSystem.receiveStreamImpl(FileDescriptor, byte[], int, int, int) line: not available [native method]  

答えて

1

この機能でasynctaskスレッドがハングアップしていることがわかりますUIスレッド。

ループありえないが、それほど頻繁に、今あなたが1024バイトでそれを持っていることが起こって、あなたがバッファサイズを増やすことができます多分毎秒または2

またはalternatevely publishProgressの更新を送信するためにpostDelayedとハンドラを使用することを検討して

多分半分のMBかそのようなものですが、私はまだハンドラメソッドを使うでしょう。あなたの更新とメモリ消費は進行状況の更新に依存しません。

EDIT:

ここでは、私はファイルをダウンロードするために私のプロジェクトの1のために使用したコードです。私は非常に大きなファイル(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(); 

通知バーを使用して、進行状況バーの代わりに更新を行いますが、残りは同じであることがわかります。

+0

私は1024バイトのバッファを使用することも非常に非効率的になることに同意します。 'lenghthOfFile'を使用して、ダウンロードするファイルのサイズに基づいて割り当てることを提案し、合計の20%または10%をバッファに割り当てることをお勧めします。これにより進捗状況の更新も遅くなります。 – Squonk

+0

あるいは、あなたが知っているように、「パーセント」(新しい変数)が1に増えるたびにアップデートを公開するだけです。 – dmon

+0

最初はパーセンテージについてです。つまり、新しいパーセンテージを計算し、比較し、保存する必要があります。進行状況の更新も非常に非効率的です。とバッファサイズについて私の意見は、あなたが固定サイズではなく、代わりに大きなサイズのファイルを考えているので、dinamicallyファイルサイズに調整する必要があることです(100 mbのようなメモリクラッシュ、 mbは10MBのバッファですが、メモリ不足の可能性もあります。私の経験では、0.5MBから1MBまではバッファサイズが大きいと言われています – DArkO

0

私は更新が頻繁に起こっていることに同意しますが、進捗状況を公開するハンドラオブジェクトの代わりに、単純な整数計算のビットを使って次のような記述をします。

事前計算されたtickSize(実際には進行状況の更新を表示する合計サイズの割合)を使用し、次の進捗を表示するタイミングを追跡します。 Handlerオブジェクトの代わりにintを使用します)。

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, 0, count); 
} 

// ... 
関連する問題