Android 自定義Camera SurfaceView 拍照自動旋轉圖片及保存

前言:抱着最起碼的要求盡力去做好每一件事 ! ——秋不白

本文適用針對項目的相機多張拍攝,查看圖庫(自己寫的,查看自己拍攝的照片,不包含系統圖庫和其他文件夾的圖片),其實也是自己項目中不斷總結,爲什麼還要寫個自定義相機呢,因爲之前項目中寫的不夠好,拍照圖片的旋轉啊,現在離開公司了,總覺得還欠缺點什麼,如有需要可以聯繫我,代碼還沒有上傳github(後面我再放到gitbug),有興趣,請移步https://gitee.com/redrose/Demo,查看完整代碼。

我定義了Photo和classPhoto兩個java bean,快速開發就接入了LitePal,Glide,鴻洋大神的適配器,

圖庫效果截圖:

相機預覽界面

功能:重力傳感器監聽手機橫着豎着,(比如豎着拍攝的照片,查看的時候希望是橫着的,而不是豎着),動態修改相機參數,保存照片,以及加載圖片。

申請權限,權限要自己加了

前提:

1 自定義SurfaceView(還有GLSurfaceView,TextureView,使用SurfaceView,最簡單,畢竟是Google親兒子,都封裝好了)

2.Camera 工具類,(單利模式管理Camera對象,參數設置,釋放資源等)(封成工具類,方便後面自己用GLSurfaceView,TextureView去實現相機,以及後面接入openGL,,或者opencv 做人臉識別,識別人臉拍照等等)

Camera工具類

package com.redrose.videodemo.camera;

import android.graphics.ImageFormat;
import android.hardware.Camera;

import java.util.List;

/**
 * Desc: 相機工具類
 * author: RedRose
 * Date: 2019/3/20
 * Email: [email protected]
 */

public class CameraUtil {
    private static CameraUtil mInstance;
    /**
     * 相機參數對象
     */
    private Camera.Parameters mParameters;
    /**
     * 閃光燈自動
     */
    public static final int FLASH_AUTO = 0;
    /**
     * 閃光燈關閉
     */
    public static final int FLASH_OFF = 1;
    /**
     * 閃光燈開啓
     */
    public static final int FLASH_ON = 2;

    private CameraUtil() {
    }

    private static final Object o = new Object();

    public static CameraUtil getInstance() {
        if (mInstance == null) {
            synchronized (o) {
                if (mInstance == null) {
                    mInstance = new CameraUtil();
                }
            }
        }
        return mInstance;
    }

    private Camera mCamera;

    public Camera openCamera() {
        // 0 表示開啓後置相機
        return openCamera(0);
    }

    public Camera openCamera(int id) {
        if (mCamera == null) {
            mCamera = Camera.open(id);
        }
        setProperty();
        return mCamera;
    }

    /**
     * 相機屬性設置
     */
    private void setProperty() {
        //設置相機預覽頁面旋轉90°,(默認是橫屏)
        mCamera.setDisplayOrientation(90);
        mParameters = mCamera.getParameters();
        //設置將保存的圖片旋轉90°(豎着拍攝的時候)
        mParameters.setRotation(90);
        mParameters.setPreviewSize(1920, 1080);
        mParameters.setPictureSize(1920, 1080);
//        mParameters.setPictureSize(4608, 3456);
        mParameters.setPictureFormat(ImageFormat.JPEG);
        mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
//        mParameters.set(ImageFormat.YUV_444_888);
        mCamera.setParameters(mParameters);
    }
    /**
     * 選裝圖片的角度
     */
    public void setRotateDegree(int degree) {
//        boolean result = degree == 0 || degree == 90
//        mParameters.setRotation(90);
        if (mCamera != null) {
            mParameters = mCamera.getParameters();
            mParameters.setRotation(degree);
            mCamera.setParameters(mParameters);
        }

    }

    /**
     * 獲取支持的預覽分辨率
     */
    public List<Camera.Size> getPreviewSizeList() {
        if (mCamera == null) {
            throw new NullPointerException("Camera can not be null");
        }
        return mCamera.getParameters().getSupportedPreviewSizes();
    }

