MIUI 系統(tǒng) BUG,Android 調(diào)用相機(jī)崩潰?將拍照適配方案進(jìn)行到底!

寫在前面

昨天也是為大家分享了 7.0 相機(jī)適配,今天就來為大家講講 Android 之相機(jī)適配。

提起 Android 調(diào)用系統(tǒng)相機(jī)拍照上傳圖片或者是顯示圖片,想必任何一位開發(fā) Android 的朋友都不會(huì)陌生,基本這個(gè)功能已經(jīng)涵蓋各個(gè)應(yīng)用了,今天,我就來給大家聊聊網(wǎng)上并不多見卻有經(jīng)常聽到大家吐槽的問題。

根據(jù)相機(jī)適配對圖片的操作,所以有了這款圖片壓縮庫:[https://github.com/nanchen2251/CompressHelper

拍照功能實(shí)現(xiàn)

對于拍照功能的實(shí)現(xiàn)方式我這里就不多談了,無非兩種,一種是利用相機(jī)的 API 來自定義相機(jī),另一種是利用 Intent 調(diào)用系統(tǒng)指定的相機(jī)拍照。而這兩種方式的實(shí)現(xiàn)網(wǎng)上搜索一大把,我就不在這里啰嗦了。

有沒有相機(jī)可用?

前面講到我們是調(diào)用系統(tǒng)指定的相機(jī) APP 來拍照,那么系統(tǒng)是否存在可以被我們調(diào)用的 APP 呢?這個(gè)我們不敢確定,畢竟 Android 奇葩問題多,還真有遇到過這種極端的情況導(dǎo)致閃退的。雖然很極端,但作為客戶端人員還是要進(jìn)行處理,方式有二:

  • 調(diào)用相機(jī)時(shí),簡單粗暴的 try-catch
  • 調(diào)用相機(jī)前,檢測系統(tǒng)有沒有相機(jī) APP 可用

try-catch 這種粗暴的方式大家肯定很熟悉了,那么要如何檢測系統(tǒng)有沒有相機(jī) APP 可用呢?系統(tǒng)在 PackageManager 里為我們提供這樣一個(gè) API:


通過這樣一個(gè) API ,可以知道系統(tǒng)是否存在 Action 為 MediaStore.ACTION_IMAGE_CAPTURE 的 Intent 可以喚起的拍照界面,具體實(shí)現(xiàn)代碼如下:

/**
     * 判斷系統(tǒng)中是否存在可以啟動(dòng)的相機(jī)應(yīng)用
     *
     * @return 存在返回true,不存在返回false
     */
    public boolean hasCamera() {
        PackageManager packageManager = mActivity.getPackageManager();
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
        return list.size() > 0;
    }

拍出來的照片“歪了”!!!

經(jīng)常會(huì)遇到一種情況,拍照時(shí)看到照片是正的,但是當(dāng)我們的 APP 獲取到這張照片時(shí),卻發(fā)現(xiàn)旋轉(zhuǎn)了 90 度(也有可能是 180、270,不過 90 度比較多見,貌似都是由于手機(jī)傳感器導(dǎo)致的)。很多童鞋對此感到很困擾,因?yàn)椴皇撬惺謾C(jī)都會(huì)出現(xiàn)這種情況,就算會(huì)是出現(xiàn)這種情況的手機(jī)上,也并非每次必現(xiàn)。要怎么解決這個(gè)問題呢?從解決的思路上看,只要獲取到照片旋轉(zhuǎn)的角度,利用 Matrix 來進(jìn)行角度糾正即可。那么問題來了,要怎么知道照片旋轉(zhuǎn)的角度呢?細(xì)心的童鞋可能會(huì)發(fā)現(xiàn),拍完一張照片去到相冊點(diǎn)擊屬性查看,能看到下面這樣一堆關(guān)于照片的屬性數(shù)據(jù)。


