Android自定义开发 拍照、录制视频以及切换前后摄像头

一、布局文件

<?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"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".MainActivity">

    <GridLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:columnCount="1"
        android:padding="20dp"
        android:rowCount="5"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toTopOf="parent">

      

        <Button
            android:id="@+id/btCamera"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="自定义 Camera 拍照" />

        <Button
            android:id="@+id/btCameraRecord"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="自定义 Camera 录视频" />

       

      

    </GridLayout>


</RelativeLayout>

二、拍照、录视频的activity代码

package com.chy.CCamera1;


import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.RectF;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.chy.myActivity.R;
import com.chy.util.BitmapUtil;
import com.chy.util.FileUtil;
import com.chy.view.FaceView;

import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;

/**
 * 自定义拍照 1
 * */
public class CameraActivity1 extends AppCompatActivity {

    public static final String TYPE_TAG = "TYPE";
    public static final int TYPE_CAPTURE = 0;// 拍照标记
    public static final int TYPE_RECORD = 1;// 录制视频标记
    //控制MediaRecorderHelper的初始化
    private boolean lock = false;

    private CameraHelper1 mCameraHelper;
    private MediaRecorderHelper mMediaRecorderHelper = null;

    private SurfaceView surfaceView;
    private FaceView faceView;
    private ImageView ivSetting;// 设置
    private ImageButton btnTakePic;// 拍照
    private ImageView ivStart;// 开始录制视频
    private ImageView ivStop;
    private ImageView ivExchange;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera1);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        initView();// 初始化控件
        // 跳转录像界面
        videoMethod();

        mCameraHelper = new CameraHelper1(this, surfaceView);
        // 调用回调函数
        mCameraHelper.addCallBack(new CameraHelper1.CallBack() {
            @Override
            public void onPreviewFrame(byte[] data) {
                if (!lock){
                   if (mCameraHelper.getmCamera() != null){
                       mMediaRecorderHelper = new MediaRecorderHelper(CameraActivity1.this,
                               mCameraHelper.getmCamera(),mCameraHelper.mDisplayOrientation,
                               mCameraHelper.mSurfaceHolder.getSurface());
                   }
                   lock = true;
                }
            }

            @Override
            public void onTakePic(final byte[] data) {
              new Thread(new Runnable() {
                  @Override
                  public void run() {
                      savePic(data);
                  }
              }).start();
                btnTakePic.setClickable(true);
            }
            @Override
            public void onFaceDetect(ArrayList<RectF> faces) {
                faceView.setmFaces(faces);
            }
        });

    }

    /**
     * 控件初始化
     * */
    private void initView(){
        // surfaceView
        surfaceView = findViewById(R.id.surfaceView);
        // faceView
        faceView = findViewById(R.id.faceView);
        // setting
        ivSetting = findViewById(R.id.ivSetting);
        ivSetting.setOnClickListener(setMethod);
        // take pic
        btnTakePic = findViewById(R.id.btnTakePic);
        btnTakePic.setOnClickListener(takePic);
        // start
        ivStart = findViewById(R.id.ivStart);
        ivStart.setOnClickListener(startVideo);
        // stop
        ivStop = findViewById(R.id.ivStop);
        ivStop.setOnClickListener(stopVideo);
        // exchange
        ivExchange = findViewById(R.id.ivExchange);
        ivExchange.setOnClickListener(exchangeMethod);
    }


    /**
     * 录制视频方法
     * */
    private void videoMethod(){
        if (getIntent().getIntExtra(TYPE_TAG,0) == TYPE_RECORD){
            btnTakePic.setVisibility(View.GONE);
            ivStart.setVisibility(View.VISIBLE);
        }
    }

    /**
     * 保存图片方法
     * */
    private void savePic(final byte[] data){
        try {
            // 系统当前时间
            final long temp = System.currentTimeMillis();

            FileUtil fileUtil = new FileUtil(getApplicationContext());
            final File picFile = fileUtil.createCameraFile("camera1");
            if (picFile != null && data != null){
                Bitmap rawBitMap = BitmapFactory.decodeByteArray(data, 0, data.length);
                Bitmap resultBitMap = null;
                if (mCameraHelper.mCameraFacing == Camera.CameraInfo.CAMERA_FACING_FRONT){
                    resultBitMap = BitmapUtil.mirror(BitmapUtil.rotate(rawBitMap, 270f));
                }else {
                    resultBitMap = BitmapUtil.rotate(rawBitMap, 90f);
                }

                byte[] result = BitmapUtil.toByteArray(resultBitMap);
                // 输出文件
                FileOutputStream fos = new FileOutputStream(picFile);
                fos.write(result, 0, result.length);
                fos.flush();
                fos.close();

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(getApplicationContext(),
                                "图片已保存!",Toast.LENGTH_SHORT).show();
                        long time_consuming = System.currentTimeMillis() - temp;
                        System.out.println("耗时:"+time_consuming);
                        System.out.println("路径:"+picFile.getAbsolutePath());
                    }
                });
            }
        }catch (Exception e){
            e.printStackTrace();
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(),
                            "保存图片失败!",Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

    @Override
    protected void onDestroy() {
        mCameraHelper.releaseCamera();
        if (mMediaRecorderHelper != null && mMediaRecorderHelper.isRunning){
            mMediaRecorderHelper.stopRecord();
            mMediaRecorderHelper.release();
        }
        super.onDestroy();
    }


    /**
     * 设置点击事件
     * */
    private View.OnClickListener setMethod = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(getApplicationContext(),"setting", Toast.LENGTH_SHORT).show();
        }
    };

    /**
     * 拍照点击事件
     * */
    private View.OnClickListener takePic = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mCameraHelper.takePic();
        }
    };

    /**
     * 切换摄像头
     * */
    private View.OnClickListener exchangeMethod = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mCameraHelper.exchangeCamera();
            lock = false;
        }
    };

    /**
     * 开始录制视频
     * */
    private View.OnClickListener startVideo = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            ivExchange.setClickable(false);
            ivStart.setVisibility(View.GONE);
            ivStop.setVisibility(View.VISIBLE);
            mMediaRecorderHelper.startRecord();
        }
    };

    /**
     * 停止录制视频
     * */
    private View.OnClickListener stopVideo = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            ivStart.setVisibility(View.VISIBLE);
            ivStop.setVisibility(View.GONE);
            ivExchange.setClickable(true);
            mMediaRecorderHelper.stopRecord();
        }
    };


}

 三、调用摄像头工具类代码