    /**
     * 獲取保存圖片支持的分辨率
     */
    public List<Camera.Size> getPictureSizeList() {
        if (mCamera == null) {
            throw new NullPointerException("Camera can not be null");
        }
        return mCamera.getParameters().getSupportedPictureSizes();
    }

    /**
     * 設置閃光燈模式
     */
    public void setFlashMode(int mode) {
        mParameters = mCamera.getParameters();
        String flashMode = mParameters.getFlashMode();
        switch (mode) {
            case FLASH_AUTO:
                mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
                break;
            case FLASH_OFF:
                mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
                break;
            case FLASH_ON:
                mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
                break;
            default:
                break;
        }
        mCamera.setParameters(mParameters);
    }

    /**
     * 釋放相機資源
     */
    public void releaseCamera() {
        if (mCamera != null) {
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.lock();
            mCamera.release();
            mCamera = null;
            isRelease = true;
        }
    }
    /**
     * 是否旋轉圖片 true 選裝
     */
    private boolean isRelease = false;

    public boolean getIsRelease() {
        return isRelease;
    }
    /**
     * 設置保存圖片的分辨率
     */
    public void setSaveSize(Camera.Size saveSize) {
        mParameters.setPictureSize(saveSize.width, saveSize.height);
        mCamera.setParameters(mParameters);
    }
}

自定義SurfaceView

package com.redrose.videodemo.camera;

import android.content.Context;
import android.hardware.Camera;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import com.redrose.videodemo.utils.BitmapCallBack;
import com.redrose.videodemo.utils.LogUtils;
import com.redrose.videodemo.utils.ToastUtil;
import com.redrose.videodemo.utils.ToolUtils;

import java.io.IOException;

/**
 * Desc:
 * Author: RedRose
 * Date: 2019/3/20
 * Email: [email protected]
 */

public class Preview extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback, Camera.PictureCallback {

    private Camera mCamera;
    private BitmapCallBack mBitmapCallback;
    private static final String TAG = Preview.class.getSimpleName();

    public Preview(Context context) {
        this(context, null);
    }

    public Preview(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public Preview(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mCamera = CameraUtil.getInstance().openCamera();
        SurfaceHolder holder = getHolder();
        holder.addCallback(this);
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        LogUtils.e(TAG, " --surfaceCreated--");
        try {
            //這裏必須要這樣處理,比如鎖屏,回到桌面,再次回到相機的時候,surfaceCreated 會重新執行
            //所以,要加個標識,判斷是否被釋放過資源
            if (CameraUtil.getInstance().getIsRelease()) {
                mCamera = CameraUtil.getInstance().openCamera();
            }
            mCamera.setPreviewDisplay(holder);
        } catch (IOException e) {
            e.printStackTrace();
        }
        mCamera.setPreviewCallback(this);
        mCamera.startPreview();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        LogUtils.e(TAG, " --surfaceChanged--");
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        LogUtils.e(TAG, " --surfaceDestroyed--");
        //每次 執行surfaceDestroyed,都要銷燬,釋放camera
        CameraUtil.getInstance().releaseCamera();
    }
    /**
     * 預覽回調
     */
    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {

    }
    /**
     * 拍攝成功後回調
     */
    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        if (mBitmapCallback != null) {
            mBitmapCallback.backByte(data);
        }
        camera.startPreview();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        /**
         * 觸摸聚焦
         */
        mCamera.autoFocus(new Camera.AutoFocusCallback() {
            @Override
            public void onAutoFocus(boolean success, Camera camera) {
                if (success) {
                    ToastUtil.show(getContext(), "聚焦成功");
                    camera.cancelAutoFocus();
                }
            }
        });
        return super.onTouchEvent(event);
    }

