? ? ? ?使用相機intent,我們就可以成功拍攝現場照片并保存了。
? ? ? ?有了照片,接下來就是找到并加載它,然后展示給用戶看。在南昌APP開發的技術實現上,這需要加載照片到大小合適的Bitmap對象中。要從文件生成Bitmap對象,我們需要BitmapFactory類:
? ? ? ?Bitmap bitmap = BitmapFactory.decodeFile(mPhotoFile.getPath());
? ? ? ?看到這里,有沒有感覺不對勁?肯定有的。問題在于:介紹Bitmap時,我們提到“大小合適”。Bitmap是個簡單對象,它只存儲實際像素數據。也就是說,即使原始照片已壓縮過,但存入Bitmap對象時,文件并不會同樣壓縮。因此,16萬像素24位已壓縮為5Mb大小的JPG照片文件,一旦載入Bitmap對象,就會立即膨脹至48Mb大小!
? ? ? ?這其實個問題是可以設法解決的,但需要手工縮放位圖照片。具體做法就是,首先確認文件到底有多大,然后考慮按照給定區域大小合理縮放文件。最后,重新讀取縮放后的文件,創建Bitmap對象。
? ? ? ?創建名為PictureUtils.java的新類,并在其中添加getScaledBitmap(String, int, int)縮放方法,如下代碼清單所示。
? ? ? ?創建getScaledBitmap(...)方法(PictureUtils.java)
? ? ? ?public class PictureUtils {
? ? ? ?public static Bitmap getScaledBitmap(String path, int destWidth, int destHeight) {
? ? ? ?// Read in the dimensions of the image on disk
? ? ? ?BitmapFactory.Options options = new BitmapFactory.Options();
? ? ? ?options.inJustDecodeBounds = true;
? ? ? ?BitmapFactory.decodeFile(path, options);
? ? ? ?float srcWidth = options.outWidth;
? ? ? ?float srcHeight = options.outHeight;
?
? ? ? ?// Figure out how much to scale down by
? ? ? ?int inSampleSize = 1;
? ? ? ?if (srcHeight > destHeight || srcWidth > destWidth) {
? ? ? ?if (srcWidth > srcHeight) {
? ? ? ?inSampleSize = Math.round(srcHeight / destHeight);
? ? ? ?} else {
? ? ? ?inSampleSize = Math.round(srcWidth / destWidth);
? ? ? ?}
? ? ? ?}
? ? ? ?options = new BitmapFactory.Options();
? ? ? ?options.inSampleSize = inSampleSize;
? ? ? ?// Read in and create final bitmap
? ? ? ?return BitmapFactory.decodeFile(path, options);
? ? ? ?}
? ? ? ?}?
? ? ? ?上述方法中,inSampleSize值很關鍵。它決定著縮略圖像素的大小。假設這個值是1的話,就表明縮略圖和原始照片的水平像素大小一樣。如果是2的話,它們的水平像素比就是1∶2。因此,inSampleSize值為2時,縮略圖的像素數就是原始文件的四分之一。
? ? ? ?問題總是接踵而來,解決了縮放問題,又冒出了新問題:fragment剛啟動時,PhotoView
? ? ? ?究竟有多大無人知道。onCreate(...)、onStart()和onResume()方法啟動后,才會有實例化布局出現。也就在此時,顯示在屏幕上的視圖才會有大小尺寸。這也是出現新問題的原因。
? ? ? ?解決方案有兩個:要么等布局實例化完成并顯示,要么干脆使用保守估算值。特定條件下,盡管估算比較主觀,但確實是一個切實可行的辦法。再添加一個getScaledBitmap(String,Activity)靜態Bitmap估算方法,如下代碼所示。
? ? ? ?編寫合理的縮放方法(PictureUtils.java)
? ? ? ?public class PictureUtils {
? ? ? ?public static Bitmap getScaledBitmap(String path, Activity activity) {
? ? ? ?Point size = new Point();
? ? ? ?activity.getWindowManager().getDefaultDisplay()
? ? ? ?.getSize(size);
? ? ? ?return getScaledBitmap(path, size.x, size.y);
? ? ? ?}
? ? ? ?...?
? ? ? ?該方法先確認屏幕的尺寸,然后按此縮放圖像。這樣,就能保證載入的ImageView永遠不會過大。看到沒有,無論如何,這是一個比較保守的估算有時就是能解決問題。
? ? ? ?接下來,為把Bitmap載入ImageView。在CrimeFragment.java中,添加刷新mPhotoView的方法,如下代碼清單所示。
? ? ? ?更新mPhotoView(CrimeFragment.java)
? ? ? ?...
? ? ? ?private String getCrimeReport() {
? ? ? ?...
? ? ? ?}
? ? ? ?private void updatePhotoView() {
? ? ? ?if (mPhotoFile == null || !mPhotoFile.exists()) {
? ? ? ?mPhotoView.setImageDrawable(null);
? ? ? ?} else {
? ? ? ?Bitmap bitmap = PictureUtils.getScaledBitmap(
? ? ? ?mPhotoFile.getPath(), getActivity());
? ? ? ?mPhotoView.setImageBitmap(bitmap);
? ? ? ?}
? ? ? ?}
? ? ? ?}?
? ? ? ?然后,分別在onCreateView(...)和onActivityResult(...)方法中調用updatePhotoView()
? ? ? ?方法,如下代碼清單所示。
? ? ? ?調用updatePhotoView()方法(CrimeFragment.java)
? ? ? ?mPhotoButton.setOnClickListener(new View.OnClickListener() {
? ? ? ?@Override
? ? ? ?public void onClick(View v) {
? ? ? ?startActivityForResult(captureImage, REQUEST_PHOTO);
? ? ? ?}
? ? ? ?});
? ? ? ?mPhotoView = (ImageView) v.findViewById(R.id.crime_photo);
? ? ? ?updatePhotoView();
? ? ? ?return v;
? ? ? ?}
? ? ? ?@Override
? ? ? ?public void onActivityResult(int requestCode, int resultCode, Intent data) {
? ? ? ?if (resultCode != Activity.RESULT_OK) {
? ? ? ?return;
? ? ? ?}
? ? ? ?if (requestCode == REQUEST_DATE) {
? ? ? ?...
? ? ? ?} else if (requestCode == REQUEST_CONTACT && data != null) {
? ? ? ?...
? ? ? ?} else if (requestCode == REQUEST_PHOTO) {
? ? ? ?updatePhotoView();
? ? ? ?}
? ? ? ?}?
? ? ? ?再次運行應用,這樣就可以看到已拍照片的縮略圖了。