package com.chy.CCamera1;

import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.hardware.Camera;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 摄像头工具类
 * */
public class CameraHelper1 implements Camera.PreviewCallback {

  private Camera mCamera = null;//Camera对象
    private Camera.Parameters mParameters;//Camera对象的参数
    private SurfaceView mSurfaceView;//用于预览的SurfaceView对象
    public SurfaceHolder mSurfaceHolder;//SurfaceHolder对象

    private Activity mActivity;
    private CallBack mCallBack = null;//自定义的回调
    //默认设置为后置摄像
    public int mCameraFacing = Camera.CameraInfo.CAMERA_FACING_BACK;

    public int mDisplayOrientation = 0;//预览旋转的角度

    private int picWidth = 2160;//保存图片的宽
    private int picHeight = 3840;//保存图片的高


    public CameraHelper1(Activity _activity, SurfaceView _surfaceView){
        this.mActivity = _activity;
        this.mSurfaceView = _surfaceView;
        mSurfaceHolder = mSurfaceView.getHolder();
        init();
    }

    @Override
    public void onPreviewFrame(byte[] data,Camera camera) {
        mCallBack.onPreviewFrame(data);
    }

    /**
     * 拍照方法
     * */
    public void takePic(){
       if (mCamera != null){
           mCamera.takePicture(null,null, new Camera.PictureCallback() {
               @Override
               public void onPictureTaken(byte[] data,Camera camera) {
                  mCamera.startPreview();
                   mCallBack.onTakePic(data);
               }
           });
       }

    }