    public void takePhoto() {
        mCamera.autoFocus(new Camera.AutoFocusCallback() {
            @Override
            public void onAutoFocus(boolean success, Camera camera) {
                //設置聚焦成功後再拍照,其實可以不用。看需求吧,可以直接調用takePicture()
                //有些手機會聚焦失敗,也就是success是false
                if (success) {
                    ToastUtil.show(getContext(), "聚焦成功");
                    camera.cancelAutoFocus();
                    mCamera.takePicture(null, null, Preview.this);
                }
            }
        });
    }
    /**
     * 設置回調到Activity吧
     */
    public void setBitmapCallback(BitmapCallBack callback) {
        this.mBitmapCallback = callback;
    }
}
public interface BitmapCallBack {
    void backByte(byte[] data);
}

CamreaActivity

package com.redrose.videodemo.camera;

import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.hardware.Camera;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.TextView;

import com.redrose.videodemo.base.BaseActivity;

import org.litepal.crud.DataSupport;
import org.xutils.view.annotation.ContentView;
import org.xutils.view.annotation.Event;
import org.xutils.view.annotation.ViewInject;

import com.redrose.videodemo.R;
import com.redrose.videodemo.bean.Photo;
import com.redrose.videodemo.bean.Time;
import com.redrose.videodemo.utils.BitmapCallBack;
import com.redrose.videodemo.utils.GlideUtils;
import com.redrose.videodemo.utils.IntentUtils;
import com.redrose.videodemo.utils.LogUtils;
import com.redrose.videodemo.utils.MySensorHelper;
import com.redrose.videodemo.utils.SPUtils;
import com.redrose.videodemo.utils.ToastUtil;
import com.redrose.videodemo.utils.ToolUtils;
import com.zhy.adapter.recyclerview.CommonAdapter;
import com.zhy.adapter.recyclerview.base.ViewHolder;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

/**
 * Desc:
 * Author: RedRose
 * Date: 2019/3/20
 * Email: [email protected]
 */
