Android調用相冊、相機(兼容6.0、7.0、8.0)

又好久沒有寫博客了,好習慣不能斷,該寫點就得寫點,今天帶來的筆記是關於Android 項目調用系統相機 與調用系統相冊的之後拿到照片的基本操作,我感覺好多人還是不太熟悉的哈。項目兼容 Android 5.0設備、Android 6.0設備、Android 7.0、Android 8.0等設備,下面請開始欣賞我的表演,先上動畫,給大家看一下效果哈。

Android 5.0設備效果:

 

小米 2s 測試效果

Android 6.0設備效果:

 

小米4測試效果

Android 8.0 設備效果:

 

小米8se 測試

看了三個小動畫,感覺就是相機效果越來越清楚了(說人話),好的迴歸正題

一、界面上定義了三個按鈕,一個imageview代碼還是扔上來吧,

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btn_get_pic_form_photo_album"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_margin="10dp"
        android:text="調用相冊" />

    <Button
        android:id="@+id/btn_get_Permission"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_margin="10dp"
        android:text="動態權限申請" />

    <Button
        android:id="@+id/btn_get_pic_from_camera"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_margin="10dp"
        android:text="調用相機" />

    <ImageView
        android:id="@+id/iv_test"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_centerInParent="true"
        android:contentDescription="@string/app_name"
        android:scaleType="fitXY"
        tools:src="@mipmap/ic_launcher" />

</RelativeLayout>

二、引入框架

我這個人很懶,引入了 glide
圖片加載框架和easypermissions動態權限申請框架,兩個十分好用的框。

 //glide 圖片加載
    implementation 'com.github.bumptech.glide:glide:4.8.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
    //動態權限申請庫
    implementation 'pub.devrel:easypermissions:1.3.0'

三、簡單說一下easypermissions框架使用

衆所周知,Android 6.0 開始 google 爸爸引入了動態權限機制,所謂來保護用戶隱私(其實就是對開發者坑爹,個人見解)。但是我們必須處理啊,畢竟是google 爸爸。

以下僅僅以本項目所申請權限爲例進行講解。

1、AndroidManifest.xml 內操作

 <!--讀寫內存塊權限-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <!--調用相機權限-->
    <uses-permission android:name="android.permission.CAMERA" />

2、初始化集合裝載權限

 private String[] permissions = {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE};

3、檢查權限、申請權限

 //獲取權限
    private void getPermission() {
        if (EasyPermissions.hasPermissions(this, permissions)) {
            //已經打開權限
            Toast.makeText(this, "已經申請相關權限", Toast.LENGTH_SHORT).show();
        } else {
            //沒有打開相關權限、申請權限
            EasyPermissions.requestPermissions(this, "需要獲取您的相冊、照相使用權限", 1, permissions);
        }

    }

4、實現接口

在所運用權限申請的界面實現EasyPermissions.PermissionCallbacks接口

5、處理回調


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        //框架要求必須這麼寫
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }

    
    //成功打開權限
    @Override
    public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
        
        Toast.makeText(this, "相關權限獲取成功", Toast.LENGTH_SHORT).show();
    }
    //用戶未同意權限
    @Override
    public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
        Toast.makeText(this, "請同意相關權限,否則功能無法使用", Toast.LENGTH_SHORT).show();
    }

四、調用相機 適配>=6.0以上設備

1、AndroidManifest.xml 內操作

   <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.example.hxd.pictest.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

其中,android:authorities="com.example.hxd.pictest.fileprovider"的值其實是:項目包名.fileprovider

2、創建file_paths.xml文件

在 項目 res 下面創建 xml 文件夾,xml文件夾下創建 file_paths.xml 文件,文件內寫如下:內容

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

文件創建,如下圖:

3、點擊按鈕拍照

  private File cameraSavePath;//拍照照片路徑
  private Uri uri;//照片uri

   //激活相機操作
    private void goCamera() {
    cameraSavePath = new File(Environment.getExternalStorageDirectory().getPath() + "/" + System.currentTimeMillis() + ".jpg");


        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            //第二個參數爲 包名.fileprovider
            uri = FileProvider.getUriForFile(MainActivity.this, "com.example.hxd.pictest.fileprovider", cameraSavePath);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        } else {
            uri = Uri.fromFile(cameraSavePath);
        }
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        MainActivity.this.startActivityForResult(intent, 1);
    }

