Andriod后台拍照程序

一、新建Andriod应用项目

        生成blank activity

二、配置AndroidManifest.xml

       摄像权限<uses-permission android:name="android.permission.CAMERA" />

       写SDK卡权限<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

三、修改activity_main.xml如下

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/ly"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical" >     
    </RelativeLayout>

四、实现CameraView类,继承SurfaceView并实现SurfaceHolder.Callback、Camera.PictureCallback接口

    1、SurfaceView的介绍(来自网络)

         SurfaceView是视图(View)的继承类,这个视图里内嵌了一个专门用于绘制的Surface。你可以控制这个Surface的格式和尺寸。Surfaceview控制这个Surface的绘制位置。

         Surface是纵深排序(Z-ordered)的,这表明它总在自己所在窗口的后面。Surfaceview提供了一个可见区域,只有在这个可见区域内 的Surface部分内容才可见,可见区域

外的部分不可见。Surface的排版显示受到视图层级关系的影响,它的兄弟视图结点会在顶端显示。这意味者 Surface的内容会被它的兄弟视图遮挡,这一特性可以用来放置

遮盖物(overlays)(例如,文本和按钮等控件)。注意,如果Surface上面 有透明控件,那么它的每次变化都会引起框架重新计算它和顶层控件的透明效果,这会影响性能。

        你可以通过SurfaceHolder接口访问这个Surface,getHolder()方法可以得到这个接口。Surfaceview变得可见时,Surface被创建;Surfaceview隐藏前,Surface被销毁。

这样能节省资源。如果你要查看 Surface被创建和销毁的时机,可以重载surfaceCreated(SurfaceHolder)和 surfaceDestroyed(SurfaceHolder)。

        Surfaceview的核心在于提供了两个线程:UI线程和渲染线程。这里应注意:

        a.所有SurfaceView和SurfaceHolder.Callback的方法都应该在UI线程里调用,一般来说就是应用程序主线程。渲染线程所要访问的各种变量应该作同步处理。

        b.由于surface可能被销毁,它只在SurfaceHolder.Callback.surfaceCreated()和 SurfaceHolder.Callback.surfaceDestroyed()之间有效,所以要确保渲染线程访问的是合法有效的Surface。

    2、Camera.PictureCallback接口

         通过实现onPictureTaken方法来得到拍照后的图片的二进制数据

         详见http://android.toolib.net/reference/android/hardware/Camera.PictureCallback.html

   3、Handler类和Runnable类

        Handler是来满足线程间的通信,Handler先进先出的原则,可以对运行在不同线程中的多个任务进行排队,Handler可以发送和处理消息对象或Runnable对象,这些消息对象和Runnable对象与一个线程相关联。每个Handler的实例都关联了一个线程和线程的消息队列。当创建了一个Handler对象时,一个线程或消息队列同时也被创建,该Handler对象将发送和处理这些消息或Runnable对象。

       Runnable是接口类,实现方法run来执行要做的事情。使用Handler的post方法将Runnable对象放到Handler的线程队列中后,该Runnable的执行其实并未单独开启线程,而是仍然在当前Activity线程中执行的,Handler只是调用了Runnable对象的run方法。
   4、Camera类,几个主要函数
        camera = Camera.open();// 摄像头的初始化

        camera.setPreviewDisplay(holder)//告诉camera在哪画预览

        camera.setParameters(parameters);// 设置参数
        camera.startPreview();// 开始预览

        camera.takePicture//对焦后拍照

        camera.setPreviewDisplay(null);//摄像头用完调三个函数
        camera.stopPreview();
        camera.release();

  5、代码

