Android学习笔记——简单实现照相、录音和录像功能

        Android菜鸟第一次写原创博客,大神请轻喷,共同进步。

    最近刚接触到如何实现一个简单的照相机功能,然后又将录音和录像功能加了进去。ps:录像功能相对复杂,自己实现起来比较困难,我就直接在程序里调用系统的录像功能了。以后在慢慢学习:)好,言归正传。

1、首先新建一个照相机项目;

2、我先新建了一个BaseActivity,用于设置相机屏幕全屏和获取屏幕宽高像素等功能;

代码:

package xw.phonemanager.activity;

import android.app.Activity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Window;
import android.view.WindowManager;

public class BaseActivity extends Activity {
	
	public static float screenWidth, screenHeigth;
//	private ProgressDialog mDialog;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setFullScreen(); // 设置全屏
		getScreen(); //获取屏幕宽高值
	}
	
	// 设置全屏
	private void setFullScreen() {
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);
	}
	//获取屏幕宽高值
	private void getScreen() {

		DisplayMetrics metrics = new DisplayMetrics();
		getWindowManager().getDefaultDisplay().getMetrics(metrics);

		screenWidth =  metrics.widthPixels;
		screenHeigth =  metrics.heightPixels;
	}
	
//	public void showProgressDialog(String message){
//	}

}
3、新建一个照相的Activity(名叫PhotographActivity)继承了 BaseActivity,同时实现了OnClickListener, SurfaceHolder.Callback, PictureCallback三个接口。这时eclipse会自动提示必须实现onClick(View v)、surfaceCreated(SurfaceHolder holder)、surfaceChanged(SurfaceHolder holder, int format, int width, int height)、surfaceDestroyed(SurfaceHolder holder)、onPictureTaken(byte[] data, Camera camera)这四个方法,具体功能请看代码注释;

4、新建一个布局文件photograph.xml,用于显示打开相机后预览状态屏幕上显示的东西,和常见的相机界面差不多,如图:

Android学习笔记——简单实现照相、录音和录像功能_第1张图片

xml代码:




    

    

    

    

    

    

    

5、开始实现相机、录音和录像功能,请看代码和注释:

package xw.activity.photograph;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.Locale;

import xw.phonemanager.activity.BaseActivity;
import xw.phonemanager.activity.MenuActivity;
import xw.phonemanager.activity.R;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PictureCallback;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.format.DateFormat;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.Toast;

