你需要知道的Android拍照適配方案

聲明:本文作者授權(quán)微信公眾號(hào)Android程序員(AndroidTrending)在微信公眾號(hào)平臺(tái)原創(chuàng)首發(fā)楞卡。

近段時(shí)間玄货,家里陪自己度過(guò)大學(xué)四年的電腦壞了,挑選好的新電腦配件終于在本周全部到貨您市,自己動(dòng)手完成組裝挪凑。從AMD到i7的CPU荠瘪,6G內(nèi)存到14G內(nèi)存夯巷,打開(kāi) AndroidStudio 的速度終于杠桿的上去了,感動(dòng)到淚流滿面鞍埂3貌汀!@捍隆:罄住!7透鳌臀突!扯了這么多,回歸一下正題贾漏,還是來(lái)說(shuō)說(shuō)本篇文章要寫什么吧候学!說(shuō)起調(diào)用系統(tǒng)相機(jī)來(lái)拍照的功能,大家肯定不陌生纵散,現(xiàn)在所有應(yīng)用都具備這個(gè)功能梳码。例如最基本的,用戶拍照上傳頭像伍掀。Android開(kāi)發(fā)的孩紙都知道掰茶,碎片化給拍照這個(gè)功能的實(shí)現(xiàn)帶來(lái)挺多頭疼的問(wèn)題。所以蜜笤,我決定寫寫一些網(wǎng)上不多見(jiàn)但又經(jīng)常聽(tīng)到童鞋們吐槽的問(wèn)題濒蒋。

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

Android 程序上實(shí)現(xiàn)拍照功能的方式分為兩種:第一種是利用相機(jī)的 API 來(lái)自定義相機(jī),第二種是利用 Intent 調(diào)用系統(tǒng)指定的相機(jī)拍照把兔。下面講的內(nèi)容都是針對(duì)第二種實(shí)現(xiàn)方式的適配沪伙。

通常情況下,我們調(diào)用拍照的業(yè)務(wù)場(chǎng)景是如下面這樣的:

  1. A 界面垛贤,點(diǎn)擊按鈕調(diào)用相機(jī)拍照焰坪;
  2. A 界面得到拍完照片,跳轉(zhuǎn)到 B 界面進(jìn)行預(yù)覽聘惦;
  3. B 界面有個(gè)按鈕某饰,點(diǎn)擊后觸發(fā)某個(gè)業(yè)務(wù)流程來(lái)處理這張照片儒恋;

實(shí)現(xiàn)的大體流程代碼如下:


    //1、調(diào)用相機(jī)
    File mPhotoFile = new File(folder,filename);
    Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    Uri fileUri = Uri.fromFile(mPhotoFile);
    captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
    mActivity.startActivityForResult(captureIntent, CAPTURE_PHOTO_REQUEST_CODE);

    //2黔漂、拿到照片
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == CapturePhotoHelper.CAPTURE_PHOTO_REQUEST_CODE && resultCode == RESULT_OK) {
            File photoFile = mCapturePhotoHelper.getPhoto();//獲取拍完的照片
            if (photoFile != null) {
                PhotoPreviewActivity.preview(this, photoFile);//跳轉(zhuǎn)到預(yù)覽界面
            }
            finish();
        } else {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }

    //3诫尽、各種各樣處理這張圖片的業(yè)務(wù)代碼

到這里基本科普完了如何調(diào)用系統(tǒng)相機(jī)拍照,相信這些網(wǎng)上一搜一大把的代碼炬守,很多童鞋都能看懂牧嫉。

有沒(méi)有相機(jī)可用?

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

  1. 調(diào)用相機(jī)時(shí)怕轿,簡(jiǎn)單粗暴的 try-catch
  2. 調(diào)用相機(jī)前,檢測(cè)系統(tǒng)有沒(méi)有相機(jī) app 可用

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

通過(guò)這樣一個(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;
    }

