• 2.2.1 构建基于定时器的Camera应用程序


      为了纠正刚才所描述的情况,可以再照相时添加一个时间延迟。接下来更新SnapShot示例,使得在按下按钮10秒钟后开始照相。

       为了实现这个功能,需要使用一个类似java.util.Timer的对象。但是,在Android中使用Timer对象会导致一些问题,因为它引入了一个单独的线程。为了使用单独的线程与UI交互,需要使用一个Handler对象在主线程中触发一个动作。

       使用Handler对象的另一个用途是安排在将来发生的操作。Handler对象所拥有的功能使得我们不必使用Timer对象。

       为了创建在将来执行某些动作的Handler对象,只需构建一个通用的Handler对象:

    1    Handler timerHandler=new Handler();

       然后,必须创建一个Runnable对象,在其run方法中包含后面将要发生的动作。在当前的情况下,我们希望这个动作在10秒钟之后发生,触发照相操作:

    1     Runnable timerTask=new Runnable() {
    2         
    3         @Override
    4         public void run() {
    5             camera.takePicture(null, null, SnapShot.this);
    6         }
    7     };

      现在单击一个按钮时,只需要这样安排操作:

    1      timerHandler.postDelayed(timerTask, 1000);

      这将通知timerHandler在10秒钟之后调用timerTask方法。

      下面的示例将创建一个Handler对象,并使它每秒钟调用一个方法。通过采用这种方式,可以在屏幕上为用户提供倒计时。

     1 package com.nthm.androidtest;
     2 
     3 import java.io.FileNotFoundException;
     4 import java.io.IOException;
     5 import java.io.OutputStream;
     6 import java.util.Iterator;
     7 import java.util.List;
     8 import android.app.Activity;
     9 import android.content.ContentValues;
    10 import android.content.res.Configuration;
    11 import android.hardware.Camera;
    12 import android.net.Uri;
    13 import android.os.Bundle;
    14 import android.os.Handler;
    15 import android.provider.MediaStore.Images.Media;
    16 import android.view.SurfaceHolder;
    17 import android.view.SurfaceView;
    18 import android.view.View;
    19 import android.view.View.OnClickListener;
    20 import android.widget.Button;
    21 import android.widget.TextView;
    22 
    23 public class SnapShot extends Activity implements OnClickListener,SurfaceHolder.Callback,Camera.PictureCallback{
    24     private SurfaceView cameraView;
    25     private SurfaceHolder surfaceHolder;
    26     private Camera camera;

       这种活动非常类似于SnapShot活动。我们需要添加一个Button对象来触发倒计时的开始,并且添加一个TextView对象来显示倒计时。

    1     private Button startButton;
    2     private TextView countdownTextView;

       还需要一个Handler对象,在当前情况下是timerUpdateHandler;需要一个布尔值来帮助我们跟踪计时器是否已经开始(timerRunning);同时还要有一个整数(currentTime)用于跟踪倒计时。

     1     private Handler timerUpdateHandler;
     2     private boolean timerRunning=false;
     3     private int currentTime=10;
     4     
     5     @Override
     6     protected void onCreate(Bundle savedInstanceState) {
     7         super.onCreate(savedInstanceState);
     8         setContentView(R.layout.snapshot);
     9         cameraView=(SurfaceView) findViewById(R.id.CameraView);
    10         
    11         surfaceHolder=cameraView.getHolder();
    12         surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    13         surfaceHolder.addCallback(this);

       接下来,获得新UI元素(在布局XML中定义)的引用,并使我们的活动作为Button对象的OnClickListener。可以这么做是因为该活动实现OnClickListener。

    1         countdownTextView=(TextView) findViewById(R.id.CountDownTextView);
    2         startButton=(Button) findViewById(R.id.CountDownButton);
    3         startButton.setOnClickListener(this);

      在onCreate方法中做的最后一件事情是实例化Handler对象。

    1         timerUpdateHandler=new Handler();
    2     }

      在按下startButton时将调用onClick方法。通过检查timerRunning布尔值,可以判断计时器例程是否还没有运行;如果还没有运行,那么立即通过Handler对象(timerUpdateHandler)调用下面将描述的timerUpdateTask Runnable对象。

    1     @Override
    2     public void onClick(View v) {
    3         if(!timerRunning){
    4             timerRunning=true;
    5             timerUpdateHandler.post(timerUpdateTask);
    6         }
    7     }

        下面的代码是称为timerUpdateTask的Runnable对象。该对象包含run方法,通过timerUpdateHandler对象触发它。

    1      private Runnable timerUpdateTask=new Runnable() {
    2         
    3         @Override
    4         public void run() {

      如果currentTime(保存倒计时的整数)大于1,那么将对他进行递减,同时安排1秒钟后再次调用该Handler对象。

    1             if(currentTime>1){
    2                 currentTime--;
    3                 timerUpdateHandler.postDelayed(timerUpdateTask, 1000);
    4             }else{

       如果currentTime不再大于1,那么将实际触发摄像头以使其照相,并重置所有的跟踪变量。

    1                 camera.takePicture(null, null, TimerSnapShot.this);
    2                 timerRunning=false;
    3                 currentTime=10;
    4             }

       无论如何,我们都将更新TextView对象,使得它在照相之前一直显示当前的时间。

    1                countdownTextView.setText(""+currentTime);
    2         }
    3     };

       该活动的其余操作与前面所述的SnapShot示例基本相同。

     1     @Override
     2     public void onPictureTaken(byte[] data, Camera camera) {
     3         Uri imageFileUri=getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, new ContentValues());
     4         try {
     5             OutputStream imageFileOS=getContentResolver().openOutputStream(imageFileUri);
     6             imageFileOS.write(data);
     7             imageFileOS.flush();
     8             imageFileOS.close();
     9         } catch (FileNotFoundException e) {
    10             e.printStackTrace();
    11         }catch (IOException e) {
    12             e.printStackTrace();
    13         }
    14         camera.startPreview();
    15     }
    16     @Override
    17     public void surfaceCreated(SurfaceHolder holder) {
    18         camera=Camera.open();
    19     try {
    20         camera.setPreviewDisplay(holder);
    21         Camera.Parameters parameters=camera.getParameters();
    22         if(this.getResources().getConfiguration().orientation!=Configuration.ORIENTATION_LANDSCAPE){
    23             //这是一个众所周知但未文档化的特性
    24             parameters.set("orientation", "portrait");
    25             //对于Android 2.2及其以上版本
    26             camera.setDisplayOrientation(90);
    27             //对于Android 2.0及其以上版本取消注释
    28             parameters.setRotation(90);
    29         }
    30         //用于Android 2.0 和更高版本的效果
    31         List<String> colorEffects=parameters.getSupportedColorEffects();
    32         Iterator<String> cei=colorEffects.iterator();
    33         while(cei.hasNext()){
    34             String currentEffect=cei.next();
    35             if(currentEffect.equals(Camera.Parameters.EFFECT_SOLARIZE)){
    36                 parameters.setColorEffect(currentEffect);
    37             }
    38         }
    39         //结束Android 2.0 和更高版本的效果
    40         camera.setParameters(parameters);
    41         } catch (IOException e) {
    42             camera.release();
    43         }
    44     }
    45 
    46     @Override
    47     public void surfaceChanged(SurfaceHolder holder, int format, int width,
    48             int height) {
    49         camera.startPreview();
    50     }
    51 
    52     @Override
    53     public void surfaceDestroyed(SurfaceHolder holder) {
    54         camera.stopPreview();
    55         camera.release();
    56     }
    57 }

        然而,布局XML稍微有点不同。这个应用程序在一个包含LinearLayout的FrameLayout中显示摄像头预览SurfaceView,其中包含TextView来显示倒计时,并且包含Button来触发倒计时。该FrameLayout中的所有对象均左上角对其,并且以此堆叠。采用这种方式,TextView和Button均显示在摄像头预览的顶部。

     1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2     android:layout_width="match_parent"
     3     android:layout_height="match_parent"
     4     android:orientation="vertical"
     5     >
     6 <FrameLayout 
     7     android:id="@+id/FrameLayout01"
     8     android:layout_width="wrap_content"
     9     android:layout_height="wrap_content"
    10     >
    11     <SurfaceView 
    12         android:id="@+id/CameraView"
    13         android:layout_width="match_parent"
    14         android:layout_height="match_parent"
    15         />
    16     <LinearLayout 
    17         android:id="@+id/LinearLayout01"
    18         android:layout_width="wrap_content"
    19         android:layout_height="wrap_content"
    20         android:orientation="horizontal"
    21         >
    22         <TextView 
    23          android:id="@+id/CountDownTextView"
    24          android:layout_width="match_parent"
    25          android:layout_height="wrap_content"
    26          android:text="10"
    27          android:textSize="100dip"
    28          android:layout_gravity="center_vertical|center_horizontal|center"/>
    29         <Button 
    30          android:id="@+id/CountDownButton"
    31          android:layout_width="wrap_content"
    32          android:layout_height="wrap_content"
    33          android:text="Start Time"/>
    34     </LinearLayout>
    35 </FrameLayout>
    36 </LinearLayout>

       最后,需要确保在AndroidManifest.xml文件中包含CAMERA权限。

    1     <uses-permission android:name="android.permission.CAMERA"/>
  • 相关阅读:
    Codeforces Round #445 A. ACM ICPC【暴力】
    “玲珑杯”ACM比赛 Round #1
    HDU 6034 Balala Power!【排序/进制思维】
    2017多校训练1
    POJ 3620 Avoid The Lakes【DFS找联通块】
    Educational Codeforces Round 1D 【DFS求联通块】
    Openjudge1388 Lake Counting【DFS/Flood Fill】
    洛谷 P1506 拯救oibh总部【DFS/Flood Fill】
    小白书 黑白图像【DFS/Flood Fill】
    SSOJ 2316 面积【DFS/Flood Fill】
  • 原文地址:https://www.cnblogs.com/ZSS-Android/p/3929468.html
Copyright © 2020-2023  润新知