    /**
     * 初始化方法
     * */
    public void init(){
        mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                if (mCamera == null){
                    openCamera(mCameraFacing);
                }
                startPreview();
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder,int format,int width,int height) {

            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                releaseCamera();
            }
        });
    }


    /**
     * 打开相机
     * @param direction 摄像头方向
     * */
    private boolean openCamera(int direction){
       boolean supportCameraFacing = supportCameraFacing(direction);

       if (supportCameraFacing){
         try {
             mCamera = Camera.open(direction);
            initParameters(mCamera);
             mCamera.setPreviewCallback(this);
         }catch (Exception e){
             e.printStackTrace();
             Toast.makeText(mActivity, "打开相机失败!", Toast.LENGTH_SHORT).show();
            return false;
         }
       }
       return supportCameraFacing;
    }


    /**
     * 相机配置参数
     * */
    private void initParameters(Camera camera){
       try {
           mParameters = camera.getParameters();
           // 开启闪光灯
           //mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
           // 关闭闪光灯
           //mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
           // 设图像格式
           mParameters.setPreviewFormat(ImageFormat.NV21);
           //获取与指定宽高相等或最接近的尺寸
           //设置预览尺寸
           Camera.Size bestPreviewSize = getBestSize(mSurfaceView.getWidth(), mSurfaceView.getHeight(), mParameters.getSupportedPreviewSizes());
           if (bestPreviewSize != null){
               mParameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height);
           }

           // 设置保存图片尺寸
           Camera.Size bestPicSize =  getBestSize(picWidth, picHeight, mParameters.getSupportedPictureSizes());
           if (bestPicSize != null){
               mParameters.setPictureSize(bestPicSize.width, bestPicSize.height);
           }

           // 对焦模式
           if (isSupportFocus(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE))
               mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);

           camera.setParameters(mParameters);
       }catch (Exception e){
           e.printStackTrace();
           Toast.makeText(mActivity, "相机初始化失败!", Toast.LENGTH_SHORT).show();
       }

    }

    /**
     * 开始预览
     * */
    private void startPreview(){
        if (mCamera != null){
            try {
                mCamera.setPreviewDisplay(mSurfaceHolder);
                setCameraDisplayOrientation(mActivity);
                mCamera.startPreview();
                startFaceDetect();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void startFaceDetect() {
        if (mCamera != null){
            mCamera.startFaceDetection();
            mCamera.setFaceDetectionListener(new Camera.FaceDetectionListener() {
                @Override
                public void onFaceDetection(Camera.Face[] faces,Camera camera) {
                    mCallBack.onFaceDetect(transForm(faces));
                    Log.v("tag", "检测到"+faces.length+"张人脸");
                }
            });
        }
    }


    /**
     * 判断是否支持某一对焦模式
     */
    private Boolean isSupportFocus(String focusMode) {
        boolean autoFocus = false;

        List<String> listFocusMode =    mParameters.getSupportedFocusModes();
        for (String mode :listFocusMode) {
            if (mode == focusMode)
                autoFocus = true;
            Log.v("tag","相机支持的对焦模式:"+mode);
        }
        return autoFocus;
    }

    /**
     * 切换摄像头
     * */
    public void exchangeCamera() {
        releaseCamera();

       if (mCameraFacing == Camera.CameraInfo.CAMERA_FACING_BACK){
           mCameraFacing =Camera.CameraInfo.CAMERA_FACING_FRONT;// 前置摄像机
       } else {
           mCameraFacing = Camera.CameraInfo.CAMERA_FACING_BACK;// 后置摄像机
       }

        if (mCamera == null){
            openCamera(mCameraFacing);
        }
        startPreview();
    }

    /**
     *  释放摄像头资源
     */
    public void releaseCamera() {
        if (mCamera == null) {
            return;
        }

        try {
            mCamera.stopPreview();
            mCamera.setPreviewDisplay(null);
            mCamera.setPreviewCallback(null);
            mCamera.lock();
            mCamera.release();
            mCamera = null;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取与指定宽高相等或最接近的尺寸
     * */
    private Camera.Size getBestSize(int targetWidth,int targetHeight,List<Camera.Size> sizeList){
        Camera.Size bestSize = null;
        double targetRatio = Double.valueOf(targetHeight) / targetWidth;
        double minDiff = targetRatio;

        for (Camera.Size size:sizeList) {
            double supportedRatio = Double.valueOf(size.width)/size.height;
            Log.v("系统支持的尺寸:"+size.width+"*"+size.height, "比例:"+supportedRatio);
        }

        for (Camera.Size size:sizeList) {
           if (size.width == targetHeight && size.height == targetWidth){
               bestSize = size;
               break;
           }

           double supportedRatio = Double.valueOf(size.width)/size.height;
           if (Math.abs(supportedRatio - targetRatio) < minDiff){
               minDiff = Math.abs(supportedRatio - targetRatio);
               bestSize = size;
           }
        }

        Log.v("目标尺寸:"+targetWidth+"*"+targetHeight,   "比例:"+targetRatio);
        Log.v("最优尺寸",bestSize.height+"*"+bestSize.width);

        return bestSize;
    }

    /**
     * 解决预览变形问题
     *
     * @param sizes
     * @param w
     * @param h
     * @return
     */
    /*private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
        final double aspectTolerance = 0.1;
        double targetRatio = (double) w / h;
        if (sizes == null) {
            return null;
        }
        Camera.Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        int targetHeight = h;

        // Try to find an size match aspect ratio and size
        for (Camera.Size size : sizes) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > aspectTolerance) {
                continue;
            }
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        // Cannot find the one match the aspect ratio, ignore the requirement
        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Camera.Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }*/


    /**
     * 设置预览旋转角度
     * */
    private void setCameraDisplayOrientation(Activity activity){
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(mCameraFacing, info);
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();

        int screenDegree = 0;
        switch (rotation){
            case Surface.ROTATION_0:// 角度为0
                screenDegree = 0;
                break;
            case Surface.ROTATION_90:// 角度为90
                screenDegree = 90;
                break;
            case Surface.ROTATION_180:// 角度为180
                screenDegree = 180;
                break;
            case Surface.ROTATION_270:// 角度为270
                screenDegree = 270;
                break;
        }

        // 相机旋转角度
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){
            mDisplayOrientation = (info.orientation + screenDegree) % 360;
            mDisplayOrientation = (360 - mDisplayOrientation) % 360;// 补偿后视镜
        }else {
            mDisplayOrientation = (info.orientation - screenDegree + 360) % 360;
        }

        mCamera.setDisplayOrientation(mDisplayOrientation);
        Log.v("tag","屏幕的旋转角度 : "+rotation);
        Log.v("tag","setDisplayOrientation(result) : "+mDisplayOrientation);
    }


    /**
     * 判断是否支持某个相机
     * */
    private Boolean supportCameraFacing(int cameraFacing)  {
        Camera.CameraInfo info = new Camera.CameraInfo();
        for (int cameraIndex=0; cameraIndex<Camera.getNumberOfCameras(); cameraIndex++) {
            Camera.getCameraInfo(cameraIndex,  info);
            if (info.facing == cameraFacing)
                return true;
        }
        return false;
    }


    /**
     *  将相机中用于表示人脸矩形的坐标转换成UI页面的坐标
     */
    private ArrayList<RectF> transForm(Camera.Face[] faces) {
        Matrix matrix = new Matrix();
        // 设置为前摄像头 - Need mirror for front camera.
        mCameraFacing = Camera.CameraInfo.CAMERA_FACING_FRONT;
        int mirror = mCameraFacing;
       if (mirror>1){
           matrix.setScale(-1f,1f);
       }else {
           matrix.setScale(1f,1f);
       }
        // This is the value for android.hardware.Camera.setDisplayOrientation.
        matrix.postRotate(Float.valueOf(mDisplayOrientation));
        // Camera driver coordinates range from (-1000, -1000) to (1000, 1000).
        // UI coordinates range from (0, 0) to (width, height).
        matrix.postScale(mSurfaceView.getWidth() / 2000f, mSurfaceView.getHeight() / 2000f);
        matrix.postTranslate(mSurfaceView.getWidth() / 2f, mSurfaceView.getHeight() / 2f);

        ArrayList<RectF> rectList = new  ArrayList<RectF>();
        for (Camera.Face face : faces) {
            RectF srcRect = new RectF(face.rect);
            RectF dstRect = new RectF(0f,0f,0f,0f);
            matrix.mapRect(dstRect, srcRect);
            rectList.add(dstRect);
        }
        return rectList;
    }

    public Camera getmCamera(){
        Camera camera = null;

        if (mCamera != null)
            camera = mCamera;

        return camera;
    }

    public void addCallBack(CallBack callBack){
        this.mCallBack = callBack;
    }

    /**
     * 回调函数接口
     * */
    public interface CallBack{
        void onPreviewFrame(byte[] data);
        void onTakePic(byte[] data);
        void onFaceDetect(ArrayList<RectF> faces);
    }

    /**
     * 检测摄像头是否存在
     * */
    private boolean checkCameraHardware(Context context) {
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
            return true;
        } else {
            return false;
        }
    }

}

四、录像工具类

package com.chy.CCamera1;

import android.app.Activity;
import android.hardware.Camera;
import android.media.MediaRecorder;
import android.util.Log;
import android.view.Surface;
import android.widget.Toast;

import com.chy.util.FileUtil;
/**
 * 录像工具类
 * */
public class MediaRecorderHelper {

    private MediaRecorder mMediaRecorder = null;
    public boolean isRunning = false;
    private String filePath = null;

    private Activity mActivity;
    private Camera mCamera;
    private int rotation;
    private Surface surface;

    /**
     * 构造函数
     * */
    public MediaRecorderHelper(Activity _mActivity, Camera _mCamera, int _rotation, Surface _surface){
        this.mActivity = _mActivity;
        this.mCamera = _mCamera;
        this.rotation = _rotation;
        this.surface = _surface;
        initFilePath();
    }

    /**
     * 初始化文件方法
     * */
    private void initFilePath(){
        FileUtil fileUtil = new FileUtil(mActivity.getApplicationContext());
        filePath = fileUtil.createVideoFile().getAbsolutePath();
    }

    public void startRecord(){
        mMediaRecorder = new MediaRecorder();

        if (mMediaRecorder != null){
           try {
               mCamera.unlock();// 必须调用
               mMediaRecorder.reset();
               mMediaRecorder.setCamera(mCamera);
               mMediaRecorder.setOrientationHint(rotation);//改变保存后的视频文件播放时是否横屏(不加这句,视频文件播放的时候角度是反的)
               mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);//设置从麦克风采集声音
               mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);//设置从摄像头采集图像
               mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);//设置视频的输出格式为MP4
               mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);//设置音频的编码格式
               mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);// 设置视频的编码格式
               mMediaRecorder.setVideoSize(176, 144);// 设置视频大小.必须放在设置编码和格式的后面,否则报错
               mMediaRecorder.setVideoFrameRate(20);// 设置帧率
               //it.setMaxDuration(10000) //设置最大录像时间为10s
               mMediaRecorder.setPreviewDisplay(surface);//设置
               mMediaRecorder.setOutputFile(filePath);//设置输出文件
               mMediaRecorder.prepare();
               mMediaRecorder.start();
               isRunning = true;

               Log.d("tag", "开始录制视频");
               Log.d("tag", "视频保存路径:"+filePath);
           }catch (Exception e){
               e.printStackTrace();
           }
        }
    }

    public void stopRecord(){
       if (mMediaRecorder != null){
           mMediaRecorder.stop();
           isRunning = false;
           Log.d("tag", "停止录制视频");
           Toast.makeText(mActivity, "视频保存路径"+filePath, Toast.LENGTH_SHORT).show();
       }
    }

    public void release(){
        if (mMediaRecorder != null){
            mMediaRecorder.release();
            mMediaRecorder = null;
            isRunning = false;
        }
    }

}