拍出來(lái)的照片“歪了”!S鸾堋渡紫!

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

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

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


    /**
     * 獲取圖片的旋轉(zhuǎn)角度
     *
     * @param path 圖片絕對(duì)路徑
     * @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ī)型上遇到過(guò)這樣的問(wèn)題货邓,調(diào)用系統(tǒng)相機(jī)拍照秆撮,拍完點(diǎn)擊確定回到自己的app里面卻莫名奇妙的閃退了。這種閃退有兩個(gè)特點(diǎn):

  1. 沒(méi)有什么錯(cuò)誤日志(有些機(jī)子啥日志都沒(méi)有换况,有些機(jī)子會(huì)出來(lái)個(gè)空異常錯(cuò)誤日志)职辨;
  2. 同個(gè)機(jī)子上非必現(xiàn)(有時(shí)候怎么拍都不閃退,有時(shí)候一拍就閃退)戈二;

對(duì)待非必現(xiàn)問(wèn)題往往比較頭疼舒裤,當(dāng)初遇到這樣的問(wèn)題也是非常不解。上網(wǎng)搜羅了一圈也沒(méi)方案觉吭,后來(lái)留意到一個(gè)比較有意思信息:有些系統(tǒng)廠商的 ROM 會(huì)給自帶相機(jī)應(yīng)用做優(yōu)化腾供,當(dāng)某個(gè) app 通過(guò) intent 進(jìn)入相機(jī)拍照界面時(shí),系統(tǒng)會(huì)把這個(gè) app 當(dāng)前最上層的 Activity 銷毀回收鲜滩。(注意:我遇到的情況是有時(shí)候很快就回收掉伴鳖,有時(shí)候怎么等也不回收,沒(méi)有什么必現(xiàn)規(guī)律)為了驗(yàn)證一下徙硅,便在啟動(dòng)相機(jī)的 Activity 中對(duì) onDestory 方法進(jìn)行加 log 榜聂。果不其然,終于發(fā)現(xiàn)進(jìn)入拍照界面的時(shí)候 onDestory 方法被執(zhí)行了嗓蘑。所以须肆,前面提到的閃退基本可以推測(cè)是 Activity 被回收導(dǎo)致某些非UI控件的成員變量為空導(dǎo)致的贴汪。(有些機(jī)子會(huì)報(bào)出空異常錯(cuò)誤日志,但是有些機(jī)子閃退了什么都不報(bào)休吠,是不是覺(jué)得很奇葩0夤 )

既然涉及到 Activity 被回收的問(wèn)題,自然要想起 onSaveInstanceState 和 onRestoreInstanceState 這對(duì)方法瘤礁。去到 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);
    }

對(duì)于 onSaveInstanceState 和 onRestoreInstanceState 方法的作用還不熟悉的童鞋柜思,網(wǎng)上資料很多岩调,可以自行搜索。

到這里赡盘,可能有童鞋要問(wèn)号枕,這種閃退并不能保證復(fù)現(xiàn),我要怎么知道問(wèn)題所在和是否修復(fù)了呢陨享?我們可以去到開(kāi)發(fā)者選項(xiàng)里開(kāi)啟不保留活動(dòng)這一項(xiàng)進(jìn)行調(diào)試驗(yàn)證

它作用是保留當(dāng)前和用戶接觸的 Activity 葱淳,并將目前無(wú)法和用戶交互 Activity 進(jìn)行銷毀回收。打開(kāi)這個(gè)調(diào)試選項(xiàng)就可以滿足驗(yàn)證的需求抛姑,當(dāng)你的 app 的某個(gè) Activity 跳轉(zhuǎn)到拍照的 Activity 后赞厕,這個(gè) Activity 立馬就會(huì)被系統(tǒng)銷毀回收,這樣就可以很好的完全復(fù)現(xiàn)閃退的場(chǎng)景定硝,幫助開(kāi)發(fā)者確認(rèn)問(wèn)題有沒(méi)有修復(fù)了皿桑。

涉及到 Activity 被銷毀,還想提一下代碼實(shí)現(xiàn)上的問(wè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 方法中獲取拍下來(lái)的照片顽腾,并啟動(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 方法中獲取拍下來(lái)的照片進(jìn)行預(yù)覽漓摩;

上面兩種方案得到的實(shí)現(xiàn)效果是一模一樣的裙士,但是第二種方案卻存在很大的問(wè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)證適配一下。

圖片無(wú)法顯示

圖片無(wú)法顯示這個(gè)問(wèn)題也是略坑耸采,如何坑法兴泥?往下看,同樣是在小米4S小米4 LTE機(jī)子上(MIUI的版本是7.3虾宇,Android系統(tǒng)版本是6.0)出現(xiàn)概率很高的場(chǎng)景(當(dāng)然,不保證其他機(jī)子沒(méi)出現(xiàn)過(guò))如绸。按照我們前面提到的業(yè)務(wù)場(chǎng)景嘱朽,調(diào)用相機(jī)拍照完成后,我們的 app 會(huì)有一個(gè)預(yù)覽圖片的界面怔接。但是在用了小米的機(jī)子進(jìn)行拍照后搪泳,自己 app 的預(yù)覽界面卻怎么也無(wú)法顯示出照片來(lái),同樣是相當(dāng)郁悶扼脐,郁悶完后還是要一步一步去排查解決問(wèn)題的岸军!為此,需要一步一步猜測(cè)驗(yàn)證問(wèn)題所在瓦侮。

  • 猜測(cè)一:沒(méi)有拿到照片路徑艰赞,所以無(wú)法顯示?

直接斷點(diǎn)打 log 跟蹤肚吏,猜測(cè)一很快被推翻方妖,路徑是有的。

  • 猜測(cè)二:Bitmap太大了罚攀,無(wú)法顯示党觅?

直接在 AS 的 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 上無(wú)法顯示。到這里有童鞋要吐槽了魁莉,沒(méi)對(duì)圖片的采樣率 inSampleSize 做處理睬涧?天地良心啊,絕對(duì)做處理了沛厨,直接看代碼:


    /**
     * 壓縮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;
    }

瞄了代碼后,是不是覺(jué)得沒(méi)有問(wèn)題了逆皮?沒(méi)錯(cuò)宅粥,inSampleSize 確確實(shí)實(shí)經(jīng)過(guò)處理,那為什么圖片還是太大而顯示不出來(lái)呢电谣? requestWidth秽梅、int requestHeight 設(shè)置得太大導(dǎo)致 inSampleSize 太小了?不可能啊剿牺,我都試著把長(zhǎng)寬都設(shè)置成 100 了還是沒(méi)法顯示企垦!干脆,直接打印 inSampleSize 值晒来,一打印钞诡,inSampleSize 值居然為 1 。 我去湃崩,徹底打臉了荧降,明明說(shuō)好的處理過(guò)了,居然還是 1 T芏痢6浣搿!薄扁!為了一探究竟剪返,干脆加 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)行打印出來(lái)的日志如下:

圖片原來(lái)的寬高居然都是 -1 脱盲,真是奇葩了!難怪震放,inSampleSize 經(jīng)過(guò)處理之后結(jié)果還是 1 宾毒。狠狠的吐槽了之后,總是要回來(lái)解決問(wèn)題的。那么诈铛,圖片的寬高信息都丟失了乙各,我去哪里找啊幢竹? 像下面這樣耳峦?


    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 對(duì)象是 null邑飒;那要怎樣才能獲圖片的寬高呢循签?前面提到的 ExifInterface 再次幫了我們大忙,通過(guò)它的下面兩個(gè)屬性即可拿到圖片真正的寬高

順手吐槽一下疙咸,為什么高不是 TAG_IMAGE_HEIGHT 而是 TAG_IMAGE_LENGTH县匠。改良過(guò)后的代碼實(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;
        }
    }

再看一下撒轮,打印出來(lái)的log

這樣就可以解決問(wèn)題啦乞旦。

總結(jié)

以上總結(jié)了這么些身邊童鞋經(jīng)常問(wèn)起,但網(wǎng)上又不多見(jiàn)的適配問(wèn)題题山,希望可以幫到一些開(kāi)發(fā)童鞋少走彎路兰粉。文中多次提到小米的機(jī)子,并不代表只有MIUI上有這樣的問(wèn)題存在顶瞳,僅僅只是因?yàn)槲疑磉厧У膸撞繖C(jī)子大都是小米的玖姑。對(duì)待適配問(wèn)題,在搜索引擎都無(wú)法提供多少有效的信息時(shí)慨菱,我們只能靠斷點(diǎn)客峭、打log、觀察控制臺(tái)的日志抡柿、以及API文檔來(lái)尋找一些蛛絲馬跡作為突破口,相信辦法總比困難多等恐。

以上的示例代碼已經(jīng)整理到:https://github.com/D-clock/AndroidStudyCode 洲劣,主要的代碼在下面紅圈部分

感興趣的童鞋可以自行查看!如有錯(cuò)誤课蔬,歡迎大家指正囱稽!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市二跋,隨后出現(xiàn)的幾起案子战惊,更是在濱河造成了極大的恐慌,老刑警劉巖扎即,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吞获,死亡現(xiàn)場(chǎng)離奇詭異况凉,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)各拷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門刁绒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人烤黍,你說(shuō)我怎么就攤上這事知市。” “怎么了速蕊?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵嫂丙,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我规哲,道長(zhǎng)跟啤,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任媳叨,我火速辦了婚禮腥光,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘糊秆。我一直安慰自己武福,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布痘番。 她就那樣靜靜地躺著捉片,像睡著了一般。 火紅的嫁衣襯著肌膚如雪汞舱。 梳的紋絲不亂的頭發(fā)上伍纫,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音昂芜,去河邊找鬼莹规。 笑死,一個(gè)胖子當(dāng)著我的面吹牛泌神,可吹牛的內(nèi)容都是我干的良漱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼欢际,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼母市!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起损趋,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤患久,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蒋失,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡返帕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了高镐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片溉旋。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖嫉髓,靈堂內(nèi)的尸體忽然破棺而出观腊,到底是詐尸還是另有隱情,我是刑警寧澤算行,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布梧油,位于F島的核電站,受9級(jí)特大地震影響州邢,放射性物質(zhì)發(fā)生泄漏儡陨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一量淌、第九天 我趴在偏房一處隱蔽的房頂上張望骗村。 院中可真熱鬧,春花似錦呀枢、人聲如沸胚股。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)琅拌。三九已至,卻和暖如春摘刑,著一層夾襖步出監(jiān)牢的瞬間进宝,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工枷恕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留党晋,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓徐块,卻偏偏與公主長(zhǎng)得像隶校,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蛹锰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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