关于android之Camera的案例开发哟~




     浏览了那么多技术博客,今天,咱也写一篇,第一篇,恩,第一篇,要写好~先写一点儿学习感悟吧。从前天开始,学习基于android的Cmeara的开发,在网上搜了很多,很多都是片段,要不然就是code量非常大,而且中间注释也不多,看了完全没有头绪,越看越烦,索性,就不看咱们国内的了,去developer系统的学习了下,把官方文档中,关于Camera的通读了一遍,哦,可能不止一遍。不看不知道,一看全知道了~知道啥了?

   
    知道了android.hardware.Camera这个类官方已经弃用了,推荐使用android.hardware.Camera2,而且我发现网上大多的代码都是针对老的Camera类的,还有人再问新的Camera2这个类怎么应用,这里呢,我要讲的也是Camera的用法,为什么不用新的Camera2:?因为我一直在搞的就是Camera,等完全掌握老的,再去搞新的Camera2。如果,你想知道怎么应用Camera2,我推荐你去最权威的地方找答案,就是官网,它那里写的真的很详细,对里边每个方法都有详解,而且告诉你为什么这么写,怎么就那么用,比你在网上搜的别人写的代码详细多了。当然了,这个估计很多人都知道,可就是图一个方便、快捷,所以,就直接当答案,可是,很多都是写的注释或者解释非常简单的,这就造成,你还得再去找更详细的,与其这样,你还不如直接去官网去看,去学习,它的写法,肯定是最简洁的,例子都是google写的,很权威。

先上效果图


    

    
    好了,啰里啰嗦的这么多,真烦~开始写代码咯~做这个小项目的具体步骤如下:     
     

    一、分析布局    手机当中最常用的APP,估计就是camera了,你看见什么新鲜的,你肯定是就把它照下来或者录下来,然后呢.......就晒到朋友圈里。现在的人,动不动就晒,什么旅游啊、吃饭啊、玩啊,我真不知道,有什么好晒的,就你吃过?就你玩过?臭显摆什么。真的是病,得治。哎呀呀,跑题了,回来。camera这个布局咱们明眼人都能看出来,没什么布局其实,就是一个大窗口,外加几个按钮,就是这些。好了,分析完了。就这些?就这些。












<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <FrameLayout
        android:id="@+id/layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1" />
	
    
    <LinearLayout 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:background="#2F2F4F">
    	<Button
        android:id="@+id/button_capture"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center" 
        android:text="拍照"
        android:textColor="#FFFFFF"/>
    <Button 
        android:id="@+id/video"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="录像"
        android:textColor="#FFFFFF"/>    
    </LinearLayout>
    
</LinearLayout>
     细解释一下布局代码啊:上面说过了,这个布局就一个窗口加几个按钮。代码里就是这样,FrameLayout在整体布局上部,而两个按钮在整体布局下面,就这些,恩,就这些~说说作用,那两个按钮不必解释,就说那个FramLayout,这是一个容器,用来盛装摄像头画面的View的,即SurfaceView,它的作用类似于画布,摄像头的画面是画,画在画布上。这是比喻,实际上不是画在上面的。SurfaceView是在代码里创建的,并添加到FrameLayout里的,你也可以新建一个类,继承SurefaceView,然后在布局里添加进去。怎么都可以。


二、分析业务代码
1.拍照功能

   要拍照,就得现有一个显示摄像头画面的View,对,就是SurefaceView。客官,上代码~

    

