设计模式的Builder模式[结合使用Android中的MediaRecorder来浅析]
##摘要:
java23种设计模式之一,英文叫Builder Pattern。其核心思想是将一个“复杂对象的构建算法”与它的“部件及组装方式”分离,使得构件算法和组装方式可以独立应对变化;复用同样的构建算法可以创建不同的表示,不同的构建过程可以复用相同的部件组装方式。
##友情提示:
本文为笔者自己理解,如有写的不对的地方,欢迎指出
版权申明
本文原创作者:章飞_906285288
作者的博客:http://blog.csdn.net/qq_29924041
转载请注明出处
##使用Builder模式来构建我们的MediaRecorder的参数对象
简述:
在Android的开发过程中,无处不见的builder模式,如系统的Dialog的时候采用的就是Builder模式,ImageLoader的初始化的过程中,同样也是。那什么是Builder模式呢?Builder模式又叫做构建者模式。举个最简单的例子:车子是由轮胎,底盘,发动机,方向盘,座椅等组成的。车子是一个类class,具体这些可以组装成奔驰车子,宝马车子等等。不同的参数可以组装成不同的车子。这就是Builder组装的对象。其核心思想是将一个“复杂对象的构建算法”与它的“部件及组装方式”分离,使得构件算法和组装方式可以独立应对变化;复用同样的构建算法可以创建不同的表示,不同的构建过程可以复用相同的部件组装方式。
以下代码是写的是一个Test代码。格式上面没有单独抽出来,MediaRecorder是通过构造一个Params的对象来进行实现的
package com.zzf.cit;
import android.hardware.Camera;
import android.media.MediaRecorder;
import android.view.SurfaceHolder;
import com.eques.cit.util.ELog;
import java.io.File;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
public class VideoRecorder {
public static final String TAG = "VideoRecorder";
public static final String ROOT_PATH = "/mnt/sdcard/zzf/record";
private static VideoRecorder instance;
private Params mParams;
private MediaRecorder mMediaRecorder;
private boolean isRecording = false;
public static VideoRecorder getInstance(){
if (instance == null) {
synchronized (VideoRecorder.class) {
if (instance == null) {
instance = new VideoRecorder();
}
}
}
return instance;
}
public void setParams(Params mParams){
this.mParams = mParams;
}
/**
* 创建一个私有的无参的构造函数
*/
private VideoRecorder(){
File file = new File(ROOT_PATH);
if (!file.exists()) {
file.mkdir();
}
}
/**
* 开始进行录像
*/
public void startRecord(){
if (!isRecording){
mMediaRecorder = new MediaRecorder();
mMediaRecorder.reset();
if (mParams.mCamera != null) {
mParams.mCamera.unlock();
}
mMediaRecorder.setCamera(mParams.mCamera);
mMediaRecorder.setAudioSource(mParams.audioSource);
ELog.i(TAG,"mMediaRecorder.getMaxAmplitude:"+mMediaRecorder.getMaxAmplitude());
mMediaRecorder.setVideoSource(mParams.videoSource);
mMediaRecorder.setOutputFormat(mParams.outputFormat);
mMediaRecorder.setAudioEncoder(mParams.audioEncoderType);
mMediaRecorder.setVideoEncoder(mParams.videoEncoderType);
mMediaRecorder.setVideoFrameRate(mParams.videoFrameRate);
mMediaRecorder.setPreviewDisplay(mParams.mSurfaceHolder.getSurface());
mMediaRecorder.setVideoSize(mParams.mVideoSize.width, mParams.mVideoSize.height);
mMediaRecorder.setOutputFile(mParams.recorderPath);
mMediaRecorder.setVideoEncodingBitRate(300 * 1024 * 5);
mMediaRecorder.setMaxDuration(60 * 1000);
mMediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
@Override
public void onInfo(MediaRecorder mr, int what, int extra) {
}
});
Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
if (isRecording){
isRecording = false;
}
}
};
timer.schedule(timerTask,60 * 1000);
try {
mMediaRecorder.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mMediaRecorder.start();
isRecording = true;
}
}
/**
* 停止录像
*/
public void stopRecord(){
if (isRecording) {
isRecording = false;
if (mMediaRecorder != null) {
if (mParams.mCamera != null) {
mParams.mCamera.lock();
}
mMediaRecorder.stop();
mMediaRecorder.release();
mMediaRecorder = null;
}
}
}
}
class Params{
//录像的具体路径
public String recorderPath;
//音频音源
public int audioSource;
//视频源
public int videoSource;
//输出的格式
public int outputFormat;
//音频的编码类型
public int audioEncoderType;
//视频的编码类型
public int videoEncoderType;
public SurfaceHolder mSurfaceHolder;
//视频的帧率
public int videoFrameRate;
//视频的大小
public VideoSize mVideoSize;
//
public Camera mCamera;
static class VideoSize{
public int width;
public int height;
public VideoSize(int width,int height){
this.width = width;
this.height = height;
}
}
public Params(Builder mBuilder){
this.recorderPath = mBuilder.recorderPath;
this.audioSource = mBuilder.audioSource;
this.videoSource = mBuilder.videoSource;
this.outputFormat = mBuilder.outputFormat;
this.audioEncoderType = mBuilder.audioEncoderType;
this.videoEncoderType = mBuilder.videoEncoderType;
this.mSurfaceHolder = mBuilder.mSurfaceHolder;
this.videoFrameRate = mBuilder.videoFrameRate;
this.mVideoSize =mBuilder.mVideoSize;
this.mCamera = mBuilder.mCamera;
}
static class Builder{
//录像的具体路径
public String recorderPath;
//音频音源
public int audioSource = MediaRecorder.AudioSource.MIC ;
//视频源
public int videoSource = MediaRecorder.VideoSource.CAMERA;
//输出的格式
public int outputFormat = MediaRecorder.OutputFormat.MPEG_4;
//音频的编码类型
public int audioEncoderType = MediaRecorder.AudioEncoder.AMR_NB;
//视频的编码类型
public int videoEncoderType = MediaRecorder.VideoEncoder.H264;
public SurfaceHolder mSurfaceHolder;
//视频的帧率
public int videoFrameRate;
//视频的大小
public VideoSize mVideoSize;
public Camera mCamera;
public Builder(){
}
public Builder recorderPath(String recorderPath){
this.recorderPath = recorderPath;
return this;
}
public Builder audioSource(int audioSource){
this.audioSource = audioSource;
return this;
}
public Builder videoSource(int videoSource){
this.videoSource = videoSource;
return this;
}
public Builder outputFormat(int outputFormat){
this.outputFormat = outputFormat;
return this;
}
public Builder audioEncoderType(int audioEncoderType){
this.audioEncoderType = audioEncoderType;
return this;
}
public Builder videoEncoderType(int videoEncoderType){
this.videoEncoderType = videoEncoderType;
return this;
}
public Builder mSurfaceHolder(SurfaceHolder mSurfaceHolder){
this.mSurfaceHolder = mSurfaceHolder;
return this;
}
public Builder videoFrameRate(int videoFrameRate){
this.videoFrameRate = videoFrameRate;
return this;
}
public Builder mCamera(Camera mCamera){
this.mCamera = mCamera;
return this;
}
public Builder mVideoSize(VideoSize mVideoSize){
if (mVideoSize != null) {
this.mVideoSize = mVideoSize;
}else{
this.mVideoSize = new VideoSize(854, 480);
}
return this;
}
public Params build(){
return new Params(this);
}
}
@Override
public String toString() {
return "Params{" +
"recorderPath='" + recorderPath + '\'' +
", audioSource=" + audioSource +
", videoSource=" + videoSource +
", outputFormat=" + outputFormat +
", audioEncoderType=" + audioEncoderType +
", videoEncoderType=" + videoEncoderType +
", mSurfaceHolder=" + mSurfaceHolder +
", videoFrameRate=" + videoFrameRate +
", mVideoSize=" + mVideoSize +
", mCamera=" + mCamera +
'}';
}
}
调用部分的代码,只截取部分的代码。
if (mVideoRecorder != null) {
Params mParams = new Params.Builder()
.recorderPath(VideoRecorder.ROOT_PATH + File.separator + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(System.currentTimeMillis())+".3gp")
.mSurfaceHolder(mSurfaceView.getHolder())
.audioSource(MediaRecorder.AudioSource.CAMCORDER)
.audioEncoderType(MediaRecorder.AudioEncoder.AAC)
.videoSource(MediaRecorder.VideoSource.CAMERA)
.videoEncoderType(MediaRecorder.VideoEncoder.H263)
.mVideoSize(new VideoSize(854, 480))
.videoFrameRate(30)
.outputFormat(MediaRecorder.OutputFormat.MPEG_4)
.mCamera(mCamera)
.build();
Log.i(TAG,"PARAMS:"+mParams.toString());
mVideoRecorder.setParams(mParams);
mVideoRecorder.startRecord();
}
当然在使用MediaRecorder时候,在Android中是要有权限限制的
Builder模式好处和优点
使用Builder模式必然会导致写两遍相关属性的代码和SETTER方法,看起来有点吃力不讨好。然而需要看到的是,客户端代码的可用性和可读性得到了大大提高。与此同时,构造函数的参数数量明显减少调用起来非常直观。
Builder方法另外一个优势在于,单个builder构建多个对象时Builder参数可在创建期间进行调整,还可以根据对象不同而进行改变。这就像我越来越推崇的以“不变”应“万变”。Builder模式特别适合那些属性个数很多的类,我认为没有必要给那些本不需要设置值传递参数(设置null)。