1. 程式人生 > >Android--使用手機拍照獲取圖片路徑,小米手機選擇照片問題處理

Android--使用手機拍照獲取圖片路徑,小米手機選擇照片問題處理

Android開發選取照片問題

本文主要記錄使用手機自帶相機拍照獲取返回照片路徑,以及從本地相簿選取已有照片時返回Intent data;
資料處理 操作。(小米手機獲取照片路徑與其他手機不一致問題!)

一:使用相機時新增許可權:

  <!-- 呼叫相機許可權 -->
<uses-permission android:name="android.permission.CAMERA" />
  <!-- SDCard中建立與刪除檔案許可權 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
/>
<!-- SDCard寫入資料許可權 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

二 調取相機拍照:

1. 拍照獲取圖片,返回Bitmap物件,圖片不會自動儲存至本地:

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 1); 

使用此方法拍照時,返回結果Intent data ;data.getData()==null;

   @Override  
   protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    //...
    Uri uri = data.getData();//此時uri為null
    Bundle bundle = data.getExtras();//
     if (bundle != null) {
        //圖片被儲存在 bundle中返回,使用budle.get("data")獲取bitmap物件
        Bitmap  photo = (Bitmap) bundle.get("data"
); //todo:得到bitmap物件可以直接使用imgaeview展示,此時是縮圖 } else { Toast.makeText(getApplicationContext(), "無法找到該圖片!", Toast.LENGTH_LONG).show(); return; } //... }

ps:如果像儲存圖片到本地需要單獨設定儲存得路徑

/**
     * 將bitmap儲存為特定格式的圖片
     *
     * @param bmp                    需要儲存的bmp
     * @param desFilename            目的檔案路徑
     * @param format                 儲存的圖片格式, 如果為空則預設儲存為jpg格式
     * @param quality                是否進行質量壓縮 
     * @param recycleBitmapSavedFile 是否在儲存圖片後回收bitmap
     * @return 儲存成功, 則返回true; 否則返回false
     */
    public static boolean saveBitmap(Bitmap bmp, String desFilename, Bitmap.CompressFormat format,
                                     boolean recycleBitmapSavedFile, int quality) {
        try {
            if (bmp == null || bmp.isRecycled() || TextUtils.isEmpty(desFilename)) {
                return false;
            }
            File file = new File(desFilename);
            if (!file.getParentFile().exists())
                file.getParentFile().mkdirs();

            if (file.exists())
                file.delete();
            file.createNewFile();

            FileOutputStream outStream = new FileOutputStream(file);

            if (format == null) {
                format = Bitmap.CompressFormat.JPEG;
            }

            boolean result = bmp.compress(format, quality, outStream);
            outStream.flush();
            outStream.close();

            if (recycleBitmapSavedFile) {
                bmp.recycle();
                bmp = null;
            }
            // 操作成功, 直接返回
            return result;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (RuntimeException e) {
            e.printStackTrace();
        } catch (OutOfMemoryError e) {
            e.printStackTrace();
        }

        return false;
    }

2 自定義照片儲存路徑,需要注意自定義路徑時返回Intent data 都為null :

![這裡寫圖片描述](https://img-blog.csdn.net/20161213130517218?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ2l0aHViXzMwNjYyNTcx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
    /**
     * 兩種拍照獲取圖片得方法
     */
    private Uri photoUri;
    @Override
    public void onTakePhotoItemclick() {
        //方法一:儲存拍攝圖片至手機預設相簿中

        SimpleDateFormat timeStampFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        filename = timeStampFormat.format(new Date());
        ContentValues values = new ContentValues(); //使用本地相簿儲存拍攝照片
        values.put(MediaStore.Images.Media.TITLE, filename);
        photoUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

        // 設定 intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); photoUri = 儲存圖片得uri
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
        startActivityForResult(intent, FLAG_TAKE_PHOTO);

       /* // 方法二 自定義資料夾儲存
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
            //建立資料夾 在本地檔案Pictures 目錄下建立 自己得資料夾
            File dir = new File(Environment.getExternalStorageDirectory()+ "/Pictures/image");
            if (!dir.exists()) {
                dir.mkdirs();
            }
             //照片名稱
            File file = new File(dir, new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".jpg");
            photoUri = Uri.parse(file.getPath());

            startActivityForResult(new Intent(MediaStore.ACTION_IMAGE_CAPTURE)
                    .putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)), FLAG_TAKE_PHOTO);

        } else {
            showToast("請檢查SDCard!");
        }*/

    }

如何獲取imagePath:

 @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == FLAG_CHOOSE_IMG && resultCode == RESULT_OK) {  //處理選擇照片返回
            //todo:
        } else if (requestCode == FLAG_TAKE_PHOTO && resultCode == RESULT_OK) { //處理拍照返回
            //使用第一種方法拍照時處理圖片路徑
            Uri uri = null;
            String path = "";
            Cursor cursor = null;
            uri = photoUri;
            if (uri != null) {
                String[] proj = {MediaStore.Images.Media.DATA};
                cursor = managedQuery(uri, proj, null, null,
                        null);
                int column_index = cursor
                        .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                cursor.moveToFirst();
                path = cursor.getString(column_index);
                //在android 4.0及其以上的版本中,Cursor會自動關閉,不需要自己關閉。
                if (cursor != null && !cursor.isClosed() && Build.VERSION.SDK_INT < 14) {
                    cursor.close();
                }
            }

            // 第二種方法時:獲取圖片路徑
            if (photoUri != null) {//todo
                path = photoUri.toString();
            }
            //todo: 得到 path 之後可以轉換成bitmap 使用。
        }
    }

在上述方法二中因為是自定義路徑所以圖片地址是已知得因此直接將 photoUri 轉化成String 就可以直接使用了。

三 直接選擇本地現有圖片

 @Override
    public void onChoosePhotoItemclick() {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_PICK);
        intent.setType("image/*");
        startActivityForResult(intent, FLAG_CHOOSE_IMG);
    }