@ContentView(R.layout.activity_camera)
public class CameraActivity extends BaseActivity implements BitmapCallBack {
    @ViewInject(R.id.pre_text)
    private TextView mPreSize;
    @ViewInject(R.id.save_text)
    private TextView mSaveSize;
    @ViewInject(R.id.flashlight)
    private ImageView mFlashView;
    @ViewInject(R.id.photo_list)
    private ImageView mPreImageView;
    @ViewInject(R.id.take_photo)
    private View mTakePhoto;
    @ViewInject(R.id.camera_preview)
    private Preview mPreview;
    private boolean showLocation = false;
    private PopupWindow mPopWindow;
    private List<Photo> mPhotoList;
    private Time mTime;
    /**
     * 是否旋轉圖片
     * true 表示當前Activity 處於橫屏,false:當前處於豎屏
     */
    private boolean mIsRotate = false;
    /**
     * 重力傳感器監聽
     * 橫着 豎着狀態
     */
    private MySensorHelper mMySensor;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initData();
    }

    private void initData() {
        mMySensor = new MySensorHelper(this);
        mMySensor.enable();
        int mode = SPUtils.getInt("Flash_mode");
        initFlashMode(mode);
        mPreview.setBitmapCallback(this);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        Calendar calendar = Calendar.getInstance();
        String format = sdf.format(calendar.getTime());
        mTime = new Time();
        mTime.setClassId(Long.parseLong(format));
        mTime.setDay(calendar.get(Calendar.DAY_OF_MONTH));
        mTime.setYear(calendar.get(Calendar.YEAR));
        mTime.setMonth(calendar.get(Calendar.MONTH) + 1);
        mPhotoList = new ArrayList<>();
    }

    private void showPopWindow(View view) {
        mPopWindow = new PopupWindow(view, ToolUtils.dp2px(mContext.getApplicationContext(),
                200), ToolUtils.dp2px(mContext.getApplicationContext(), 200));
        mPopWindow.setFocusable(true);
//        popupWindow.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#3F51B5")));
        mPopWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        mPopWindow.setOutsideTouchable(true);
        mPopWindow.update();
        if (showLocation) {
            mPopWindow.showAsDropDown(mSaveSize);
        } else {
            mPopWindow.showAsDropDown(mPreSize);
        }
    }

    /**
     * 顯示支持保存的分辨率
     */
    private void showSupportSize(List<Camera.Size> list) {
        LayoutInflater inflater = LayoutInflater.from(mContext);
        View view = inflater.inflate(R.layout.pop_size_layout, null);
        RecyclerView recycleView = view.findViewById(R.id.recycle_size);
        initRecycle(recycleView);
        SizeAdapter mAdapter = new SizeAdapter(mContext, R.layout.size_item, list);
        recycleView.setAdapter(mAdapter);
        showPopWindow(view);
    }

    @Event(value = {R.id.pre_text, R.id.save_text, R.id.flashlight, R.id.take_photo, R.id.photo_list,
            R.id.all_list})
    private void onclickView(View view) {
        int id = view.getId();
        switch (id) {
            /*暫時註釋 動態設置預覽分辨率*/
            case R.id.pre_text:
                /*預覽分辨率,建議設置成屏幕分辨率,經測試,支持的最高就是屏幕分辨率 */
                showLocation = false;
                showSupportSize(CameraUtil.getInstance().getPreviewSizeList());
                break;
            //設置保存圖片的分辨率
            case R.id.save_text:
                showLocation = true;
                showSupportSize(CameraUtil.getInstance().getPictureSizeList());
                break;
            //切換閃光燈模式
            case R.id.flashlight:
                int mode = SPUtils.getInt("Flash_mode");
                if (mode == CameraUtil.FLASH_AUTO) {
                    mode = CameraUtil.FLASH_OFF;
                } else if (mode == CameraUtil.FLASH_OFF) {
                    mode = CameraUtil.FLASH_ON;
                } else if (mode == CameraUtil.FLASH_ON) {
                    mode = CameraUtil.FLASH_AUTO;
                }
                SPUtils.put("Flash_mode", mode);
                initFlashMode(mode);
                break;
            //拍照
            case R.id.take_photo:
                mPreview.takePhoto();
                break;
            //打開當前拍攝的照片圖庫
            case R.id.photo_list:
                int size = mPhotoList.size();
                if (size == 0) {
                    ToastUtil.show(mContext, "還未拍攝照片,可以點擊右側查看所有照片");
                    return;
                }
                Bundle bundle = new Bundle();
                bundle.putSerializable("photoList", (ArrayList<Photo>) mPhotoList);
                IntentUtils.goToPreviewActivity(mContext, bundle);
                break;
            //打開圖庫
            case R.id.all_list:
                IntentUtils.goToImageActivity(mContext, null);
                break;
            default:
                break;
        }
    }

    private void initRecycle(RecyclerView recyclerView) {
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        //設置佈局管理器
        recyclerView.setLayoutManager(layoutManager);
        //設置爲垂直佈局,這也是默認的
        layoutManager.setOrientation(OrientationHelper.VERTICAL);
        //設置Adapter
//        recyclerView.setAdapter(recycleAdapter);
        //設置分隔線
//        recyclerView.addItemDecoration(new DividerGridItemDecoration(this));
        //設置增加或刪除條目的動畫
        recyclerView.setItemAnimator(new DefaultItemAnimator());
    }

    @Override
    public void backByte(byte[] data) {
        GlideUtils.loadByte(mPreImageView, data);
        ToolUtils.saveImageFile(data, mPhotoList, mIsRotate);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        Calendar calendar = Calendar.getInstance();
        String format = sdf.format(calendar.getTime());
        List<Time> times = DataSupport.where("classId = ?", format).find(Time.class);
        mTime.setPhotoList(mPhotoList);
        if (times.size() == 0) {
            mTime.save();
        }
    }

    /**
     * Desc: 相機頁面,拍攝照片保存分辨率 顯示適配器
     * author: RedRose
     * Date: 2019/4/1
     * Email: [email protected]
     */
    private class SizeAdapter extends CommonAdapter<Camera.Size> {

        private SizeAdapter(Context context, int layoutId, List<Camera.Size> datas) {
            super(context, layoutId, datas);
        }

        @Override
        protected void convert(ViewHolder holder, Camera.Size size, int position) {
            LogUtils.d("----redrose 裝載數據測試 ----");
            TextView textView = holder.getView(R.id.size_text);
            String sizeString = String.format("%d * % d", size.width, size.height);
            textView.setText(sizeString);
            if (showLocation) {
                textView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        CameraUtil.getInstance().setSaveSize(size);
                        if (mPopWindow != null) {
                            mPopWindow.dismiss();
                            mPopWindow = null;
                        }
                        ToastUtil.show(mContext, size.width + "x" + size.height);
                    }
                });
            }
        }
    }

    private void initFlashMode(int mode) {
        if (mode == CameraUtil.FLASH_AUTO) {
            mFlashView.setImageResource(R.mipmap.flash_auto);
        } else if (mode == CameraUtil.FLASH_OFF) {
            mFlashView.setImageResource(R.mipmap.flash_off);
        } else if (mode == CameraUtil.FLASH_ON) {
            mFlashView.setImageResource(R.mipmap.flash_on);
        }
        CameraUtil.getInstance().setFlashMode(mode);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mMySensor.disable();
        LogUtils.e(TAG, " ---onDestroy---");
    }
    /**
     * 是否旋轉圖片
     */
    public void setIsRotate(boolean isRotate) {
        if(mIsRotate == isRotate){
            return;
        }
        this.mIsRotate = isRotate;
        if (mIsRotate) {
            CameraUtil.getInstance().setRotateDegree(0);
        }else {
            CameraUtil.getInstance().setRotateDegree(90);
        }
    }
    public boolean getIsRotate(){
        return mIsRotate;
    }
}

