Android相机应用开发实例

   在学习直接调用本地相机获取照片之前,我想最好还是根据Android给的相机API自己开发一个简单的相机,对于相机的运作过程有一个基本的了解。

 

  第一步,建立SurfaceView显示预览(拍照之前)

  activity_main.xml文件定义FrameLayout布局,用一个button来实施拍照行为

  

<FrameLayout 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" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"
    >


    <SurfaceView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/surfaceView"
        android:layout_gravity="center" />
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="visible"
        android:id="@+id/shot_button_layout"
        >
        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_alignParentBottom="true"
            android:text="@string/shot"
            android:layout_marginRight="10dp"
            android:layout_marginBottom="10dp"/>


        </RelativeLayout>
</FrameLayout>

  onCreate方法布局全屏和添加回调函数,其中的button点击动作为拍摄照片

@Override
    protected void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_NO_TITLE); //此方法必须在super.onCreate方法之前调用
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);//全屏显示

        setContentView(R.layout.activity_main);


        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mCamera.takePicture(null, null, new MyPictureCallback());
            }
        });

        mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
        mSurfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        //获取手机分辨率
        Display display = getWindowManager().getDefaultDisplay(); //Activity#getWindowManager()
        Point size = new Point();
        display.getSize(size);
        mSurfaceView.getHolder().setFixedSize(size.x,size.y);

        mSurfaceView.getHolder().setKeepScreenOn(true);
        mSurfaceView.getHolder().addCallback(new SurfaceCallback());
    }

  重要的一个步骤就是处理SurfaceView的显示与更新。

private final class SurfaceCallback implements SurfaceHolder.Callback{
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            mCamera = Camera.open();
            Camera.Parameters parameters = mCamera.getParameters();
            mSupportedPreviewSizes = parameters.getSupportedPreviewSizes();
            Camera.Size mPreviewSize = mSupportedPreviewSizes.get(mSupportedPreviewSizes.size()-1);

            parameters.setPreviewSize(mPreviewSize.width,mPreviewSize.height);

            parameters.setPreviewFrameRate(5);
            if(parameters.getSupportedPreviewFormats().contains(ImageFormat.JPEG)){
                parameters.setPreviewFormat(ImageFormat.JPEG);
            }

            parameters.setPictureFormat(ImageFormat.JPEG);
            parameters.setPictureSize(1024, 768);
            parameters.setJpegQuality(80);
            mCamera.setParameters(parameters);
            try {
                mCamera.setPreviewDisplay(holder);
                mCamera.startPreview();
            } catch (IOException e) {
                e.printStackTrace();
            }
            Log.v(LOG_TAG,"Camera parameters are: "+parameters.flatten());
        }

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

        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            if (mCamera != null){
                mCamera.release();
                mCamera =null;
            }
        }
    }

   

   第二步,实现拍照与照片数据的保存(保存在sd卡里的CameraDemo/目录下)。

private final class MyPictureCallback implements Camera.PictureCallback {

        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            SavePictureTask savePictureTask = new SavePictureTask();
            savePictureTask.execute(data);  
            mCamera.startPreview();
        }
    }

  建立上边代码中的SavePictureTask异步处理类。

public class SavePictureTask extends AsyncTask<byte[],Void,Void>{
    @Override
    protected Void doInBackground(byte[]... params) {
        File path = new File(getSDPath()+"/CameraDemo");
        if (!path.exists()) {
            path.mkdirs();
        }
        // 创建文件
        Calendar calendar = Calendar.getInstance();
        String filename = ""+calendar.get(Calendar.YEAR)+calendar.get(Calendar.MONTH)+
                calendar.get(Calendar.DAY_OF_MONTH)+Integer.toString((int) System.currentTimeMillis()) + ".jpg";
        File picture = new File(path+"/"+filename);  //这里是全路径
        try {
            FileOutputStream out = new FileOutputStream(picture);
            out.write(params[0]);
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
    public String getSDPath(){
        File sdDir = null;
        boolean sdCardExist = Environment.getExternalStorageState()
                .equals(android.os.Environment.MEDIA_MOUNTED);   //判断sd卡是否存在
        if   (sdCardExist)
        {
            sdDir = Environment.getExternalStorageDirectory();//获取跟目录
        }
        return sdDir.toString();

    }
}

  实现一个简单拍照功能的相机难度不大,但是所给API的模式还需进一步理解。这个相机的自动对焦功能实现的不是太好,有待于改进,这里就不贴代码了,以后需要深入学习的。完整代码等我更新到github上会贴出地址。

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。