public class PhotographActivity extends BaseActivity implements
		OnClickListener, SurfaceHolder.Callback, PictureCallback {

	SurfaceView cameraPrew;// 预览图对象
	ImageView shot;
	ImageView flash;
	ImageView back;
	ImageView switchCamera;
	Button recordStart;
	Button recordStop;
	Button VCR;
	SeekBar focus;
	Camera camera;// 相机对象
	Camera.Parameters parameters;// 相机参数对象

	MediaRecorder mRecorder; // MediaRecorder对象,用于实现录音和录像

	private int cameraNum; // 摄像头的数量
	private int cameraID;// 摄像头的编号
	private boolean canSwitchCam = false;
	private boolean noSD;
	private int maxZoom; // 最大变焦
	private String recFileName; // 录音音频文件名称
	// 设置了两个判断标识,当处于录音状态时不允许拍照或录像,均置为false
	private boolean isPhoto = true; // 是否可以照相
	private boolean isVideo = true; // 是否可以录像

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

		setContentView(R.layout.photograph);

		Window window = getWindow();
		window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);// 屏幕高亮
		setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);// 强制横屏
		getWindow().setFormat(PixelFormat.TRANSPARENT);// 屏幕半透

		init();// 初始化
	}

	private void init() {
		checkSD();// 首先检测SD卡是否存在或可用,不可用则提示用户,避免浪费表情的尴尬:D
		cameraInit();
		prewInit();
		buttonInit();
		zoomInit();
		seekBarInit();
	}

	/**
	 * 检查是否有SD卡
	 */
	private void checkSD() {
		String SDtatus = Environment.getExternalStorageState();
		if (SDtatus == Environment.MEDIA_MOUNTED) {
			noSD = true;
			Toast.makeText(PhotographActivity.this, "没有SD卡或SD卡不可用",
					Toast.LENGTH_LONG).show();
		} else {
			noSD = false;
		}
	}

	/**
	 * 相机初始化
	 */
	private void cameraInit() {
		cameraNum = Camera.getNumberOfCameras();// 摄像头的个数
		if (camera != null) { // 若不为空,释放资源重新获取
			camera.release();
		}
		camera = Camera.open(); // 打开摄像头

		// 检测手机的摄像头个数,若不止一个则显示切换摄像头的图标,canSwitchCam置为true
		switchCamera = (ImageView) findViewById(R.id.switch_camera);
		if (cameraNum > 1) {
			switchCamera.setVisibility(View.VISIBLE);
			canSwitchCam = true;
			cameraID = 0;// 当前的摄像头ID设为0
		}
		// 相机实例获得相机参数集
		parameters = camera.getParameters();

	}

	/**
	 * 预览初始化
	 */
	private void prewInit() {
		cameraPrew = (SurfaceView) findViewById(R.id.camera);// 绑定SurfaceView并实例化

		cameraPrew.getHolder().setFixedSize((int) BaseActivity.screenWidth,
				(int) BaseActivity.screenHeigth);
		cameraPrew.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		cameraPrew.getHolder().addCallback(this);
		// 给整个屏幕的SurfaceView设置一个触摸监听,实现全屏手动对焦
		cameraPrew.setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				camera.autoFocus(null);// 点击屏幕即可对焦
				return false;
			}
		});
	}

	/**
	 * 按键初始化,设置按键监听
	 */
	private void buttonInit() {
		shot = (ImageView) findViewById(R.id.shot_btn);// 拍照键
		flash = (ImageView) findViewById(R.id.flash_switch);// 切换闪光灯键
		back = (ImageView) findViewById(R.id.back_btn);// 返回键
		recordStart = (Button) findViewById(R.id.record_start_btn);// 开始录音键
		recordStop = (Button) findViewById(R.id.record_stop_btn);// 结束录音键
		VCR = (Button) findViewById(R.id.video_btn);// 开始录像键

		// 设置监听
		shot.setOnClickListener(this);
		flash.setOnClickListener(this);
		back.setOnClickListener(this);
		switchCamera.setOnClickListener(this);
		recordStart.setOnClickListener(this);
		recordStop.setOnClickListener(this);
		VCR.setOnClickListener(this);
	}

	/**
	 * 滑动条实现变焦,初始化
	 */
	private void seekBarInit() {
		focus = (SeekBar) findViewById(R.id.seekbar_focal);
		focus.setProgress(0);
		focus.setMax(maxZoom);// 滑动条的最大值设为获得的相机可变焦值的最大值
		focus.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

			@Override
			public void onStopTrackingTouch(SeekBar seekBar) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onStartTrackingTouch(SeekBar seekBar) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onProgressChanged(SeekBar seekBar, int progress,
					boolean fromUser) {
				zoomChanged(progress);// 传递当前进度,变焦
			}
		});
	}

	private void zoomInit() {
		maxZoom = parameters.getMaxZoom();// 获得相机最大变焦范围
	}

	/**
	 * 按键监听
	 */
	@Override
	public void onClick(View v) {
		int id = v.getId();
		switch (id) {
		case R.id.shot_btn:
			if (isPhoto == true) {
				takPicture();
			} else {
				Toast.makeText(this, "无响应,正在录音", Toast.LENGTH_SHORT).show();
			}
			break;
		case R.id.flash_switch:
			flashSwitch();
			break;
		case R.id.back_btn:
			startActivity(new Intent(PhotographActivity.this,
					MenuActivity.class));
			finish();
			break;
		// 切换摄像头
		case R.id.switch_camera:
			if (canSwitchCam == true) {// 至少有两个才能切换
				if (camera != null) {
					camera.stopPreview();
					camera.release();
					Camera.open(++cameraID % cameraNum);// 在id:0~cameraNum之间切换
				}
			}
			break;

		case R.id.record_start_btn:
			if (noSD == true) { // 没有SD卡
				Toast.makeText(PhotographActivity.this, "没有SD卡或SD卡不可用",
						Toast.LENGTH_LONG).show();
				return;
			} else {
				startRec();// 开始录音
			}
			break;

		case R.id.record_stop_btn:
			stopRec();// 结束录音
			break;

		case R.id.video_btn:
			if (isVideo == true) {
				startVideo();// 开始录像
			} else {
				Toast.makeText(this, "无响应,正在录音", Toast.LENGTH_SHORT).show();
			}
			break;
		}
	}

	/**
	 * 切换闪光灯状态,如果当前是开状态,点击切换为关状态, 再点击切换为自动状态,再点击又到开状态
	 */
	private void flashSwitch() {
		if (parameters.getFlashMode() == Parameters.FLASH_MODE_AUTO) {
			flash.setImageResource(R.drawable.light_on);
			parameters.setFlashMode(Parameters.FLASH_MODE_ON);
			camera.setParameters(parameters);
		} else if (parameters.getFlashMode() == Parameters.FLASH_MODE_ON) {
			flash.setImageResource(R.drawable.light_off);
			parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
			camera.setParameters(parameters);
		} else {
			flash.setImageResource(R.drawable.light_auto);
			parameters.setFlashMode(Parameters.FLASH_MODE_AUTO);
			camera.setParameters(parameters);
		}
	}

	// 变焦
	private void zoomChanged(int zoom) {
		parameters.setZoom(zoom);
		camera.setParameters(parameters);
	}

	// 照像
	public void takPicture() {
		camera.autoFocus(null);
		camera.takePicture(null, null, this);
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		try {
			camera.setPreviewDisplay(cameraPrew.getHolder());// 获取相机预览
		} catch (IOException e) {
			e.printStackTrace();
		}
		camera.getParameters();// 获取相机参数实例
		camera.startPreview();
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		// TODO Auto-generated method stub

	}

	/**
	 * 退出相机界面后,释放相机相关资源
	 */
	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		if (camera != null) {
			camera.stopPreview();
			camera.release();
			camera = null;
		}
	}

	/**
	 * 拍照并保存,自动跳转到查看界面
	 */
	@Override
	public void onPictureTaken(byte[] data, Camera camera) {
		if (noSD == true) { // 没有SD卡
			Toast.makeText(PhotographActivity.this, "没有SD卡或SD卡不可用",
					Toast.LENGTH_LONG).show();
			return;
		} else {
			Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
			String name = DateFormat.format("yyyyMMdd_hhmmss",
					Calendar.getInstance(Locale.CHINA))
					+ ".jpg";// 自定义照片名字和格式
			File file = new File("sdcard/TianTian/photo/");
			file.mkdirs(); // 创建目录
			String fileName = "/mnt/sdcard/TianTian/photo/" + name;// 照片文件的绝对路径
			BufferedOutputStream bos = null;
			try {
				bos = new BufferedOutputStream(new FileOutputStream(fileName));
				bitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos);// 通过缓冲流存入

				// 拍完之后跳转到查看刚拍的照片的一个Activity(ConfirmActivity),用户可以选择是否保留图片
				ConfirmActivity.photoName = fileName;
				Uri imgUri = Uri.fromFile(new File(fileName));
				Intent intent = new Intent();
				intent.setClass(PhotographActivity.this, ConfirmActivity.class);
				intent.setData(imgUri);
				this.camera.stopPreview();// 停止预览
				startActivity(intent);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} finally {
				try {
					bos.close();// 关闭流
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	// 开始录音
	private void startRec() {
		// 录音时不能拍照和录像
		isPhoto = false;
		isVideo = false;

		mRecorder = new MediaRecorder();
		mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 设置录音员,从MIC获得声音
		mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);// 设置音频输出格式
		mRecorder.setAudioEncoder(MediaRecorder.VideoEncoder.DEFAULT);// 设置编码格式

		String path = Environment.getExternalStorageDirectory().getPath();
		String name = DateFormat.format("yyyyMMdd_hhmmss",
				Calendar.getInstance(Locale.CHINA))
				+ ".3gp";
		File file = new File(path);
		file.mkdirs();
		recFileName = path + "/" + name;
		file = new File(recFileName);
		if (!file.exists()) {
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		mRecorder.setOutputFile(recFileName);
		try {
			mRecorder.prepare();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		mRecorder.start(); // 录音开始
		Toast.makeText(this, "录音开始", Toast.LENGTH_SHORT).show();

		// “开始录音”后,将按钮换成“停止录音”获得焦点
		recordStart.setVisibility(View.GONE);
		recordStop.setVisibility(View.VISIBLE);
	}

	// 停止录音
	private void stopRec() {

		isPhoto = true;
		isVideo = true;

		mRecorder.stop();
		mRecorder.release();
		mRecorder = null;
		Toast.makeText(this, "录音结束", Toast.LENGTH_SHORT).show();

		// “停止录音”后,将按钮还原“开始录音”获得焦点
		recordStop.setVisibility(View.GONE);
		recordStart.setVisibility(View.VISIBLE);
	}

	/**
	 * 调用系统录像机录像
	 */
	private void startVideo() {
		camera.stopPreview();
		camera.release();
		camera = null;
		Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
		intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);
		startActivityForResult(intent, RESULT_FIRST_USER);
		finish();
	}

	/**
	 * 重写onKeyDown方法,当在相机界面按返回键退到主菜单而不是直接退出程序
	 */
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
			startActivity(new Intent(PhotographActivity.this,
					MenuActivity.class));
			finish();
		}
		return false;
	}

}