重力監聽傳感器,判斷手機是橫着還是豎着

package com.redrose.videodemo.utils;

import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.util.Log;
import android.view.OrientationEventListener;

import com.redrose.videodemo.camera.CameraActivity;

import java.lang.ref.WeakReference;

/**
 * Desc:
 * 手機橫着豎着監聽
 *
 * @author: RedRose
 * Date: 2019/4/2
 * Email: [email protected]
 */

public class MySensorHelper {
    private static final String TAG = MySensorHelper.class.getSimpleName();
    private OrientationEventListener mLandOrientationListener;
    private OrientationEventListener mPortOrientationListener;
    private WeakReference<CameraActivity> mActivityWeakRef;
    private boolean isPortLock = false;
    private boolean isLandLock = false;

    public MySensorHelper(final CameraActivity activity) {
        this.mActivityWeakRef = new WeakReference(activity);
        this.mLandOrientationListener = new OrientationEventListener(activity, 3) {
            public void onOrientationChanged(int orientation) {
                LogUtils.d(MySensorHelper.TAG, "mLandOrientationListener");
                if (orientation < 100 && orientation > 80 || orientation < 280 && orientation > 260) {
                    LogUtils.e(MySensorHelper.TAG, "轉到了橫屏");
                    if (!MySensorHelper.this.isLandLock) {
                        CameraActivity mActivity = MySensorHelper.this.mActivityWeakRef.get();
                        if (mActivity != null) {
                            LogUtils.e(MySensorHelper.TAG, "轉到了橫屏##################");
                            /*mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                            isLandLock=true;
                            isPortLock=false;*/
                            if (!mActivity.getIsRotate()) {

                                mActivity.setIsRotate(true);
                            }
                        }
                    }
                }

            }
        };
        this.mPortOrientationListener = new OrientationEventListener(activity, 3) {
            public void onOrientationChanged(int orientation) {
                LogUtils.d(MySensorHelper.TAG, "mPortOrientationListener");
                if (orientation < 10 || orientation > 350 || orientation < 190 && orientation > 170) {
                    LogUtils.e(MySensorHelper.TAG, "轉到了豎屏");
                    if (!MySensorHelper.this.isPortLock) {
                        CameraActivity mActivity = MySensorHelper.this.mActivityWeakRef.get();
                        if (mActivity != null) {
                            LogUtils.e(MySensorHelper.TAG, "轉到了豎屏!!!!!!!!!!!!!!!!!!!!!!");
                            /*mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                            isPortLock=true;
                            isLandLock=false*/
                            ;
                            if (mActivity.getIsRotate()) {
                                mActivity.setIsRotate(false);
                            }
                        }
                    }
                }

            }
        };
        //this.disable();
    }