五、使用方法

 /**
     * 按钮点击事件
     * */
    @Override
    public void onClick(View v) {
        switch (v.getId()){

            case R.id.btCamera:// Camera1 拍照事件
                PermissionUtil.getInstance().checkPermission(this,permissions,new Runnable() {
                    @Override
                    public void run() {
                       Intent intent = new Intent(MainActivity.this,CameraActivity1.class);
                       intent.putExtra(CameraActivity1.TYPE_TAG, CameraActivity1.TYPE_CAPTURE);
                       startActivity(intent);
                    }
                });
                break;
            case R.id.btCameraRecord:// Camera 录视频按钮
                PermissionUtil.getInstance().checkPermission(MainActivity.this,permissions,new Runnable() {
                    @Override
                    public void run() {
                        Intent intent = new Intent(MainActivity.this,CameraActivity1.class);
                        intent.putExtra(CameraActivity1.TYPE_TAG, CameraActivity1.TYPE_RECORD);
                        startActivity(intent);
                    }
                });
                break;
   
        }
    }

 

 六、权限动态获取方法

1、在AndroidManifest.xml中填写如下权限

<uses-permission android:name="android.permission.INTERNET" /> <!-- 网络权限 -->
<uses-permission android:name="android.permission.CAMERA" /> <!-- 相机权限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" /><!-- 音频录制权限-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><!-- 定位权限 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- 获取基站的服务信号权限,以便获取位置信息 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 写入数据权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!--读取数据权限  -->

