相机的调用

本文介绍如何在Android上开发相机应用程序,包括使用Camera API的基本方法、创建预览界面、实现拍照功能及图片存储等。文中还提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

相机的用法

参考:

http://www.2cto.com/kf/201401/272099.html

侵立删。

最近在学习Android硬件Camera的调用,所以结合书本和网上博客练练手。
需要注意

  • 此API 21(Lollipop android 5.0)就开始弃用
    建议学习最新的camera2,不然使用as总是弹出deprecate(弃用)。
  • 调试时,不能用API 23 (marshmallow android 6.0)调试,因为此版本的camera的permission为动态的,静态的permission不可用。
  • 下面有使用方法,禁止as 弹通知。
    步骤:

  1. 检查和访问摄像头存在与数目
    由于camera为单进程占用硬件,使用之前需要检查是否被占用,否则会与其他程序冲突,无法使用。同理,使用完一定要释放camera资源,以便留给其他进程使用。
    //    官方建议的安全地访问摄像头的方法
    public static Camera getCameraInstance() {
        Camera c = null;
          try {
            c = Camera.open();
//返回一个新建Camera对象
        } catch (Exception e) {
            Log.d("Tag", "Error is" + e.getMessage());
        }
        return c;
    }

检查设备是否支持摄像头


    //    检查设备是否支持摄像头
    public boolean CheckCameraHardware(Context mContext) {
        if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
//            摄像头存在
            return true;
        } else {
//            摄像头不存在
            return false;
        }
    }

摄像头数量

        int cameraNum = Camera.getNumberOfCameras();
        //一般有两个,0为后置,1为前置
        mCamera = getCameraInstance();
        if (mCamera != null) {
            mCamera.startPreview();
        }
        Log.d("Tag77", "CameraNum:" + cameraNum);

释放相机资源。

        if (mCamera != null) {
//            释放相机资源
            mCamera.release();
            mCamera = null;
        }
  1. 创建预览类
//CameraView.java
/**
 * Created by ss on 2016/10/29.
 *基本的相机预览类
 */
 //小写传参,禁止deprecation 弹出
@SuppressWarnings("deprecation")
public class CameraView extends SurfaceView implements SurfaceHolder.Callback {
    //相机类
    private Camera mCamera;
    private SurfaceHolder mHolder;
    public CameraView(Context mContext,Camera mCamera) {
        super(mContext);
        this.mCamera=mCamera;
        //创建和销毁底层surface时可以获得通知
        mHolder =getHolder();
        //添加SurfaceHolder.Callback
        mHolder.addCallback(this);
        //已经在API 11就失效了
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    }
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    try{
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();
        //mCamera.setPreviewDisplay(holder);
        mCamera.setDisplayOrientation(90);
        //clockwise顺时针旋转90
    }
    catch (IOException e) {
        Log.d("Tag","Error is"+e.getMessage());
    }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // 如果预览无法更改或旋转,注意此处的事件
        // 确保在缩放或重排时停止预览
        if (mHolder.getSurface() == null){
            // 预览surface不存在
            return;
        }
        // 更改时停止预览
        try {
            mCamera.stopPreview();
        } catch (Exception e){
            // 忽略:试图停止不存在的预览
        }
        // 在此进行缩放、旋转和重新组织格式
        // 以新的设置启动预
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.setDisplayOrientation(90);
            mCamera.startPreview();
        } catch (Exception e){
            Log.d("TAG", "Error is " + e.getMessage());
        }
    }
}
  1. 创建相机UI
    UI为一个照相并保存的按钮,一个退出按钮,一个图片显示器(ImageView)。
<FrameLayout
    android:id="@+id/frameLayout"
    android:layout_width="match_parent"
    android:layout_weight="1"
    android:layout_height="0dp" />
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_weight="0.2"
    android:layout_height="0dp">
    <Button
        android:id="@+id/BtnCapture"
        android:text="@string/button_name"
        android:layout_width="60dp"
        android:layout_height="30dp" />

    <ImageView
            android:id="@+id/thumbsView"
            android:layout_alignParentRight="true"
            android:layout_alignParentEnd="true"
            android:layout_centerVertical="true"      
     android:contentDescription="@string/content_description"
            android:layout_width="60dp"
            android:layout_height="60dp"/>

    <Button
        android:id="@+id/BtnExit"
        android:text="@string/button_exit"
        android:layout_width="60dp"
        android:layout_height="30dp"
        android:layout_alignParentTop="true"
        android:layout_toRightOf="@+id/BtnCapture"
        android:layout_toEndOf="@+id/BtnCapture"
        android:layout_marginLeft="60dp"
        android:layout_marginStart="30dp" />
