package com.apress.proandroidmedia.ch2.timersnapshot;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
import android.app.Activity;
import android.content.ContentValues;
import android.content.res.Configuration;
import android.hardware.Camera;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore.Images.Media;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class TimerSnapShot extends Activity implements OnClickListener,
SurfaceHolder.Callback, Camera.PictureCallback {
SurfaceView cameraView;
SurfaceHolder surfaceHolder;
Camera camera;这个 activity 非常类似我们的 SnapShot activity。我们打算添加一个 Button 来触发的倒计时, 和一个 TextView 来显示倒计时。 Button startButton;
TextView countdownTextView;
我们还需要一个 Handler,本例中名为 timerUpdateHandler,一个布尔量(timerRunning),帮助我们记录是否启动了计时器,还有一个整数(currentTime),记录倒计时读数。 Handler timerUpdateHandler;
boolean timerRunning = false;
int currentTime = 10;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
cameraView = (SurfaceView)this.findViewById(R.id.CameraView);
surfaceHolder = cameraView.getHolder();
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceHolder.addCallback(this); 下一步,我们将取得新UI元素(在布局XML中定义)的引用,并使我们的 activity 成为 Button 的 OnClickListener。我们可以这样做,是因为我们的 activity 实现了 OnClickListener。 countdownTextView = (TextView) findViewById(R.id.CountDownTextView);
startButton = (Button) findViewById(R.id.CountDownButton);
startButton.setOnClickListener(this);最后,在我们onCreate方法中, 要做的是实例化Handler对象。 timerUpdateHandler = new Handler();
}
我们的onClick方法在按下startButton按钮时被调用。我们会检查timerRunning,看定时器例程是否已经运行,如果没有,我们通过Handler对象timerUpdateHandler,非延迟调用 Runnable timerUpdateTask。 public void onClick(View v)
{
if (!timerRunning)
{
timerRunning = true;
timerUpdateHandler.post(timerUpdateTask);
}
}
这是我们的 Runnable 对象 timerUpdateTask。它包含run方法,由我们的timerUpdateHandler对象触发。 private Runnable timerUpdateTask = new Runnable()
{
public void run()
{
如果记录倒计时计数的整数currentTime大于1,则递减之,并让Handler在1秒后再度调用本Runnable。 if (currentTime > 1)
{
currentTime--;
timerUpdateHandler.postDelayed(timerUpdateTask, 1000);
}
else
{
如果currentTime不大于1,我们将让相机进行拍照并重置所有的记录变量。 camera.takePicture(null,null ,TimerSnapShot.this);
timerRunning = false;
currentTime = 10;
}不管结果如何,我们将更新 TextView 来显示当前的剩余时间。 countdownTextView.setText(""+currentTime);
}
};本 activity 的其余部分,与前述的SnapShot示例基本一样。 public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
{
camera.startPreview();
}
public void surfaceCreated(SurfaceHolder holder)
{
camera = Camera.open();
try {
camera.setPreviewDisplay(holder);
Camera.Parameters parameters = camera.getParameters();
if (this.getResources().getConfiguration().orientation
!= Configuration.ORIENTATION_LANDSCAPE)
{
parameters.set("orientation", "portrait");
// Android 2.2 及以上版本
camera.setDisplayOrientation(90);
// Android 2.0 及以上版本
parameters.setRotation(90);
}
camera.setParameters(parameters);
}
catch (IOException exception)
{
camera.release();
}
}
public void surfaceDestroyed(SurfaceHolder holder)
{
camera.stopPreview();
camera.release();
}
public void onPictureTaken(byte[] data, Camera camera)
{
Uri imageFileUri = getContentResolver()
.insert(Media.EXTERNAL_CONTENT_URI, new ContentValues());
try
{
OutputStream imageFileOS = getContentResolver()
.openOutputStream(imageFileUri);
imageFileOS.write(data);
imageFileOS.flush();
imageFileOS.close();
Toast t = Toast.makeText(this,"Saved JPEG!",Toast.LENGTH_SHORT);
t.show();
}
catch (FileNotFoundException e)
{
Toast t = Toast.makeText(this,e.getMessage(), Toast.LENGTH_SHORT);
t.show();
}
catch (IOException e)
{
Toast t = Toast.makeText(this,e.getMessage(),Toast.LENGTH_SHORT);
t.show();
}
camera.startPreview();
}
}XML 布局有点不同。在此应用程序中,我们用于显示相机预览的 SurfaceView 包含在一个FrameLayout中,与之并列的还有 LinearLayout,其包含了用于显示倒计时计数的 TextView 和 触发倒计时的 Button。FrameLayout 让所有子项以左上角对齐,彼此之间顶部对齐。这样 TextView 和 Button 出现在相机预览顶部。 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<FrameLayout android:id="@+id/FrameLayout01"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<SurfaceView android:id="@+id/CameraView"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</SurfaceView>
<LinearLayout android:id="@+id/LinearLayout01"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView android:id="@+id/CountDownTextView"
android:text="10"
android:textSize="100dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center_horizontal|center">
</TextView>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/CountDownButton"
android:text="Start Timer">
</Button> </LinearLayout>
</FrameLayout>
</LinearLayout>最后,我们需要确保我们的 AndroidManifest.xml 文件包含Camera权限。 <uses-permission android:name="android.permission.CAMERA"> </uses-permission>
...
public class TimelapseSnapShot extends Activity implements OnClickListener,
SurfaceHolder.Callback, Camera.PictureCallback {
SurfaceView cameraView;
SurfaceHolder surfaceHolder;
Camera camera; 我们把Button重命名为startStopButton,因为它现在会处理两个操作。另外对其他变量的名字也做些小的修改。 Button startStopButton;
TextView countdownTextView;
Handler timerUpdateHandler;
boolean timelapseRunning = false;整数currentTime将以秒为单位,记录照片的时间间隔, 而不是从总延时往下递减,如在前面的例子中那样。常数 SECONDS_BETWEEN_PHOTOS 设置为 60。如同它的名字所暗示,这将用于确定照片之间的等待时间。 int currentTime = 0;
public static final int SECONDS_BETWEEN_PHOTOS = 60; // 一分钟
onCreate方法大部分保持不变 - 只是使用新的变量名。 @Override
public void onCreate(Bundle savedInstanceState)
{ super.onCreate(savedInstanceState);
setContentView(R.layout.main);
cameraView = (SurfaceView) this.findViewById(R.id.CameraView);
surfaceHolder = cameraView.getHolder();
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceHolder.addCallback(this);
countdownTextView = (TextView)findViewById(R.id.CountDownTextView);
startStopButton = (Button) findViewById(R.id.CountDownButton);
startStopButton.setOnClickListener(this);
timerUpdateHandler = new Handler();
}从基于计时器的应用程序,变为一个定时器应用程序,大部分变化来自 onClick 方法 和 Runnable 方法。前者在按钮被按下时触发,后者由Handler进行调度。onClick 方法首先检查定时进程是否已经开始(Button 已经按过),如果没有,它将其设置为运行态,并以 Runnable 为参数,调用 Handler 的post方法。如果是在定时过程中,按下按钮意味着停止定时,从而 timerUpdateHandler 的 removeCallbacks
方法被调用。这将清除任何挂起的Runnable对象。public void onClick(View v)
{
if (!timelapseRunning)
{
startStopButton.setText("Stop");
timelapseRunning = true;
timerUpdateHandler.post(timerUpdateTask);
}
else
{
startStopButton.setText("Start");
timelapseRunning = false;
timerUpdateHandler.removeCallbacks(timerUpdateTask);
}
}
private Runnable timerUpdateTask = new Runnable()
{
public void run()
{
if (currentTime < SECONDS_BETWEEN_PHOTOS)
{
currentTime++;
}
else
{
camera.takePicture(null,null,null,TimelapseSnapShot.this);
currentTime = 0;
} timerUpdateHandler.postDelayed(timerUpdateTask, 1000);
countdownTextView.setText(""+currentTime);
}
};本例的res/layout/main.xml 接口,当然还有AndroidManifest.xml 跟单计时器版相同。Android多媒体开发 Pro Android Media 第二章 创建自定义相机应用 3,布布扣,bubuko.com
Android多媒体开发 Pro Android Media 第二章 创建自定义相机应用 3
原文:http://blog.csdn.net/dairyman000/article/details/20369093