Android Studio | 直接调用系统摄像头拍照并回显、在SurfaceView中实现嵌入拍照并回显

1.直接调用系统摄像头拍照

功能实现:点击按钮,调用系统摄像头拍照之后,回显在imageviewl里面。
在这里插入图片描述

public class register extends AppCompatActivity
{
    private ImageView shotview ;//shotview定义在这里
    //【warning】如果这里写成:private ImageView shotview = findViewById(R.id.imageView);会报错
    //因为需要在onCreate()将类实例化之后,才可以进行初始化。
    private File currentImageFile = null;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.regiester);
        shotview = findViewById(R.id.imageView); //shotview的初始化在这里

        Button takePhoto = findViewById(R.id.getcamera);
        takePhoto.setOnClickListener(new View.OnClickListener()
        {
            //直接调用系统摄像头
            @Override
            public void onClick(View v)
            {
                //dir指的是directory,目录。storage directory 存储目录。

                //如果你想在外存储上放公共文件你可以使用getExternalStoragePublicDirectory()
                //but!如果你的api 版本低于8,那么不能使用getExternalStoragePublicDirectory(),
                //而是使用Environment.getExternalStorageDirectory(),不带参数,不能自己创建一个目录,只是返回外部存储的根路径。
                File dir = new File(Environment.getExternalStorageDirectory(),"pictures");
                //函数原型:File newFile=new File(directory, filename)
                //创建了一个文件夹,名字是dir,路径是外部存储的根路径,名字是"pictures"。
                if(dir.exists())
                {
                    dir.mkdirs();//在根路径下建子目录,子目录名是"pictures"
                }

                //命名临时图片的文件名
                currentImageFile = new File(dir,System.currentTimeMillis() + ".jpg");
                if(!currentImageFile.exists())
                {
                    try
                    {
                        currentImageFile.createNewFile();
                    }
                    catch (IOException e)
                    {
                        e.printStackTrace();
                    }
                }

                Intent it = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//通过intent调用照相机照相
                it.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(currentImageFile));
                //存到外部存储的临时文件currentImageFile的路径下
                startActivityForResult(it, Activity.DEFAULT_KEYS_DIALER);
                //如果想在Activity中得到新打开Activity 关闭后返回的数据,
                // 需要使用系统提供的startActivityForResult(Intent intent, int requestCode)方法
                //打开新的Activity,新的Activity 关闭后会向前面的Activity传回数据,为了得到传回的数据,
                //必须在前面的Activity中重写onActivityResult(int requestCode, int resultCode, Intent data)方法。
            }
        });
    }
    //重写onActivityResult(int requestCode, int resultCode, Intent data)方法
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        if (requestCode == Activity.DEFAULT_KEYS_DIALER)
        {
            shotview.setImageURI(Uri.fromFile(currentImageFile));
        }
    }
}

关于内部存储与外部存储:

1、写一个相册程序,图片肯定是放在外部存储中;而如果要保存一个应用的一些设置数据,是放在内部存储的data目录下。因此其实在安卓文件管理中,我们都是在操作绝对路径。

2、如今的设备,很多中高端机器都将自己的机身存储扩展到了8G以上,他们将存储在概念上分成了"内部internal" 和"外部external" 两部分,但其实都在手机内部。所以不管安卓手机是否有可移动的sdcard,他们总是有外部存储和内部存储。
3、你把手机连接电脑,能被电脑识别的部分就一定是外部存储。
4、公共文件Public files:文件是可以被自由访问,且文件的数据对其他应用或者用户来说都是由意义的,当应用被卸载之后,其卸载前创建的文件仍然保留。
私有文件Private files:外部存储上,应用私有文件的价值在于卸载之后,这些文件也会被删除。
5、如果你想在外存储上放公共文件你可以使用getExternalStoragePublicDirectory()。but!如果你的api 版本低于8,那么不能使用getExternalStoragePublicDirectory(),而是使用Environment.getExternalStorageDirectory(),它不带参数,不能自己创建一个目录,只是返回外部存储的根路径。
【引用总结自:个人认为的一个关于内部存储和外部存储的很好的总结】

