記錄最近遇到的多個Fragment界面重疊和調用系統相機拍照閃退問題,同時總結解決方案。html
----------------------------------------------------------------------------------------------------------------------------------------------------------------android
環境:Activity(一個)+Fragment(多個)ide
問題一:多個fragment出現重疊現象函數
首先,Android管理Fragment有兩種方式,使用add、hide、show的方式和replace方式,兩種方式各有優缺點。工具
--> replace方式
若是使用這種方式,是能夠避免重疊的問題,可是每次replace會把生命週期所有執行一遍,若是在這些生命週期函數里拉取數據的話,就會不斷重複的加載刷新數據,因此咱們並不推薦使用這種方式。post
--> add、hide、show的方式
雖然這種方式避免了可能重複加載刷新數據的問題,可是會出現重疊的問題。測試
緣由:.net
當系統內存不足,Fragment 的宿主 Activity 回收的時候,Fragment 的實例並無隨之被回收。Activity 被系統回收時,會主動調用 onSaveInstance() 方法來保存視圖層(View Hierarchy),因此當 Activity 經過導航再次被重建時,以前被實例化過的 Fragment 依然會出如今 Activity 中,此時的 FragmentTransaction 中的至關於又再次 add 了 fragment 進去的,hide()和show()方法對以前保存的fragment已經失效了,因此就出現了重疊。
然而咱們仍是推薦使用這個,咱們能夠解決。code
解決方法:MainActivity.Class中重寫onAttachFragment,從新讓新的Fragment指向了本來未被銷燬的fragment,它就是onAttach方法對應的Fragment對象orm
@Override public void onAttachFragment(Fragment fragment) { if (tab1 == null && fragment instanceof Tab1Fragment) tab1 = fragment; if (tab2 == null && fragment instanceof Tab2Fragment) tab2 = fragment; if (tab3 == null && fragment instanceof Tab3Fragment) tab3 = fragment; if (tab4 == null && fragment instanceof Tab4Fragment) tab4 = fragment; }
問題二:調用系統相機拍照閃退
在onActivityResult方法裏經過Intent的getData方法獲取的數據轉換成bitmap並顯示在界面上,有時候會有取不到數據,或者顯示的bitmap會很是小,若是將bitmap保存到sd卡後會發現,圖片的分辨率很低,而且圖片大小也是通過壓縮的,無論將相機的像素設置多高,最後經過這種方式返回的bitmap老是通過壓縮了的。若是想得到理想的照片大小和分辨率改如何處理呢?如下是個人處理方法,雖然不是最好,可是幫我解決了這個需求。我先來簡述一下爲何返回的圖片是通過了壓縮的。
你們都知道,如今手機像素少則500W或800W,多則4KW(某亞),就拿常見的800W像素的相機拍出來的照片來講,分辨率大概在3200*2400左右,個人測試機型是LG optimus 2x,2.3.7的系統,用800W像素拍出來大概就是這個分辨率,照片大小在2M左右。試想一下,在Android系統中最經常使用的Bitmap格式(ARGB_8888)一個像素佔用4byte(字節),例如一張分辨率爲3200*2400px的照片,其耗用內存狀況是:3200*2400*4/1024/1024=29.296875(MB)。若是爲了一張圖片,耗用這麼大的內存,確定是不合理的,而且,官方文檔中有說明,Android系統分配給每一個應用的最大內存是16M,因此,系統爲了防止應用內存佔用過大,對於在應用內經過相機拍攝的圖片最終返回來的結果進行了壓縮,壓縮後的圖片變得很小,經過以前說的getData的方式只能知足好比顯示個頭像這樣的需求,若是要顯示大圖,就會出現模糊的狀況。如何得到清晰的大圖,思路以下:
1.拍照時,將拍得的照片先保存在本地,其中啓動相機程序以下;
Intent getImageByCameraIntent = new Intent("android.media.action.IMAGE_CAPTURE"); Uri imageUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "image.jpg")); getImageByCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); startActivityForResult(getImageByCameraIntent, TAKE_PHOTO);
2.在onActivityResult方法中再將圖片取出,並通過縮小處理再顯示在界面上或保存在自定義文件夾下,其中壓縮比例自定義;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { switch (requestCode) { case TAKE_PICTURE: //將保存在本地的圖片取出並縮小後顯示在界面上 Bitmap bitmap = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory()+"/image.jpg"); Bitmap newBitmap = ImageTools.zoomBitmap(bitmap, bitmap.getWidth() / SCALE, bitmap.getHeight() / SCALE); //因爲Bitmap內存佔用較大,這裏須要回收內存,不然會報out of memory異常 bitmap.recycle(); //將處理過的圖片顯示在界面上,並保存到本地 //取當前時間爲照片名 String imageName= DateFormat.format("yyyyMMdd_hhmmss",Calendar.getInstance(Locale.CHINA))+".png"; ImageTools.savePhotoToSDCard(newBitmap, getPhotoPath(), imageName); break; default: break; } } }
其中ImageTools是自定義的圖片工具類,zoomBitmap()和savePhotoToSDCard()方法具體以下:
/** * Resize the bitmap * * @param bitmap * @param width * @param height * @return */ public static Bitmap zoomBitmap(Bitmap bitmap, int width, int height) { int w = bitmap.getWidth(); int h = bitmap.getHeight(); Matrix matrix = new Matrix(); float scaleWidth = ((float) width / w); float scaleHeight = ((float) height / h); matrix.postScale(scaleWidth, scaleHeight); Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true); return newbmp; } /** * Save image to the SD card * @param photoBitmap * @param photoName * @param path */ public static void savePhotoToSDCard(Bitmap photoBitmap,String path,String photoName){ if (checkSDCardAvailable()) { File dir = new File(path); if (!dir.exists()){ dir.mkdirs(); } File photoFile = new File(path , photoName ); FileOutputStream fileOutputStream = null; try { fileOutputStream = new FileOutputStream(photoFile); if (photoBitmap != null) { if (photoBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream)) { fileOutputStream.flush(); } } } catch (FileNotFoundException e) { photoFile.delete(); e.printStackTrace(); } catch (IOException e) { photoFile.delete(); e.printStackTrace(); } finally{ try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
說明:因爲Android給bitmap分配的內存最大不超過8M,因此對使用完的較大的Bitmap要釋放內存,調用其recycle()方法便可。而後將縮小(縮小方法在Demo源碼中有)後的bitmap顯示在界面上或保存到SD卡,至於以前保存的原圖,能夠刪掉,也能夠放在那,下次拍照時,這張原圖就會被下一張照片覆蓋,因此SD卡上使用只有一張臨時圖片,佔用也不是很大。
---------------------------------------------------------------------------------------------------------------------------------
參考資料:
http://blog.csdn.net/whitley_gong/article/details/51987911 //關於Fragment重疊問題分析和解決
https://m.th7.cn/show/14/201612/1045726.html //android系統相機的使用、及解決拍照閃退的問題
http://m.blog.csdn.net/article/details?id=8654137 //Android相機、相冊獲取圖片顯示並保存到SD卡