在学习直接调用本地相机获取照片之前,我想最好还是根据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上会贴出地址。