2、在MainActivity.java中定义权限

// 动态申请权限
private String[] permissions = {
        Manifest.permission.INTERNET,// 网络权限
        Manifest.permission.CAMERA,// 相机权限
        Manifest.permission.RECORD_AUDIO,// 音频录制权限
        Manifest.permission.ACCESS_FINE_LOCATION,// 定位权限
        Manifest.permission.WRITE_EXTERNAL_STORAGE,// 写入数据权限
        Manifest.permission.READ_EXTERNAL_STORAGE,// 读取数据权限
        Manifest.permission.ACCESS_COARSE_LOCATION // 获取基站的服务信号权限,以便获取位置信息
};

3、创建动态申请权限工具类

package com.chy.util;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.provider.Settings;
import android.util.Log;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

public class PermissionUtil {

    private final int PERMISSION_REQUEST_CODE = 100;
    private final int PERMISSION_SETTING_CODE = 101;

    private AlertDialog permissionExplainDialog = null;
    private AlertDialog permissionSettingDialog = null;


    private PermissionUtil(){}

    public static PermissionUtil getInstance(){
        return PermissionUtilHolder.instance;
    }

    private static class PermissionUtilHolder{
        private static final PermissionUtil instance = new PermissionUtil();
    }


    /**
     * 第一步,检查权限
     *
     * @param activity 上下文
     * @param permissions 权限数组
     * @param callBack 线程
     * */
    public void checkPermission(AppCompatActivity activity,  String[] permissions, Runnable callBack){
        boolean allGranted = true;

        for (String permission : permissions) {
            int result = ContextCompat.checkSelfPermission(activity, permission);
            Log.d("检查权限:"+permission,"结果:"+result);


             // 有权限: PackageManager.PERMISSION_GRANTED
             // 无权限: PackageManager.PERMISSION_DENIED
            if (result != PackageManager.PERMISSION_GRANTED){// 有权限
                allGranted = false;
                Toast.makeText(activity,"拥有"+permission+"权限",Toast.LENGTH_SHORT).show();
            }

        }

        if (allGranted){// 拥有全部权限
            callBack.run();
        }else {// 申请权限
            startRequestPermission(activity, permissions);
        }
    }