沒錯(cuò),這里面就有一個(gè)旋轉(zhuǎn)角度,倘若拍照后保存的成像照片文件發(fā)生了角度旋轉(zhuǎn),這個(gè)圖片的屬性參數(shù)就能告訴我們到底旋轉(zhuǎn)了多少度。只要獲取到這個(gè)角度值,我們就能進(jìn)行糾正的工作了。 Android 系統(tǒng)提供了 ExifInterface 類來滿足獲取圖片各個(gè)屬性的操作。

通過 ExifInterface 類拿到 TAG_ORIENTATION 屬性對應(yīng)的值,即為我們想要得到旋轉(zhuǎn)角度。再根據(jù)利用 Matrix 進(jìn)行旋轉(zhuǎn)糾正即可。實(shí)現(xiàn)代碼大致如下:

/**
     * 獲取圖片的旋轉(zhuǎn)角度
     *
     * @param path 圖片絕對路徑
     * @return 圖片的旋轉(zhuǎn)角度
     */
    public static int getBitmapDegree(String path) {
        int degree = 0;
        try {
            // 從指定路徑下讀取圖片,并獲取其EXIF信息
            ExifInterface exifInterface = new ExifInterface(path);
            // 獲取圖片的旋轉(zhuǎn)信息
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    /**
     * 將圖片按照指定的角度進(jìn)行旋轉(zhuǎn)
     *
     * @param bitmap 需要旋轉(zhuǎn)的圖片
     * @param degree 指定的旋轉(zhuǎn)角度
     * @return 旋轉(zhuǎn)后的圖片
     */
    public static Bitmap rotateBitmapByDegree(Bitmap bitmap, int degree) {
        // 根據(jù)旋轉(zhuǎn)角度,生成旋轉(zhuǎn)矩陣
        Matrix matrix = new Matrix();
        matrix.postRotate(degree);
        // 將原始圖片按照旋轉(zhuǎn)矩陣進(jìn)行旋轉(zhuǎn),并得到新的圖片
        Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        if (bitmap != null && !bitmap.isRecycled()) {
            bitmap.recycle();
        }
        return newBitmap;
    }

ExifInterface 能拿到的信息遠(yuǎn)遠(yuǎn)不止旋轉(zhuǎn)角度,其他的參數(shù)感興趣的童鞋可以看看 API 文檔。

拍完照怎么閃退了?

曾在小米和魅族的某些機(jī)型上遇到過這樣的問題,調(diào)用系統(tǒng)相機(jī)拍照,拍完點(diǎn)擊確定回到自己的 APP 里面卻莫名奇妙的閃退了。這種閃退有兩個(gè)特點(diǎn):
沒有什么錯(cuò)誤日志(有些機(jī)子啥日志都沒有,有些機(jī)子會(huì)出來個(gè)空異常錯(cuò)誤日志);
同個(gè)機(jī)子上非必現(xiàn)(有時(shí)候怎么拍都不閃退,有時(shí)候一拍就閃退);

對待非必現(xiàn)問題往往比較頭疼,當(dāng)初遇到這樣的問題也是非常不解。上網(wǎng)搜羅了一圈也沒方案,后來留意到一個(gè)比較有意思信息:有些系統(tǒng)廠商的 ROM 會(huì)給自帶相機(jī)應(yīng)用做優(yōu)化,當(dāng)某個(gè) APP 通過 Intent 進(jìn)入相機(jī)拍照界面時(shí),系統(tǒng)會(huì)把這個(gè) APP 當(dāng)前最上層的 Activity 銷毀回收。(注意:我遇到的情況是有時(shí)候很快就回收掉,有時(shí)候怎么等也不回收,沒有什么必現(xiàn)規(guī)律)為了驗(yàn)證一下,便在啟動(dòng)相機(jī)的 Activity 中對 onDestory() 方法進(jìn)行加 Log 。果不其然,終于發(fā)現(xiàn)進(jìn)入拍照界面的時(shí)候 onDestory() 方法被執(zhí)行了。所以,前面提到的閃退基本可以推測是 Activity 被回收導(dǎo)致某些非UI控件的成員變量為空導(dǎo)致的。(有些機(jī)子會(huì)報(bào)出空異常錯(cuò)誤日志,但是有些機(jī)子閃退了什么都不報(bào),是不是覺得很奇葩!)
既然涉及到 Activity 被回收的問題,自然要想起 onSaveInstanceState()onRestoreInstanceState() 這對方法。去到 onSaveInstanceState() 把數(shù)據(jù)保存,并在 onRestoreInstanceState() 方法中進(jìn)行恢復(fù)即可。大體代碼思路如下:

@Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mRestorePhotoFile = mCapturePhotoHelper.getPhoto();
        if (mRestorePhotoFile != null) {
            outState.putSerializable(EXTRA_RESTORE_PHOTO, mRestorePhotoFile);
        }

    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        mRestorePhotoFile = (File) savedInstanceState.getSerializable(EXTRA_RESTORE_PHOTO);
        mCapturePhotoHelper.setPhoto(mRestorePhotoFile);
    }

對于 onSaveInstanceState()onRestoreInstanceState() 方法的作用還不熟悉的童鞋,網(wǎng)上資料很多,可以自行搜索。
到這里,可能有童鞋要問,這種閃退并不能保證復(fù)現(xiàn),我要怎么知道問題所在和是否修復(fù)了呢?我們可以去到開發(fā)者選項(xiàng)里開啟不保留活動(dòng)這一項(xiàng)進(jìn)行調(diào)試驗(yàn)證。


它的作用是保留當(dāng)前和用戶接觸的 Activity ,并將目前無法和用戶交互 Activity 進(jìn)行銷毀回收。打開這個(gè)調(diào)試選項(xiàng)就可以滿足驗(yàn)證的需求,當(dāng)你的 app 的某個(gè) Activity 跳轉(zhuǎn)到拍照的 Activity 后,這個(gè) Activity 立馬就會(huì)被系統(tǒng)銷毀回收,這樣就可以很好的完全復(fù)現(xiàn)閃退的場景,幫助開發(fā)者確認(rèn)問題有沒有修復(fù)了。
涉及到 Activity 被銷毀,還想提一下代碼實(shí)現(xiàn)上的問題。假設(shè)當(dāng)前有兩個(gè) Activity ,MainActivity 中有個(gè) Button ,點(diǎn)擊可以調(diào)用系統(tǒng)相機(jī)拍照并顯示到 PreviewActivity 進(jìn)行預(yù)覽。有下面兩種實(shí)現(xiàn)方案:

  • MainActivity 中點(diǎn)擊 Button 后,啟動(dòng)系統(tǒng)相機(jī)拍照,并在 MainActivity 的 onActivityResult() 方法中獲取拍下來的照片,并啟動(dòng)跳轉(zhuǎn)到 PreviewActivity 界面進(jìn)行效果預(yù)覽;
  • MainActivity 中點(diǎn)擊 Button 后,啟動(dòng) PreviewActivity 界面,在 PreviewActivity 的 onCreate()(或者 onStart()onResume())方法中啟動(dòng)系統(tǒng)相機(jī)拍照,然后在 PreviewActivity 的 onActivityResult() 方法中獲取拍下來的照片進(jìn)行預(yù)覽;

上面兩種方案得到的實(shí)現(xiàn)效果是一模一樣的,但是第二種方案卻存在很大的問題。因?yàn)閱?dòng)相機(jī)的代碼放在 onCreate()(或者 onStart()onResume())中,當(dāng)進(jìn)入拍照界面后,PreviewActivity 隨即被銷毀,拍完照確認(rèn)后回到 PreviewActivity 時(shí),被銷毀的 PreviewActivity 需要重建,又要走一遍 onCreate()onStart()onResume(),又調(diào)用了啟動(dòng)相機(jī)拍照的代碼,周而復(fù)始的進(jìn)入了死循環(huán)狀態(tài)。為了避免讓你的用戶抓狂,果斷明智的選擇方案一。
以上這種情況提到調(diào)用系統(tǒng)拍照時(shí),Activity 就回收的情況,在小米 4S 和小米 4 LTE 機(jī)子上(MIUI 的版本是 7.3,Android 系統(tǒng)版本是 6.0)出現(xiàn)的概率很高。 所以,建議看到此文的童鞋也可以去驗(yàn)證適配一下。