</RelativeLayout>
</LinearLayout>
  1. 采集图片与Uri
    主要重写两个函数,PictureCallback和ShutterCallback
    拍照回调接口
    // 拍照回调接口
    private Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
        public void onPictureTaken(byte[] mData, Camera camera) {
            File mPictureFile = StorageHelper.getOutputFile(StorageHelper.MEDIA_TYPE_IMAGE);
            if (mPictureFile == null) {
                return;
            }
            try {
                FileOutputStream fos = new FileOutputStream(mPictureFile);
                fos.write(mData);
//          输出文件流后要关闭
                fos.close();
                Bitmap mBitmap = BitmapFactory.decodeByteArray(mData, 0, mData.length);
                thumbsView.setImageBitmap(mBitmap);
                // 获取缩略图Uri
                mUri = StorageHelper.getOutputUri(mPictureFile);
                // 停止预览
                mCamera.stopPreview();
                mCamera.startPreview();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    };

快门回调接口

// 快门回调接口
    private Camera.ShutterCallback mShutterCallback = new Camera.ShutterCallback() {
        public void onShutter() {
            mediaPlayer = new MediaPlayer();
            mediaPlayer = mediaPlayer.create(MainActivity.this, R.raw.shutter);
            try {
                mediaPlayer.prepare();
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mediaPlayer.start();
            Log.d("Tag66", "mediaPlayer 66");
        }
    };
  1. 存储的辅助类
/**
 * Created by ss on 2016/10/29.
 * 保存文件的辅助类
 */

public final class StorageHelper {
    public static final int MEDIA_TYPE_IMAGE=0;
    public static final int MEDIA_TYPE_VIDEO=1;

    public static Uri getOutputUri(File mFile){
    //返回URi 路径
        return  Uri.fromFile(mFile);
    }
    public  static File getOutputFile(int mType){
        //Environment:Return the primary external storage directory
        File mMediaFileDir = new File(Environment.getExternalStorageDirectory(),"OpenCamera");
        if (!mMediaFileDir.exists()){
            if(!mMediaFileDir.mkdir()){
                //mkdir:Creates the directory named by this file, assuming its parents exist
                return null;
            }

        }
        File mMediaFile = null;
        //创建文件名
        String mFileName = new SimpleDateFormat("yyyMMddHHmmss").format(new Date());
        switch (mType){
            case MEDIA_TYPE_IMAGE:
                mMediaFile = new File(mMediaFile.getPath()+File.separator+"IMG_"+mFileName+".jpg");
            break;
            case MEDIA_TYPE_VIDEO:
                mMediaFile = new File(mMediaFile.getPath()+File.separator+"VID_"+mFileName+".mp4");
            default:mMediaFile=null;
        }
        return mMediaFile;
    }
    }

6.下面是主活动的代码逻辑

public class MainActivity extends AppCompatActivity {
    private Camera mCamera;
    //    预览界面
    private CameraView mCameraView;
    //    缩略图
    private ImageView thumbsView;
    //    当前缩略图Uri
    private Uri mUri;
    private MediaPlayer mediaPlayer;
    private GoogleApiClient client;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        要求全屏
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
//        检查硬件设备Camera

       if (!CheckCameraHardware(this)) {
            Toast.makeText(this, "sorry no camera!", Toast.LENGTH_SHORT).show();
            return;
        }
        int cameraNum = Camera.getNumberOfCameras();
        //mCamera = getCameraInstance();
        mCamera = Camera.open();
        if (mCamera != null) {
            mCamera.startPreview();
        }
        Log.d("Tag77", "CameraNum:" + cameraNum);

// 获取预览画面
        mCameraView = new CameraView(this, mCamera);
        FrameLayout mFrameLayout = (FrameLayout) findViewById(R.id.frameLayout);
        mFrameLayout.addView(mCameraView);
        mCamera.startPreview();
// 拍照按钮
        Button BtnCapture = (Button) findViewById(R.id.BtnCapture);
        BtnCapture.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                // 使用takePicture完成拍照
                mCamera.autoFocus(new Camera.AutoFocusCallback() {
                    // 自动对焦完成拍照
                    public void onAutoFocus(boolean isSuccess, Camera camera) {
                        if (isSuccess && camera != null) {
                            mCamera.takePicture(mShutterCallback, null, mPictureCallback);
                        }

                    }
                });

            }
        });
//退出按钮
 Button BtnExit =(Button) findViewById(R.id.BtnExit);
        BtnExit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            finish();
            }
        });  
      thumbsView = (ImageView) findViewById(R.id.thumbsView);

        thumbsView.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                // 使用URI访问当前缩略图
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setDataAndType(mUri, "image/*");
                startActivity(intent);
            }
        });
        // ATTENTION: This was auto-generated to implement the App Indexing API.
        // See https://g.co/AppIndexing/AndroidStudio for more information.
        client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
    }
    //下面省略四个函数
    //拍照回调接口
    //快门回调接口
    //官方建议的安全地访问摄像头的方法
    //检查设备是否支持摄像头

7.声明权限
在AndroidManifest.xml声明权限,获得许可使用硬件camera。主要在Android 6.0 以上无效,至今没有找到方法解决。

<uses-permission android:name="android.permission.CAMERA" />
 <uses-feature android:name="android.hardware.camera" />
 <uses-feature android:name="android.hardware.camera.autofocus" />
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值