2.将拍照界面通过SurfaceView嵌入自己写的界面,存储拍下的照片,照片回调显示

在这里插入图片描述
其中关于surfaceView的设置:

<SurfaceView
        android:id="@+id/sfv_preview"
        android:layout_width="350dp"
        android:layout_height="393dp"
        android:text="@string/photo_preview"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.529"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.135" />

register.java中的代码如下:

public class register extends AppCompatActivity
{
        private SurfaceView sfv_preview;
        private Button btn_take_photo;
        private Camera camera = null;

        //surfaceHolder是surface的监听器,提供访问和控制SurfaceView背后的Surface 相关的方法
        private SurfaceHolder.Callback cpHolderCallback = new SurfaceHolder.Callback()
        {
            @Override
            public void surfaceCreated(SurfaceHolder holder)
            //当surface对象创建后,该方法就会被立即调用。
            {
                startPreview();
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
            //当surface发生任何结构性的变化时(格式或者大小),该方法就会被立即调用
            {
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder)
            //当surface对象在将要销毁前,该方法会被立即调用。
            {
                stopPreview();
            }
        };

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

        private void bindViews()
        {
            sfv_preview = (SurfaceView) findViewById(R.id.sfv_preview);
            btn_take_photo = (Button) findViewById(R.id.getcamera);
            sfv_preview.getHolder().addCallback(cpHolderCallback);
            //获得sfv_preview的surfaceview,
            //再由 addCallback为SurfaceHolder添加一个SurfaceHolder.Callback回调接口。

            btn_take_photo.setOnClickListener(new View.OnClickListener()
            {
                @Override
                public void onClick(View v)//按下“开始拍照”按钮
                {
                    camera.takePicture(null, null, new Camera.PictureCallback()
                            //拍照函数
                    {
                        @Override
                        public void onPictureTaken(byte[] data, Camera camera)
                        {
                            String path = "";//定义路径
                            if ((path = saveFile(data)) != null)//如果路径存在
                            {
                                Intent it = new Intent(register.this, show_registered_photo.class);
                                it.putExtra("path", path);
                                startActivity(it);
                                //用intent实现从当前界面跳转到预览照片的界面
                            }
                            else
                            {
                                Toast.makeText(register.this, "保存照片失败", Toast.LENGTH_SHORT).show();
                            }
                        }
                    });
                }
            });
        }

        //保存临时文件的方法
        private String saveFile(byte[] bytes){
            try {
                File file = File.createTempFile("img","");
                FileOutputStream fos = new FileOutputStream(file);
                fos.write(bytes);
                fos.flush();
                fos.close();
                return file.getAbsolutePath();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            return "";
        }


        //开始预览
        private void startPreview()
        {
            camera = Camera.open();
            try
            {
                camera.setPreviewDisplay(sfv_preview.getHolder());
                camera.setDisplayOrientation(90);   //让相机旋转90度
                camera.startPreview();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }

        //停止预览
        private void stopPreview() {
            camera.stopPreview();
            camera.release();
            camera = null;
        }
}

3.1遇到的小插曲(1):

代码没有错的情况下,和camera有关的方法都报错。如下图所示:
在这里插入图片描述
在这里插入图片描述
后来发现是因为import了错误的包,关于Camera有两个不同的包,在快捷import的时候有两个选项,如下图(画×的是我之前调用的包,画√的是导入了之后就不再报错的包),导入的时候要多注意:
在这里插入图片描述

3.2 遇到的小插曲(2)

拍照界面跳出来之后,按下btn_take_photo按钮后闪退回登录界面。
报错原因:是因为show_registered_photo类没有注册,Alt+Enter快捷键,讲其写入 AndroidManifest.xml 即可。

代码参考链接:9.3 使用Camera拍照 | 菜鸟教程

  • 5
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值