    //禁用切換屏幕的開關
    public void disable() {
        Log.e(TAG, "disable");
        this.mPortOrientationListener.disable();
        this.mLandOrientationListener.disable();
    }

    //開啓橫豎屏切換的開關
    public void enable() {
        this.mPortOrientationListener.enable();
        this.mLandOrientationListener.enable();
    }

    //設置豎屏是否上鎖,true鎖定屏幕,fanle解鎖
    public void setPortLock(boolean lockFlag) {
        this.isPortLock = lockFlag;
    }

    //設置橫屏是否鎖定,true鎖定,false解鎖
    public void setLandLock(boolean isLandLock) {
        this.isLandLock = isLandLock;
    }
}

依賴的jar

implementation 'com.android.support:recyclerview-v7:26+'
implementation 'org.xutils:xutils:3.3.36'
implementation 'com.zhy:base-adapter:3.0.3'
implementation 'com.zhy:base-rvadapter:3.0.3'

CameraActivity 佈局xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.redrose.videodemo.camera.Preview
        android:id="@+id/camera_preview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <TextView
        android:visibility="gone"
        android:id="@+id/pre_text"
        style="@style/camera_button_style"
        android:text="預覽分辨率" />
    <TextView
        android:layout_marginEnd="10dp"
        android:layout_alignParentEnd="true"
        android:id="@+id/save_text"
        style="@style/camera_button_style"
        android:text="保存分辨率" />

    <ImageView
        android:layout_marginTop="20dp"
        android:layout_centerHorizontal="true"
        android:src="@mipmap/flash_on"
        android:id="@+id/flashlight"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <View
        android:id="@+id/take_photo"
        android:layout_marginBottom="20dp"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true"
        android:background="@drawable/take_photo_selector"
        android:layout_width="56dp"
        android:layout_height="56dp"/>
    <ImageView
        android:layout_alignParentBottom="true"
        android:layout_marginStart="10dp"
        android:layout_marginBottom="10dp"
        android:src="@mipmap/ic_launcher"
        android:id="@+id/photo_list"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <ImageView
        android:layout_marginEnd="10dp"
        android:layout_marginBottom="10dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentEnd="true"
        android:src="@mipmap/ic_launcher"
        android:id="@+id/all_list"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>

共享參數工具類

/*
 *
 *   Copyright 2016 YunDi
 *
 *   The code is part of Yunnan, Shenzhen Branch of the internal architecture of YunDi source group
 *
 *   DO NOT DIVULGE
 *
 */

package com.redrose.videodemo.utils;


import android.content.Context;
import android.content.SharedPreferences;

import org.xutils.common.util.LogUtil;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;


public class SPUtils {

    public static final String TAG = SPUtils.class.getSimpleName();

    public static final String KEY_USER_INFO = "user_info";

    private static Context mContext;

    public static void init(Context context) {
        mContext = context;
    }

    /**
     * 保存在手機裏面的文件名
     */
    public static final String FILE_NAME = "share_data";

    /**
     * 保存數據的方法,我們需要拿到保存數據的具體類型,然後根據類型調用不同的保存方法
     *
     * @param key
     * @param object
     */
    public static void put(String key, Object object) {
        SharedPreferences sp = mContext.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();

        if (object instanceof String) {
            editor.putString(key, (String) object);
        } else if (object instanceof Integer) {
            editor.putInt(key, (Integer) object);
        } else if (object instanceof Boolean) {
            editor.putBoolean(key, (Boolean) object);
        } else if (object instanceof Float) {
            editor.putFloat(key, (Float) object);
        } else if (object instanceof Long) {
            editor.putLong(key, (Long) object);
        } else {
            editor.putString(key, object.toString());
        }
        editor.commit();
    }