class MyPreview extends SurfaceView implements SurfaceHolder.Callback{
<span style="white-space:pre">		</span>private SurfaceHolder mHolder;
<span style="white-space:pre">		</span>private Camera camera;
<span style="white-space:pre">		</span>
<span style="white-space:pre">		</span>public MyPreview(Context context, Camera camera) {
<span style="white-space:pre">			</span>super(context);
<span style="white-space:pre">			</span>// TODO Auto-generated constructor stub
<span style="white-space:pre">			</span>mHolder = getHolder();
<span style="white-space:pre">			</span>this.camera = camera;
<span style="white-space:pre">			</span>camera.setDisplayOrientation(90);
<span style="white-space:pre">			</span>Camera.Parameters parameters = camera.getParameters();
<span style="white-space:pre">			</span>mHolder.addCallback(this);
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>


<span style="white-space:pre">		</span>
<span style="white-space:pre">		</span>@Override
<span style="white-space:pre">		</span>public void surfaceCreated(SurfaceHolder holder) {
<span style="white-space:pre">			</span>// TODO Auto-generated method stub
<span style="white-space:pre">			</span>try {
<span style="white-space:pre">				</span>camera.setPreviewDisplay(holder);
<span style="white-space:pre">				</span>camera.startPreview();
<span style="white-space:pre">			</span>} catch (IOException e) {
<span style="white-space:pre">				</span>// TODO Auto-generated catch block
<span style="white-space:pre">				</span>e.printStackTrace();
<span style="white-space:pre">			</span>}
<span style="white-space:pre">		</span>}


<span style="white-space:pre">		</span>@Override
<span style="white-space:pre">		</span>public void surfaceChanged(SurfaceHolder holder, int format, int width,
<span style="white-space:pre">				</span>int height) {
<span style="white-space:pre">			</span>// TODO Auto-generated method stub
<span style="white-space:pre">			</span>if (mHolder.getSurface() == null){
<span style="white-space:pre">				</span>return;
<span style="white-space:pre">			</span>}
<span style="white-space:pre">			</span>camera.stopPreview();
<span style="white-space:pre">			</span>
<span style="white-space:pre">			</span>
<span style="white-space:pre">			</span>try {
<span style="white-space:pre">				</span>camera.setPreviewDisplay(holder);
<span style="white-space:pre">				</span>camera.startPreview();
<span style="white-space:pre">			</span>} catch (IOException e) {
<span style="white-space:pre">				</span>// TODO Auto-generated catch block
<span style="white-space:pre">				</span>e.printStackTrace();
<span style="white-space:pre">			</span>}
<span style="white-space:pre">		</span>}


<span style="white-space:pre">		</span>@Override
<span style="white-space:pre">		</span>public void surfaceDestroyed(SurfaceHolder holder) {
<span style="white-space:pre">			</span>// TODO Auto-generated method stub
<span style="white-space:pre">			</span>
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>
<span style="white-space:pre">	</span>}

   细说以上代码:这段代码主要功能是创建SurefaceView及实现SurefaceHolder.Callback,实现这个Callback主要原因就是当打开这个程序的时候,调用这个Callback,摄像头加载这个View(这么说可能不太准确,应该是Sureface),开始预览画面(就是显示实时画面通过摄像头)。

  

   有关SurfaceView的解释,见官方说明,如下:
    Provides a dedicated drawing surface embedded inside of a view hierarchy. You can control the format of this surface and, if you like, its size; the SurfaceView takes care of placing the surface at the correct location on the screen。
    详细的大家去翻译,我只说大概意思:这个View内嵌了一个surface,你可以控制surfaace的格式,如大小。
    Access to the underlying surface is provided via the SurfaceHolder interface, which can be retrieved by calling The Surface will be created for you while the SurfaceView's window is visible; you should implement surfaceCreated(android.view.SurfaceHolder),surfaceDestroyed(android.view.SurfaceHolder),surfaceDestroyed(SurfaceHolder) to discover when the Surface is created and destroyed as the window is shown and hidden.
   大概意思:要得到这个surface,你就要实现SurfaceHolder。当这个View可见时,这个surface就被创建了,所以,你要实现surfaceCreated及surfaceDestroy方法。我这里没有在surface改变及销毁里具体实现功能,你可以自己扩展一下。写完以上代码,你就可以将它添加到FrameLayout里了。现在预览实现了,那如何拍照呢?我们不是分析的是拍照吗?说半天都没提啊,嘿,其实拍照就一步,就是camera.takePicture(),如下:

 btn.setOnClickListener(new OnClickListener() {
<span style="white-space:pre">			</span>
<span style="white-space:pre">			</span>@Override
<span style="white-space:pre">			</span>public void onClick(View v) {
<span style="white-space:pre">				</span>// TODO Auto-generated method stub
<span style="white-space:pre">				</span>camera.enableShutterSound(true);//使能拍照的咔嚓声,快门的声音。
<span style="white-space:pre">				</span>camera.takePicture(shutter, null, pictureCall);//拍照
<span style="white-space:pre">				</span>}
<span style="white-space:pre">		</span>});
拍照的代码,takePicture(ShutterCallback shutter, PictureCallback raw,PictureCallback jpeg)这里有两个回调接口 :
1. ShutterCallback shutter = new ShutterCallback() {  //实现自定义快门声音,可是我没有实现成功,不知为何。
		
		@Override
		public void onShutter() {
			// TODO Auto-generated method stub
			MediaPlayer player = MediaPlayer.create(getApplication(), R.raw.bbbb);
			try {
				player.prepare();
				player.start();
			} catch (IllegalStateException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	};

2. PictureCallback pictureCall = new PictureCallback() {//实现照片的处理接口,我这里用来保存照片及录像
		
		@Override
		public void onPictureTaken(byte[] data, Camera camera) {//这个data数组,就是照片的数据哟~
			// TODO Auto-generated method stub
			File file = getOutputFile(CAPTURE_TYPE_IMG);  //此方法主要是获得这个照片的文件名称及路径,代码加下文
			if (file == null){
				return;
			}
			Bitmap image = BitmapFactory.decodeByteArray(data, 0, data.length); //解码data数据成图片
			Matrix matrix = new Matrix(); 
			matrix.setRotate(90);//将图片翻转成垂直状态,默认是水平的。
			image = Bitmap.createBitmap(image, 0, 0, image.getWidth(), image.getHeight(), matrix, true);
			FileOutputStream os;
			try {
				os = new FileOutputStream(file); //新建输出流
				image.compress(Bitmap.CompressFormat.JPEG, 90, os);//将图片输出到手机上
				//os.write(data);
				os.close();
				camera.startPreview();//在回调中加入开始预览,主要是为了在用户照完一张后,相机自动进入下一次预览
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	};

下面是设置及得到照片的名字及路径的方法,代码如下:

	public File getOutputFile(int type) {
		// TODO Auto-generated method stub
		File fileDirectory = new File("//storage//sdcard0//DCIM", "MyCameraLibrary");
		File fileImage;
		if (!fileDirectory.exists()){
			fileDirectory.mkdir();
		}
		
		String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
		if (type == CAPTURE_TYPE_IMG){
		  fileImage = new File(fileDirectory.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
		} else if (type == CAPTURE_TYPE_VIDEO){
		  fileImage = new File(fileDirectory.getPath() + File.separator + "IMG_" + timeStamp + ".mp4");
		} else
			return null;
		return fileImage; 
		
	}

到此,就将拍照的功能讲完了,继续下一个录像功能(还是建议大家去看看文档中的MediaRecord类):

代码如下:

private boolean prepareRecorder() {
		// TODO Auto-generated method stub
		//camera = Camera.open();
		recorder = new MediaRecorder(); //新建录像类
		camera.unlock();
		recorder.setCamera(camera);
		recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
		recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
		recorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_480P));
		recorder.setOutputFile(getOutputFile(CAPTURE_TYPE_VIDEO).toString());
		recorder.setOrientationHint(90);//将录的片段垂直显示
		recorder.setPreviewDisplay(mPreview.getHolder().getSurface());
		try {
			recorder.prepare();
		} catch (IllegalStateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			releaseRecorder();
			return false;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		    releaseRecorder();
			return false;
		}
		return true;
	}


video.setOnClickListener(new OnClickListener() { //按钮触发录像功能
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				if (isRecorder){
					recorder.stop();//停止录像
					releaseRecorder();
					//camera.lock();
					isRecorder = false;
					video.setText("录像");
				}
				else if(prepareRecorder()) {
					recorder.start();//开始录像
					isRecorder = true;
					video.setText("停止录像");
				} else {
					releaseRecorder();
				}
			}
		});

对了,最后不要忘了加上权限及特色哦:

<uses-permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS"/>
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-feature android:name="android.hardware.camera"/>


得嘞,各位,到此,我已经将拍照及录像功能讲完了,可能这个界面不太美观,不过就是为了研究学习,也没关系。再有什么不懂的,欢迎留言哈~
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值