Android-Camera+SurfaceView


Camera相机是属于硬件,每台设备的Camera硬件配置的参数都是不一样的,Camera通常是用来拍照,扫描二维码等等

 

AndroidManifest.xml配置Camera需要的权限:

  <!--
        打开相机是很危险的行为,加入权限
    -->
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.autofocus"/>

    <!-- 保存图片到sdcard外部存储 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

 

AndroidManifest.xml配置Activity 横屏显示 + 全屏:

    <!--
            设置横屏显示:     android:screenOrientation="landscape"
            设置无标题+全屏:  android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
        -->
        <activity android:name=".MyCameraActivity"
                  android:screenOrientation="landscape"
                  android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

        </activity>

 

activity_camera.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">

    <SurfaceView
        android:id="@+id/surface_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="对焦"
        android:layout_alignParentBottom="true"
        android:onClick="focus"
        />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="拍照"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:onClick="takepicture"
        />

</RelativeLayout>

 

MyCameraActivity.java

package liudeli.my_media1;

import android.app.Activity;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Toast;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class MyCameraActivity extends Activity {

    private final String TAG = MySurfaceViewActivity.class.getSimpleName();

    /**
     * 操作的是SurfaceHolder,所以定义全局变量
     */
    private SurfaceHolder surfaceHolder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_camera);

        // 获取在布局文件中定义的SurfaceView
        SurfaceView surfaceView = findViewById(R.id.surface_view);

        // 不能直接操作SurfaceView,需要通过SurfaceView拿到SurfaceHolder
        surfaceHolder = surfaceView.getHolder();

        // 使用SurfaceHolder设置屏幕高亮,注意:所有的View都可以设置 设置屏幕高亮
        surfaceHolder.setKeepScreenOn(true);

        // 使用SurfaceHolder设置把画面或缓存 直接显示出来
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        /**
         * 由于要观察SurfaceView生命周期,所以需要设置监听
         * 此监听不一样,是addCallback
         *
         */
        surfaceHolder.addCallback(callback);
    }

    /**
     * 定义相机对象
     */
    private Camera camera;

    /**
     * 定义SurfaceView监听回调
     */
    private SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {

        /**
         * SurfaceView被创建了
         * @param holder
         */
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            /**
             * 只有在SurfaceView生命周期方法-->SurfaceView被创建后在打开相机
             * 以前我在 onResume 之前去打开相机,结果报错了,所以只有在这里打开相机,才是安全🔐
             */
            // Camera要选择hardware.Camera,因为Camera属于硬件hardware
            // Camera.open(1); // 这了传入的值,可以指定为:前置摄像头/后置摄像头
            camera = Camera.open(0);

            /**
             * 设置Camera与SurfaceHolder关联,Camera的数据让SurfaceView显示
             */
            try {
                camera.setPreviewDisplay(holder);
            } catch (IOException e) {
                e.printStackTrace();
                Log.e(TAG, "相机设置预览失败");
            }

            /**
             * 开始显示
             */
            camera.startPreview();
        }

        /**
         * SurfaceView发生改变了
         * @param holder
         * @param format
         * @param width
         * @param height
         */
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            // 以后做具体业务功能的时候,才会用到改变的值来处理
            // ......
        }

        /**
         * SurfaceView被销毁了
         * @param holder
         */
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            /**
             * SurfaceView被销毁后,一定要释放硬件资源,Camera是硬件
             */
            camera.stopPreview(); // (一定要有,不然只release也可能出问题)
            camera.release();
            camera = null;
            System.gc();
        }
    };

    /**
     * 拍照
     */
    public void takepicture(View view) {
        if (null != camera) {
            /**
             * 参数一:相机的快门,咔嚓,这里用不到
             * 参数二:相机原始的数据
             * 参数三:相机处理后的数据
             */
            camera.takePicture(null, null, pictureCallback);
        }
    }

    /**
     * 相机处理后的数据回调
     */
    private Camera.PictureCallback pictureCallback = new Camera.PictureCallback() {
        /**
         * 拍照完成,可以拿到数据了
         * @param data 数据
         * @param camera
         */
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            // 写在指定目录 sdcard 中去
            File file = new File(Environment.getExternalStorageDirectory(), "pictureCallback.jpg");
            try {
                // 字节文件输出流,把byte[]数据写入到文件里面去
                OutputStream os = new FileOutputStream(file);
                os.write(data);

                // 关闭字节文件输出流
                os.close();
            } catch (Exception e) {
                e.printStackTrace();
                Log.e(TAG, "保存失败");
                Toast.makeText(MyCameraActivity.this, "照片保存失败", Toast.LENGTH_SHORT).show();
            }
        }
    };

    /**
     * 对焦
     */
    public void focus(View view) {
        // 对焦都是硬件设备来完成的
        camera.autoFocus(null);
    }

    /**
     * 当Activity被销毁的时候,一定要移除监听
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, ">>>> onDestroy()");
        if (null != callback) surfaceHolder.removeCallback(callback);
    }
}

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM