2013-12-13 86 views
1

我使用這個的AsyncTask救了我的圖像資源,SD卡:Android的 - 位圖保存到SD卡與determinated ProgressDialog

public class SaveImageAsync extends AsyncTask<String, String, String> { 

    private Context mContext; 

    int imageResourceID; 

    private ProgressDialog mProgressDialog; 

    public SaveImageAsync(Context context, int image) 
    { 
     mContext = context; 
     imageResourceID = image; 
    } 

    @Override 
    protected void onPreExecute() { 
     super.onPreExecute(); 
     mProgressDialog = new ProgressDialog(mContext); 
     mProgressDialog.setMessage("Saving Image to SD Card"); 
     mProgressDialog.setMax(100); 
     mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); 
     mProgressDialog.setIndeterminate(true); 
     mProgressDialog.setCancelable(false); 
     mProgressDialog.show(); 
    } 

    @SuppressLint("NewApi") 
    @Override 
    protected String doInBackground(String... filePath) { 
     try { 


      Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), imageResourceID); 

      ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
      bitmap.compress(CompressFormat.JPEG, 100, bos); 
      byte[] bitmapdata = bos.toByteArray(); 
      ByteArrayInputStream bis = new ByteArrayInputStream(bitmapdata); 

      int lenghtOfFile = bitmap.getByteCount(); 
      Log.d("LOG", "File Lenght = " + lenghtOfFile); 

      byte[] buffer = new byte[64]; 
      int len1 = 0; 
      long total = 0; 

      while ((len1 = bis.read(buffer)) > 0) { 
       total += len1; 
       publishProgress("" + (int) ((total * 100)/lenghtOfFile)); 
       bos.write(buffer, 0, len1); 
      } 
      bos.flush(); 
      bos.close(); 
      bitmap.recycle(); 
      bis.close(); 

      return getTempUri().getPath(); 
     } catch (Exception e) { 
      return null; 
     } 


    } 

    protected void onProgressUpdate(String... progress) { 
     mProgressDialog.setIndeterminate(false); 
     mProgressDialog.setProgress(Integer.parseInt(progress[0])); 
    } 

    @Override 
    protected void onPostExecute(String filename) { 
     // dismiss the dialog after the file was saved 
     try { 
      mProgressDialog.dismiss(); 
      mProgressDialog = null; 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    private Uri getTempUri() { 
     return Uri.fromFile(getTempFile()); 
    } 

    private File getTempFile() { 
     if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 

      File directory = new File(mContext.getExternalCacheDir().getPath()); 
      directory.mkdirs(); 
      File file = new File(directory , "temp.jpg"); 
      try { 
       file.createNewFile(); 
      } catch (IOException e) {} 
      return file; 
     } else { 
      return null; 
     } 
    } 
} 

而且我這個把它從我的活動:

new SaveImageAsync(this, R.drawable.my_image_resource).execute(); 

它工作正常,問題是bitmap.getByteCount();返回的位圖大小與保存文件的最終大小完全不同。過程完成時的結果是指示進度只有20%或更少。

有沒有什麼辦法在保存之前知道文件的最終大小?謝謝。

回答

3

感謝巴斯基回答,bitmapdata.length;正是我所需要的,這是我AsyncTask爲節省bitmap到SD卡Determinated ProgressBar,我希望有人會發現它有用:

public class SaveImageAsync extends AsyncTask<Void, String, Void> { 

    private Context mContext; 
    private int imageResourceID; 

    private ProgressDialog mProgressDialog; 

    public SaveImageAsync(Context context, int image) { 
     mContext = context; 
     imageResourceID = image; 
    } 

    @Override 
    protected void onPreExecute() { 
     super.onPreExecute(); 
     mProgressDialog = new ProgressDialog(mContext); 
     mProgressDialog.setMessage("Saving Image to SD Card"); 
     mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); 
     mProgressDialog.setIndeterminate(true); 
     mProgressDialog.setCancelable(false); 
     mProgressDialog.show(); 
    } 

    @Override 
    protected Void doInBackground(Void... filePath) { 
     try { 
      Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), imageResourceID); 

      ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(); 
      bitmap.compress(CompressFormat.JPEG, 100, byteOutputStream); 
      byte[] mbitmapdata = byteOutputStream.toByteArray(); 
      ByteArrayInputStream inputStream = new ByteArrayInputStream(mbitmapdata); 

      String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath(); 
      String fileName = "mySavedImage.jpg"; 

      OutputStream outputStream = new FileOutputStream(baseDir + File.separator + fileName); 
      byteOutputStream.writeTo(outputStream); 

      byte[] buffer = new byte[128]; //Use 1024 for better performance 
      int lenghtOfFile = mbitmapdata.length; 
      int totalWritten = 0; 
      int bufferedBytes = 0; 

      while ((bufferedBytes = inputStream.read(buffer)) > 0) { 
       totalWritten += bufferedBytes; 
       publishProgress(Integer.toString((int) ((totalWritten * 100)/lenghtOfFile))); 
       outputStream.write(buffer, 0, bufferedBytes); 
      } 

     } catch (IOException e) { e.printStackTrace(); } 
     return null; 

    } 

    protected void onProgressUpdate(String... progress) { 
     mProgressDialog.setIndeterminate(false); 
     mProgressDialog.setProgress(Integer.parseInt(progress[0])); 
    } 

    @Override 
    protected void onPostExecute(Void filename) { 
     mProgressDialog.dismiss(); 
     mProgressDialog = null; 
    } 
} 

使用此行您Activity保存圖像:

new SaveImageAsync(this, R.drawable.your_image_resource).execute(); 
+0

我可以問......當你沒有在代碼中使用'filePath'時,爲什麼使用'(Void ... filePath)'?它是否使無效,可以說,'doInBackground()'參數?我試圖也保存一個文件,並想知道我是否需要一個AsyncTask來釋放主線程,但使用他們推薦的'(String ... params)'不適用於我,因爲我只有一個文件'一次保存(不是整個陣列)。但不知道如何使用可以工作的東西。謝謝,如果你知道。 – Azurespot

3

您可以使用PNG壓縮以及壓縮的效果取決於圖像的實際內容,即只包含空白區域的空白圖像尺寸較小,所有像素不同的彩色圖像的尺寸都很大。這麼長的故事... bitmap.getByteCount()爲您提供了多少字節將用於存儲實際圖像在內存(未壓縮),而不是在SD卡(壓縮)。你的期望和你真正得到的結果之間的區別解釋了〜20%的突破點。

如果我猜測一個解決方案可能是使用bitmapdata數組的長度。我修改您的代碼:

Bitmap bitmap = null; 

ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
bitmap.compress(CompressFormat.JPEG, 100, bos); 
byte[] bitmapdata = bos.toByteArray(); 
ByteArrayInputStream bis = new ByteArrayInputStream(bitmapdata); 

int lenghtOfFile = bitmapdata.length; 
byte[] buffer = new byte[64]; 
int currentProcess = 0; 
int totalReadedYet = 0; 

try { 
while ((currentProcess = bis.read(buffer)) > 0) { 
    totalReadedYet += currentProcess; 
    publishProgress(Integer.toString((int) ((totalReadedYet)/lenghtOfFile))); 
    bos.write(buffer, 0, currentProcess); 
} 

bos.flush(); 
bos.close(); 
bitmap.recycle(); 
bis.close(); 
} catch (IOException e) { 
    e.printStackTrace(); 
} 
+0

我知道,爲此我要求的方式來了解網絡文件的最終大小。 –

+1

我編輯了我的答案。 – Baschi

+0

謝謝,'bitmapdata.length;'正是我所期待的。 –