1. 程式人生 > >Android呼叫攝像頭和拍照(相容MIUI系統)

Android呼叫攝像頭和拍照(相容MIUI系統)

功能:點選一張圖片,彈出對話方塊, 有選擇相簿和拍照兩個選項,得到一張照片後再對照片進行裁剪,然後將照片顯示在圖片控制元件上。

package com.example.pickphoto;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import
android.os.Environment; import android.provider.MediaStore; import android.view.View; import android.widget.ImageView; import java.io.File; public class MainActivity extends Activity implements View.OnClickListener { private ImageView imageView; @Override protected void onCreate(Bundle savedInstanceState) { super
.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = (ImageView) findViewById(R.id.photo); imageView.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.photo: pickphoto(); break
; } } private void pickphoto() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("頭像設定"); builder.setNegativeButton("相簿", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Intent intent = new Intent(Intent.ACTION_PICK, null); intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*"); startActivityForResult(intent, 1); } }); builder.setPositiveButton("拍照", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 拍下的照片會存到SD開下,命名為icon.jpg Uri mTakePhoto = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "icon.jpg")); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, mTakePhoto); startActivityForResult(intent, 2); } }); builder.show(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { // 從相簿 case 1: if (data!=null){ startPhotoZoom(data.getData()); } break; // 從拍照 case 2: try { // 找到拍下的照片 File temp = new File(Environment.getExternalStorageDirectory()+"/icon.jpg"); startPhotoZoom(Uri.fromFile(temp)); } catch (Exception e) { e.printStackTrace(); } break; // 裁剪後 case 3: if (data!=null){ setPhotoToView(data); } } } /** 相片裁剪 再開啟一個意圖*/ private void startPhotoZoom(Uri uri) { Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(uri,"image/jpeg"); intent.putExtra("crop","true"); //裁剪框寬高的比例 intent.putExtra("aspectX",1); intent.putExtra("aspectY",1); // 裁剪圖片的寬高 intent.putExtra("outputX",100); intent.putExtra("outputY",100); intent.putExtra("return-data",true); startActivityForResult(intent,3); } private void setPhotoToView(Intent intent){ Bundle extras = intent.getExtras(); if (extras!=null){ Bitmap photo = extras.getParcelable("data"); imageView.setImageBitmap(photo); } } }

經過測試,發現在MIUI系統手機上選擇照片後不能跳到裁剪介面,原因是intent.getExtras()得到的Bundle為空,修改如下:

//        intent.putExtra("return-data", true); //把上文中的這行修改為下文

        //解決MIUI  裁剪後的圖片Uri路徑,uritempFile為Uri類變數
        uritempFile = Uri.parse("file://" + "/" +activity.getExternalCacheDir().getPath() + "/" + "small.jpg");
        LogUtils.w("cache path:"+activity.getExternalCacheDir().getPath());
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uritempFile);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        activity.startActivityForResult(intent, CROP_REQUEST_CODE);


//        Bitmap photo = extras.getParcelable("data");     //把上文中的這行修改為下文

//將Uri圖片轉換為Bitmap
                Bitmap photo = null;
                try {
                    photo = BitmapFactory.decodeStream(activity.getContentResolver().openInputStream(uritempFile));
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }


FileProvider使用如下:

 //判斷版本
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {   //如果在Android7.0以上,使用FileProvider獲取Uri
            //這裡如果不走else,相容舊版本 ,就要新增許可權
            //intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            Uri contentUri = FileProvider.getUriForFile(MainActivity.this, getPackageName()+".fileprovider", tempFile);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);
            Log.e("dasd", contentUri.toString());
        } else {    //否則使用Uri.fromFile(file)方法獲取Uri
            intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile));
        }

因為FileProvider是四大元件,所以要進行註冊:

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/filepaths" />
        </provider>

還要設定一個meta-data,裡面指向一個xml檔案:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="external"
        path="" />
</paths>

其中external-path表示要共享的是SD卡的目錄,name隨便一個不能為空,path為SD卡的子目錄,不指定則為根目錄