6、增加一个拍完照后可以查看所拍的照片的功能,并且可以选择保留或者删除当前的照片,选择后均会回到相机界面。新建一个ConfirmActivity,继承BaseActivity。代码:

package xw.activity.photograph;

import java.io.File;

import xw.phonemanager.activity.BaseActivity;
import xw.phonemanager.activity.R;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.net.Uri;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.Toast;

public class ConfirmActivity extends BaseActivity {

	public static String photoName;
	ImageView photo;// 显示所拍的照
	ImageView save;// 保留
	ImageView delete;// 删除

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

		setContentView(R.layout.confirm);
		setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);// 强制横屏

		photo = (ImageView) findViewById(R.id.photo_img);
		save = (ImageView) findViewById(R.id.photo_save);
		// 设置监听,点击后会自动回到相机界面
		save.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				Toast.makeText(ConfirmActivity.this, "照片已保存", Toast.LENGTH_LONG)
						.show();
				startActivity(new Intent(ConfirmActivity.this,
						PhotographActivity.class));
				finish();
			}
		});

		delete = (ImageView) findViewById(R.id.photo_delete);
		// 设置监听,点击后会自动回到相机界面
		delete.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				File file = new File(photoName);
				if (file.exists()) {
					file.delete();// 删除照片
					Toast.makeText(ConfirmActivity.this, "照片已删除",
							Toast.LENGTH_LONG).show();
					startActivity(new Intent(ConfirmActivity.this,
							PhotographActivity.class));
					finish();
				}
			}
		});

		showPic();// 显示所拍的照片
	}

	private void showPic() {
		Intent intent = getIntent();
		Uri originUri = intent.getData();
		photo.setImageURI(originUri);
	}

	/**
	 * 重写onKeyDown方法,当在相机界面按返回键退到主菜单而不是直接退出程序
	 */
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
			startActivity(new Intent(ConfirmActivity.this,
					PhotographActivity.class));
			finish();
		}
		return false;

	}
}

与之对应的xml:



    
    

    

    



至此,简单的照相、录音和录像功能基本实现,照相界面效果图:

Android学习笔记——简单实现照相、录音和录像功能_第2张图片


Android学习笔记——简单实现照相、录音和录像功能_第3张图片

学识鄙陋,未免贻笑大方,望见谅:)

谢谢。


你可能感兴趣的:(学习笔记)