圖片無法顯示

圖片無法顯示這個(gè)問題也是略坑,如何坑法?往下看,同樣是在小米 4S 和小米 4 LTE 機(jī)子上(MIUI 的版本是 7.3,Android 系統(tǒng)版本是 6.0)出現(xiàn)概率很高的場景(當(dāng)然,不保證其他機(jī)子沒出現(xiàn)過)。按照我們前面提到的業(yè)務(wù)場景,調(diào)用相機(jī)拍照完成后,我們的 APP 會(huì)有一個(gè)預(yù)覽圖片的界面。但是在用了小米的機(jī)子進(jìn)行拍照后,自己 APP 的預(yù)覽界面卻怎么也無法顯示出照片來,同樣是相當(dāng)郁悶,郁悶完后還是要一步一步去排查解決問題的!為此,需要一步一步猜測驗(yàn)證問題所在。

  • 猜測一:沒有拿到照片路徑,所以無法顯示?
    直接斷點(diǎn)打 log 跟蹤,猜測一很快被推翻,路徑是有的。
  • 猜測二:Bitmap太大了,無法顯示?
    直接在 Android Studio 的 log 控制臺(tái)仔細(xì)的觀察了一下系統(tǒng) log ,發(fā)現(xiàn)了一些蛛絲馬跡
    OpenGLRenderer: Bitmap too large to be uploaded into a texture