public class CameraView extends SurfaceView implements SurfaceHolder.Callback,
  Camera.PictureCallback {

 private SurfaceHolder holder;
 private Camera camera;
 // private Camera.Parameters parameters;
 private Activity act;
 private Handler handler = new Handler();

 @SuppressWarnings("deprecation")
 public CameraView(Context context, Activity act) {
  super(context);
  this.act = act;

  if (!checkCameraHardware(context)) {
   return;
  }

  holder = getHolder();// 生成Surface Holder
  holder.addCallback(this);
  holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// 指定Push Buffer

  handler.postDelayed(new Runnable() {

   @Override
   public void run() {
    if (camera == null) {
     handler.postDelayed(this, 1 * 1000);// 由于启动camera需要时间,在此让其等两秒再进行聚焦知道camera不为空
    } else {
     camera.autoFocus(new AutoFocusCallback() {
      // @SuppressLint("NewApi")
      @Override
      public void onAutoFocus(boolean success, Camera camera) {
       if (success) {
        // camera.enableShutterSound(false);
        camera.takePicture(new ShutterCallback() {// 如果聚焦成功则进行拍照
           @Override
           public void onShutter() {
           }
          }, null, CameraView.this);
       } else {
       }
      }
     });
    }
   }
  }, 2 * 1000);//2 s
 }

 @Override
 public void surfaceCreated(final SurfaceHolder holder) {
  // TODO Auto-generated method stub
  try {
   camera = Camera.open();// 摄像头的初始化
  } catch (Exception e) {
   // Camera is not available (in use or does not exist)
  }
  handler.postDelayed(new Runnable() {
   @Override
   public void run() {
    if (holder != null) {
     try { // The Surface has been created, now tell the camera
       // where to draw the preview
      camera.setPreviewDisplay(holder);
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    } else {
     handler.postDelayed(this, 1 * 1000);
    }
   }
  }, 2 * 1000);
 }

 @Override
 public void surfaceChanged(SurfaceHolder holder, int format, int width,
   int height) {
  // TODO Auto-generated method stub
  // parameters = camera.getParameters();
  // camera.setParameters(parameters);// 设置参数
  camera.startPreview();// 开始预览
 }

 @Override
 public void surfaceDestroyed(SurfaceHolder holder) {
  // TODO Auto-generated method stub
 }

 void ReleaseCamera() {
  if (camera != null) {
   try {
    camera.setPreviewDisplay(null);
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   camera.stopPreview();
   camera.release();
   camera = null;
  }
 }

 @SuppressLint("SimpleDateFormat")
 public void onPictureTaken(byte[] data, Camera camera) {// 拍摄完成后保存照片

  try {

   Date date = new Date();
   SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
   String time = format.format(date);

   // 在SD卡上创建文件夹

   File file = new File(Environment.getExternalStorageDirectory()
     + "/myCamera/pic");
   if (!file.exists()) {

    file.mkdirs();
   }

   String path = Environment.getExternalStorageDirectory()
     + "/myCamera/pic/" + time + ".jpg";
   data2file(data, path);

   ReleaseCamera();

   holder.removeCallback(CameraView.this);

   act.finish();

  } catch (Exception e) {

  }

 }

 private void data2file(byte[] w, String fileName) throws Exception {// 将二进制数据转换为文件的函数
  FileOutputStream out = null;
  try {
   out = new FileOutputStream(fileName);
   out.write(w);
   out.close();
   Toast.makeText(act, "Image saved to:\n" + fileName,
     Toast.LENGTH_LONG).show();

  } catch (Exception e) {
   if (out != null)
    out.close();
   throw e;
  }
 }

 /** Check if this device has a camera */
 private boolean checkCameraHardware(Context context) {
  if (context.getPackageManager().hasSystemFeature(
    PackageManager.FEATURE_CAMERA)) {
   // this device has a camera
   return true;
  } else {
   // no camera on this device
   Toast.makeText(act, "No camera!!!\n", Toast.LENGTH_LONG).show();
   return false;
  }
 }
}

五、修改MainActivity.onCreate函数

      protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  getWindow().clearFlags(
    WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
  getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
  requestWindowFeature(Window.FEATURE_NO_TITLE);// 设置横屏模式以及全屏模式

  view = new CameraView(this,this);// 通过一个surfaceview的view来实现拍照
  view.setId(1);
  setContentView(R.layout.activity_main);
  RelativeLayout relative = (RelativeLayout) this.findViewById(R.id.ly);
  RelativeLayout.LayoutParams Layout = new RelativeLayout.LayoutParams(3,3);// 设置surfaceview使其满足需求无法观看预览
  Layout.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, 1);
  Layout.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 1);

  relative.addView(view, Layout);
 }

 

六、其他

      1、如何关掉拍照声音,有个函数camera.enableShutterSound,但要API 17才能用。网上找了下,有说c改属性值可以实现,后面再研究。

      2、更多可参考http://developer.android.com/guide/topics/media/camera.html

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值