    public static String getString(String key) {
        SharedPreferences sp = mContext.getSharedPreferences(FILE_NAME,
                Context.MODE_PRIVATE);
        return sp.getString(key, null);
    }

    public static int getInt(String key) {
        SharedPreferences sp = mContext.getSharedPreferences(FILE_NAME,
                Context.MODE_PRIVATE);
        return sp.getInt(key, 0);
    }

    public static long getLong(String key) {
        return (long) get(key, 0);
    }

    public static float getFloat(String key) {
        return (float) get(key, 0f);
    }


    public static boolean getBoolean(String key) {
        return (boolean) get(key, false);
    }


    /**
     * 得到保存數據的方法,我們根據默認值得到保存的數據的具體類型,然後調用相對於的方法獲取值
     *
     * @param key
     * @param defaultObject
     * @return
     */
    public static Object get(String key, Object defaultObject) {
        SharedPreferences sp = mContext.getSharedPreferences(FILE_NAME,
                Context.MODE_PRIVATE);

        if (defaultObject instanceof Integer) {
            return sp.getInt(key, (Integer) defaultObject);
        } else if (defaultObject instanceof Boolean) {
            return sp.getBoolean(key, (Boolean) defaultObject);
        } else if (defaultObject instanceof Float) {
            return sp.getFloat(key, (Float) defaultObject);
        } else if (defaultObject instanceof Long) {
            return sp.getLong(key, (Long) defaultObject);
        }

        return null;
    }

    /**
     * 移除某個key值已經對應的值
     *
     * @param key
     */
    public static void remove(String key) {
        SharedPreferences sp = mContext.getSharedPreferences(FILE_NAME,
                Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.remove(key);
        SharedPreferencesCompat.apply(editor);
    }

    /**
     * 清除所有數據
     */
    public static void clear() {
        SharedPreferences sp = mContext.getSharedPreferences(FILE_NAME,
                Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.clear();
        SharedPreferencesCompat.apply(editor);
    }

    /**
     * 查詢某個key是否已經存在
     *
     * @param key
     * @return
     */
    public static boolean contains(String key) {
        SharedPreferences sp = mContext.getSharedPreferences(FILE_NAME,
                Context.MODE_PRIVATE);
        return sp.contains(key);
    }

    /**
     * 返回所有的鍵值對
     *
     * @return
     */
    public static Map<String, ?> getAll() {
        SharedPreferences sp = mContext.getSharedPreferences(FILE_NAME,
                Context.MODE_PRIVATE);
        return sp.getAll();
    }


    /**
     * 創建一個解決SharedPreferencesCompat.apply方法的一個兼容類
     */
    private static class SharedPreferencesCompat {
        private static final Method sApplyMethod = findApplyMethod();

        /**
         * 反射查找apply的方法
         *
         * @return
         */
        @SuppressWarnings({"unchecked", "rawtypes"})
        private static Method findApplyMethod() {
            try {
                Class clz = SharedPreferences.Editor.class;
                return clz.getMethod("apply");
            } catch (NoSuchMethodException e) {
            }

            return null;
        }

        /**
         * 如果找到則使用apply執行,否則使用commit
         *
         * @param editor
         */
        public static void apply(SharedPreferences.Editor editor) {
            try {
                if (sApplyMethod != null) {
                    sApplyMethod.invoke(editor);
                    return;
                }
            } catch (IllegalArgumentException e) {
            } catch (IllegalAccessException e) {
            } catch (InvocationTargetException e) {
            }
            editor.commit();
        }
    }

}

有的同學實現這個功能後,在打開系統圖庫的時候,看不見這張圖片,是因爲系統每次開機時會去檢索圖片等資源,把索引存到數據庫,所以要通知刷新媒體庫,要發廣播通知系統刷新(如何發,百度一大把,我就不贅述了)。

先就這麼多吧,最關鍵的就是自定義SurfaceView和CameraUtil 工具類。可以接着後面,繼續寫,實現更多的需求,我的目標是使用MediaCodeC錄製編碼小視頻和解碼,這部分還未完成。改天推到gitbub,就可以拉完整代碼了

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