處理返回資料Intent data
**PS:個別小米手機返回資料和其他手機不同(暫時無法確定是否時全部小米手機)以下是debug
下三星手機和小米手機在選擇本地圖片時資料對比。**

三星手機:這裡寫圖片描述

小米手機:這裡寫圖片描述

可以看到小米手機返回得直接是file:///檔案絕對路徑;因此在獲取圖片path
時使用以下判斷:

 /**
     * Intent data 小米手機選擇相簿照片時返回資料
     { dat=file:///storage/emulated/0/DCIM/Camera/IMG_20161129_195938.jpg typ=image/jpeg }

     //other 拍照返回 Intent data
     { dat=content://media/external/images/media/222494 }
     * @param data
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        Uri uri = null;
        String path = "";
        Cursor cursor = null;
        if (requestCode == FLAG_CHOOSE_IMG && resultCode == RESULT_OK) {  //處理選擇照片返回
            if (data != null && data.getData() != null) {
                uri = data.getData();
                if (!TextUtils.isEmpty(uri.getAuthority())) { //使用 getAuthority 做判斷條件
                    String[] proj = {MediaStore.Images.Media.DATA};
                    cursor = managedQuery(uri, proj, null, null,
                            null);
                    int column_index = cursor
                            .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                    cursor.moveToFirst();
                    path = cursor.getString(column_index);
                }else{
                    path = uri.getPath(); //小米選擇照片返回 data="file:///..." uri.getAuthority()==""
                }
                //todo:
            }


        } else if (requestCode == FLAG_TAKE_PHOTO && resultCode == RESULT_OK) { //處理拍照返回

    }

學習記錄,如有錯誤和不足,歡迎大家指出
最後貼出一個不錯的庫:一款用於在Android裝置上獲取照片(拍照或從相簿、檔案中選擇)、裁剪圖片、壓縮圖片的開源工具庫
https://github.com/crazycodeboy/TakePhoto