    /**
     * 第二步,如果用户之前拒绝过,展示需要权限的提示框,否则的话直接请求相关权限
     *
     * @param activity 上下文
     * @param  permissions 权限数组
     * */
    private void startRequestPermission(AppCompatActivity activity, String[] permissions){
        for (String permission : permissions) {
            /**
             * shouldShowRequestPermissionRationale
             * 如果应用之前请求过该权限但用户拒绝了该方法就会返回true
             *
             * 如果用户之前拒绝了权限请求并且勾选了权限请求对话框的”不再询问”,该方法会返回false,
             * 如果设备策略禁止该应用获得该权限也会返回false
             */
            if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)){
                // 向用户显示一个解释,要以异步非阻塞的方式
                // 该线程将等待用户响应!等用户看完解释后再继续尝试请求权限
                Log.v("tag", "showPermissionExplainDialog()");
                showPermissionExplainDialog(activity, permissions);
            }else {
                /**
                 * 当你的应用调用requestPermissions()方法时,系统会向用户展示一个标准对话框,
                 * 你的应用不能修改也不能自定义这个对话框,如果你需要给用户一些额外的信息和解释你就需要在
                 * 调用requestPermissions()之前像上面一样" 解释为什么应用需要这些权限"
                 */
                Log.v("tag", "requestPermission");
                requestPermission(activity, permissions);
            }
        }
    }

    /**
     *  不需要向用户解释了,我们可以直接请求该权限
     *  第三步. 请求权限
     *
     * @param activity 上下文
     * @param permissions 权限数组
     */
    private void requestPermission(AppCompatActivity activity, String[] permissions){
        ActivityCompat.requestPermissions(activity, permissions, PERMISSION_REQUEST_CODE);
    }

    /**
     * 当用户之前拒绝过,展示一个对话框,解释为什么需要此权限
     *
     * @param activity 上下文
     * @param permissions 权限数组
     */
    private void showPermissionExplainDialog(final AppCompatActivity activity,final String[] permissions){
        if (permissionExplainDialog == null){
            permissionExplainDialog = new AlertDialog.Builder(activity).setTitle("权限申请").setMessage("您刚才拒绝了相关权限,但是现在应用需要这个权限," +
                    "点击确定申请权限,点击取消将无法使用该功能")
                    .setPositiveButton("确定",new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog,int which) {
                            requestPermission(activity, permissions);
                            dialog.cancel();
                        }
                    })
                    .setNegativeButton("取消",new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog,int which) {
                            dialog.cancel();
                        }
                    }).create();

                permissionExplainDialog.show();
        }
    }

    /**
     * 最后一步,当用户拒绝并且勾选了不在提示,那么只能引导用户去设置页面打开权限
     *
     * @param activity 上下文
     */
    public void showPermissionSettingDialog(final AppCompatActivity activity){
        if (permissionSettingDialog == null){
            permissionSettingDialog = new AlertDialog.Builder(activity)
                    .setTitle("权限设置")
                    .setMessage("您刚才拒绝了相关的权限,请到应用设置页面更改应用的权限")
                    .setPositiveButton("确定",new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog,int which) {
                            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                            Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
                            intent.setData(uri);

                            activity.startActivityForResult(intent, PERMISSION_SETTING_CODE);
                            dialog.cancel();
                        }
                    })
                    .setNegativeButton("取消",new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog,int which) {
                            dialog.cancel();
                        }
                    }).create();

            permissionSettingDialog.show();
        }
    }


}

4、使用动态申请权限方法

 PermissionUtil.getInstance().checkPermission(this,permissions,new Runnable() {
                    @Override
                    public void run() {
                        // 执行方法
                    }
                });

 

 

 

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值