4、獲取照片並且展示

Android 6.0以上設備的照片路徑 就是你聲明的uri。

   if (requestCode == 1 && resultCode == RESULT_OK) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                photoPath = String.valueOf(cameraSavePath);
            } else {
                photoPath = uri.getEncodedPath();
            }
            Log.d("拍照返回圖片路徑:", photoPath);
            Glide.with(MainActivity.this).load(photoPath).into(ivTest);
        }


總結,截止到這裏,你拍攝的照片就可以拿到並且進行顯示了,這裏使用到了強大的Glide 圖片加載器省去了很多自己要寫的代碼。很方便。

五、相冊內選照片

1、調去系統相冊

  //激活相冊操作
    private void goPhotoAlbum() {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_PICK);
        intent.setType("image/*");
        startActivityForResult(intent, 2);
    }

2、獲取相冊返回的uri

這裏封裝了一個工具類,根據不同版本系統返回不同類型的uri ,這個工具類保留簡單好用


import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.DocumentsContract;
import android.provider.MediaStore;

/**
 * Content:從相冊內獲取照片轉化工具類
 * Actor:韓小呆 ヾ(✿゚▽゚)ノ
 * Time:  2018/08/18 18:54
 * Update:
 * Time:
 */
public class getPhotoFromPhotoAlbum {
    /**
     * 根據Uri獲取圖片的絕對路徑
     *
     * @param context 上下文對象
     * @param uri     圖片的Uri
     * @return 如果Uri對應的圖片存在, 那麼返回該圖片的絕對路徑, 否則返回null
     */
    public static String getRealPathFromUri(Context context, Uri uri) {
        int sdkVersion = Build.VERSION.SDK_INT;
        if (sdkVersion >= 19) { 
            return getRealPathFromUriAboveApi19(context, uri);
        } else {
            return getRealPathFromUriBelowAPI19(context, uri);
        }
    }

    /**
     * 適配api19以下(不包括api19),根據uri獲取圖片的絕對路徑
     *
     * @param context 上下文對象
     * @param uri     圖片的Uri
     * @return 如果Uri對應的圖片存在, 那麼返回該圖片的絕對路徑, 否則返回null
     */
    private static String getRealPathFromUriBelowAPI19(Context context, Uri uri) {
        return getDataColumn(context, uri, null, null);
    }

    /**
     * 適配api19及以上,根據uri獲取圖片的絕對路徑
     *
     * @param context 上下文對象
     * @param uri     圖片的Uri
     * @return 如果Uri對應的圖片存在, 那麼返回該圖片的絕對路徑, 否則返回null
     */
    @SuppressLint("NewApi")
    private static String getRealPathFromUriAboveApi19(Context context, Uri uri) {
        String filePath = null;
        if (DocumentsContract.isDocumentUri(context, uri)) {
            // 如果是document類型的 uri, 則通過document id來進行處理
            String documentId = DocumentsContract.getDocumentId(uri);
            if (isMediaDocument(uri)) {
                // 使用':'分割
                String id = documentId.split(":")[1];

                String selection = MediaStore.Images.Media._ID + "=?";
                String[] selectionArgs = {id};
                filePath = getDataColumn(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection, selectionArgs);
            } else if (isDownloadsDocument(uri)) { 
                Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(documentId));
                filePath = getDataColumn(context, contentUri, null, null);
            }
        } else if ("content".equalsIgnoreCase(uri.getScheme())) {
            // 如果是 content 類型的 Uri
            filePath = getDataColumn(context, uri, null, null);
        } else if ("file".equals(uri.getScheme())) {
            // 如果是 file 類型的 Uri,直接獲取圖片對應的路徑
            filePath = uri.getPath();
        }
        return filePath;
    }

    /**
     * 獲取數據庫表中的 _data 列,即返回Uri對應的文件路徑
     *
     */
    private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
        String path = null;

        String[] projection = new String[]{MediaStore.Images.Media.DATA};
        Cursor cursor = null;
        try {
            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                int columnIndex = cursor.getColumnIndexOrThrow(projection[0]);
                path = cursor.getString(columnIndex);
            }
        } catch (Exception e) {
            if (cursor != null) {
                cursor.close();
            }
        }
        return path;
    }

    /**
     * @param uri the Uri to check
     * @return Whether the Uri authority is MediaProvider
     */
    private static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getAuthority());
    }

    /**
     * @param uri the Uri to check
     * @return Whether the Uri authority is DownloadsProvider
     */
    private static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
    }
}