每次拍完照片,都會(huì)出現(xiàn)上面這樣的 log ,果然,因?yàn)閳D片太大而導(dǎo)致在 ImageView 上無法顯示。到這里有童鞋要吐槽了,沒對圖片的采樣率 inSampleSize 做處理?天地良心啊,絕對做處理了,直接看代碼:

/**
    * 壓縮Bitmap的大小
    *
    * @param imagePath     圖片文件路徑
    * @param requestWidth  壓縮到想要的寬度
    * @param requestHeight 壓縮到想要的高度
    * @return
    */
   public static Bitmap decodeBitmapFromFile(String imagePath, int requestWidth, int requestHeight) {
       if (!TextUtils.isEmpty(imagePath)) {
           if (requestWidth <= 0 || requestHeight <= 0) {
               Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
               return bitmap;
           }
           BitmapFactory.Options options = new BitmapFactory.Options();
           options.inJustDecodeBounds = true;//不加載圖片到內(nèi)存,僅獲得圖片寬高
           BitmapFactory.decodeFile(imagePath, options);
           options.inSampleSize = calculateInSampleSize(options, requestWidth, requestHeight); //計(jì)算獲取新的采樣率
           options.inJustDecodeBounds = false;
           return BitmapFactory.decodeFile(imagePath, options);

       } else {
           return null;
       }
   }

   public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
       final int height = options.outHeight;
       final int width = options.outWidth;
       int inSampleSize = 1;
       Log.i(TAG, "height: " + height);
       Log.i(TAG, "width: " + width);
       if (height > reqHeight || width > reqWidth) {

           final int halfHeight = height / 2;
           final int halfWidth = width / 2;

           while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
               inSampleSize *= 2;
           }

           long totalPixels = width * height / inSampleSize;

           final long totalReqPixelsCap = reqWidth * reqHeight * 2;

           while (totalPixels > totalReqPixelsCap) {
               inSampleSize *= 2;
               totalPixels /= 2;
           }
       }
       return inSampleSize;
   }

瞄了代碼后,是不是覺得沒有問題了?沒錯(cuò),inSampleSize 確確實(shí)實(shí)經(jīng)過處理,那為什么圖片還是太大而顯示不出來呢? requestWidthrequestHeight 設(shè)置得太大導(dǎo)致 inSampleSize 太小了?不可能啊,我都試著把長寬都設(shè)置成 100 了還是沒法顯示!干脆,直接打印 inSampleSize 值,一打印,inSampleSize 值居然為 1 。 我去,徹底打臉了,明明說好的處理過了,居然還是 1 !!!!為了一探究竟,干脆加 log 。

public static Bitmap decodeBitmapFromFile(String imagePath, int requestWidth, int requestHeight) {
        if (!TextUtils.isEmpty(imagePath)) {
            Log.i(TAG, "requestWidth: " + requestWidth);
            Log.i(TAG, "requestHeight: " + requestHeight);
            if (requestWidth <= 0 || requestHeight <= 0) {
                Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
                return bitmap;
            }
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;//不加載圖片到內(nèi)存,僅獲得圖片寬高
            BitmapFactory.decodeFile(imagePath, options);
            Log.i(TAG, "original height: " + options.outHeight);
            Log.i(TAG, "original width: " + options.outWidth);
            options.inSampleSize = calculateInSampleSize(options, requestWidth, requestHeight); //計(jì)算獲取新的采樣率
            Log.i(TAG, "inSampleSize: " + options.inSampleSize);
            options.inJustDecodeBounds = false;
            return BitmapFactory.decodeFile(imagePath, options);

        } else {
            return null;
        }
    }

運(yùn)行打印出來的日志如下:


圖片原來的寬高居然都是 -1 ,真是奇葩了!難怪,inSampleSize 經(jīng)過處理之后結(jié)果還是 1 。狠狠的吐槽了之后,總是要回來解決問題的。那么,圖片的寬高信息都丟失了,我去哪里找啊? 像下面這樣?

public static Bitmap decodeBitmapFromFile(String imagePath, int requestWidth, int requestHeight) {
            ...
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;//不加載圖片到內(nèi)存,僅獲得圖片寬高
            Bitmap bitmap = BitmapFactory.decodeFile(imagePath, options);
            bitmap.getWidth();
            bitmap.getHeight();
            ...
        } else {
            return null;
        }
    }

no,此方案行不通,inJustDecodeBounds = true 時(shí),BitmapFactory 獲得 Bitmap 對象是 null;
那要怎樣才能獲圖片的寬高呢?前面提到的 ExifInterface 再次幫了我們大忙,通過它的下面兩個(gè)屬性即可拿到圖片真正的寬高。


順手吐槽一下,為什么高不是 TAG_IMAGE_HEIGHT 而是 TAG_IMAGE_LENGTH。改良過后的代碼實(shí)現(xiàn)如下:

public static Bitmap decodeBitmapFromFile(String imagePath, int requestWidth, int requestHeight) {
       if (!TextUtils.isEmpty(imagePath)) {
           Log.i(TAG, "requestWidth: " + requestWidth);
           Log.i(TAG, "requestHeight: " + requestHeight);
           if (requestWidth <= 0 || requestHeight <= 0) {
               Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
               return bitmap;
           }
           BitmapFactory.Options options = new BitmapFactory.Options();
           options.inJustDecodeBounds = true;//不加載圖片到內(nèi)存,僅獲得圖片寬高
           BitmapFactory.decodeFile(imagePath, options);
           Log.i(TAG, "original height: " + options.outHeight);
           Log.i(TAG, "original width: " + options.outWidth);
           if (options.outHeight == -1 || options.outWidth == -1) {
               try {
                   ExifInterface exifInterface = new ExifInterface(imagePath);
                   int height = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, ExifInterface.ORIENTATION_NORMAL);//獲取圖片的高度
                   int width = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, ExifInterface.ORIENTATION_NORMAL);//獲取圖片的寬度
                   Log.i(TAG, "exif height: " + height);
                   Log.i(TAG, "exif width: " + width);
                   options.outWidth = width;
                   options.outHeight = height;
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
           options.inSampleSize = calculateInSampleSize(options, requestWidth, requestHeight); //計(jì)算獲取新的采樣率
           Log.i(TAG, "inSampleSize: " + options.inSampleSize);
           options.inJustDecodeBounds = false;
           return BitmapFactory.decodeFile(imagePath, options);

       } else {
           return null;
       }
   }