3、拿到圖片,展示圖片

if (requestCode == 2 && resultCode == RESULT_OK) {
            photoPath = getPhotoFromPhotoAlbum.getRealPathFromUri(this, data.getData());
            Glide.with(MainActivity.this).load(photoPath).into(ivTest);
        }

六、貼出 Activity 內完整代碼

public class MainActivity extends AppCompatActivity implements View.OnClickListener, EasyPermissions.PermissionCallbacks {

    private ImageView ivTest;

    private File cameraSavePath;//拍照照片路徑
    private Uri uri;
    private String[] permissions = {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE};


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button btnGetPicFromCamera = findViewById(R.id.btn_get_pic_from_camera);
        Button btnGetPicFromPhotoAlbum = findViewById(R.id.btn_get_pic_form_photo_album);
        Button btnGetPermission = findViewById(R.id.btn_get_Permission);
        ivTest = findViewById(R.id.iv_test);

        btnGetPicFromCamera.setOnClickListener(this);
        btnGetPicFromPhotoAlbum.setOnClickListener(this);
        btnGetPermission.setOnClickListener(this);

       

    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        switch (id) {
            case R.id.btn_get_pic_from_camera:
                goCamera();
                break;
            case R.id.btn_get_pic_form_photo_album:
                goPhotoAlbum();
                break;
            case R.id.btn_get_Permission:
                getPermission();
                break;
        }
    }

    //獲取權限
    private void getPermission() {
        if (EasyPermissions.hasPermissions(this, permissions)) {
            //已經打開權限
            Toast.makeText(this, "已經申請相關權限", Toast.LENGTH_SHORT).show();
        } else {
            //沒有打開相關權限、申請權限
            EasyPermissions.requestPermissions(this, "需要獲取您的相冊、照相使用權限", 1, permissions);
        }

    }


    //激活相冊操作
    private void goPhotoAlbum() {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_PICK);
        intent.setType("image/*");
        startActivityForResult(intent, 2);
    }

    //激活相機操作
    private void goCamera() {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
 cameraSavePath = new File(Environment.getExternalStorageDirectory().getPath() + "/" + System.currentTimeMillis() + ".jpg");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            uri = FileProvider.getUriForFile(MainActivity.this, "com.example.hxd.pictest.fileprovider", cameraSavePath);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        } else {
            uri = Uri.fromFile(cameraSavePath);
        }
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        MainActivity.this.startActivityForResult(intent, 1);
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        //框架要求必須這麼寫
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }


    //成功打開權限
    @Override
    public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {

        Toast.makeText(this, "相關權限獲取成功", Toast.LENGTH_SHORT).show();
    }
    //用戶未同意權限
    @Override
    public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
        Toast.makeText(this, "請同意相關權限,否則功能無法使用", Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        String photoPath;
        if (requestCode == 1 && resultCode == RESULT_OK) {

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                photoPath = String.valueOf(cameraSavePath);
            } else {
                photoPath = uri.getEncodedPath();
            }
            Log.d("拍照返回圖片路徑:", photoPath);
            Glide.with(MainActivity.this).load(photoPath).into(ivTest);
        } else if (requestCode == 2 && resultCode == RESULT_OK) {
            photoPath = getPhotoFromPhotoAlbum.getRealPathFromUri(this, data.getData());
            Glide.with(MainActivity.this).load(photoPath).into(ivTest);
        }

        super.onActivityResult(requestCode, resultCode, data);
    }


}


 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章