再看一下,打印出來的 log


以上總結(jié)了這么些身邊童鞋經(jīng)常問起,但網(wǎng)上又不多見的適配問題,希望可以幫到一些開發(fā)童鞋少走彎路。文中多次提到小米的機(jī)子,并不代表只有MIUI上有這樣的問題存在,僅僅只是因?yàn)槲疑磉厧У膸撞繖C(jī)子大都是小米的。對待適配問題,在搜索引擎都無法提供多少有效的信息時(shí),我們只能靠斷點(diǎn)、打 log、觀察控制臺(tái)的日志、以及 API 文檔來尋找一些蛛絲馬跡作為突破口,相信辦法總比困難多。
以上內(nèi)容采自:There
至于為什么基本全文 copy,是因?yàn)槲矣X得作者已經(jīng)講的特別清楚了,我沒必要做二次重復(fù),也只是給大家分享一下。
那下面就讓我來補(bǔ)充一下不一樣的開發(fā)情景。

如果同事寫好了壓縮九宮格顯示圖片呢?

這時(shí)候你們大框架已經(jīng)搞定了,只需要你傳回一個(gè)文件的path,你可能會(huì)這樣寫:(下面所有代碼都在 onActivityResult()` 方法)

if (null != imageGridAdapter.uri) {
    final String url = PhotoUtil.getImageUrlFromActivityResult(this, imageGridAdapter.uri);//這個(gè)方法可以拿到圖片的path
    Log.e(TAG, "onActivityResult: url:" + url);
    if (!TextUtils.isEmpty(url)) {
        file = new File(url);
        size = file.length();
        Log.e(TAG, "onActivityResult: size:" + size);
        if (size > 0 ){
          ImageItem imageItem = new ImageItem();
          imageItem.ImageId = ImageItem.NEW_ID;
          imageItem.PhotoPath = url;
          imageGridAdapter.getmDataList().add(imageItem);
          imageGridAdapter.notifyDataSetChanged();
          imageGridAdapter.uri = null;
        }
  }
}

好像沒啥問題呀,拿到圖片的 path,new 一個(gè)文件,如果文件 size = 0,則不顯示,大于 0 說明圖片存在,則顯示圖片,提示 UI 刷新。
嗯,的確,絕大部分手機(jī)都測試通過了,然而在坑爹的部分MIUI系統(tǒng)上出現(xiàn)了,返回 size 為 0,進(jìn)不到判斷循環(huán),自然不會(huì)顯示那個(gè)圖片。
這時(shí)候肯定要到 google 上去搜上一圈,一圈下來收獲不少,卻沒找到真正解決的辦法。
這里有位朋友就說啦,這個(gè) size 為0,但是間隔一定的時(shí)間就可以 new 出 size 不為 0 的 file,而這個(gè)時(shí)間是不固定的。



可見遇上這個(gè)坑的小伙伴也是盡心盡力,想方設(shè)法。
所以我也嘗試了這個(gè)方法,考慮到不能休眠主線程,就采用新開一個(gè)線程來延時(shí)處理,采用加載框,一旦 size 不為 0 了,才進(jìn)行顯示處理。
可能圖片出問題,所以我們設(shè)置一個(gè)最大休眠時(shí)間。代碼為:(其中 flag 和 time 為全局變量)

flag = true;
    time = 0;
    final String url = PhotoUtil.getImageUrlFromActivityResult(this,
            imageGridAdapter.uri);
    if (size <= 0) { // 如果size小于0出現(xiàn)了,則使用加載框
        new Thread(new Runnable() {
            @Override
            public void run() {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        showLoading(SendQuestionActivity.this);// 該方法為顯示加載框
                    }
                });
                while (flag) {
                    // 設(shè)置延遲步長是0.5s
                    try {
                        Thread.sleep(500);
                        time += 0.5;
                        file = null;
                        file = new File(url);
                        size = file.length();
                        Log.e(TAG, "onActivityResult: size:" + size);
                        if (size > 0 || time >= 10) {
                            flag = false;
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        stopLoading();//該方法為取消加載框
                    }
                });

            }
        }).start();
    }
    ImageItem imageItem = new ImageItem();
    imageItem.ImageId = ImageItem.NEW_ID;
    imageItem.PhotoPath = url;
    imageGridAdapter.getmDataList().add(imageItem);
    imageGridAdapter.notifyDataSetChanged();
    imageGridAdapter.uri = null;

這樣問題是得到解決啦,但是用戶取消的時(shí)候 size 也為 0 呀,這樣無疑是畫蛇添足,用戶取消拍照都要顯示加載框 10s,想想都可怕!!!

又聽說在 new File 的前面加上下面的這句話可以解決,倒騰一番,然并卵。

// 小米4 LTE MIUI 7.0 版本下,file的size始終為0;通過提前獲取ExifInterface信息,保證文件確實(shí)寫入到外存
try {
    ExifInterface exifInterface = new ExifInterface(url);
} catch (Exception e) {
    e.printStackTrace();
}

額,等等。上面說了,ExifInterface 可以拿到圖片的寬高等參數(shù),那我是不是可以直接通過判斷圖片寬高是否為 0 來判斷用戶是否拍照呢?如果 widthheight 為 0,說明用戶取消了拍照,不顯示。否則顯示圖片,心動(dòng)不如行動(dòng),直接上代碼。

flag = true;
Log.e(TAG, "onActivityResult: uri:" + imageGridAdapter.uri);
if (null != imageGridAdapter.uri) {
    final String url = PhotoUtil.getImageUrlFromActivityResult(this,
            imageGridAdapter.uri);
    Log.e(TAG, "onActivityResult: url:" + url);
    boolean flag = true;
    // 小米4 LTE MIUI 7.0 版本下,file的size始終為0;通過提前獲取ExifInterface信息,保證文件確實(shí)寫入到外存
    try {
        ExifInterface exifInterface = new ExifInterface(url);
        int height = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, ExifInterface.ORIENTATION_NORMAL);//獲取圖片的高度
        int width = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, ExifInterface.ORIENTATION_NORMAL);//獲取圖片的寬度
        Log.e(TAG, "onActivityResult: height:" + height);
        Log.e(TAG, "onActivityResult: width:" + width);
        if (height == 0 && width == 0) {
            flag = false;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    if (!TextUtils.isEmpty(url)) {
        file = new File(url);
        size = file.length();
        Log.e(TAG, "onActivityResult: size:" + size);
        /**
         * MIUI8.0上面方案無法解決,經(jīng)測試發(fā)現(xiàn)在一定時(shí)間后能保證size不為0
         * 奇怪的發(fā)現(xiàn)當(dāng)size為0的時(shí)候依然可以拿到圖片,多款手機(jī)測試通過
         */
        if (flag) {
            ImageItem imageItem = new ImageItem();
            imageItem.ImageId = ImageItem.NEW_ID;
            imageItem.PhotoPath = url;
            imageGridAdapter.getmDataList().add(imageItem);
            imageGridAdapter.notifyDataSetChanged();
            imageGridAdapter.uri = null;
        }

    }

}

OK,終于解決了。希望能幫到大家!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容