1、背景
同样这篇文章是为了练习代码的抽取能力,其实Camera的拍照后我们会获取到原始照片的数据,这些数据我们可以进行处理;比如加个滤镜,美白等等;这就是我们的美白相机了,但对于图片的处理,我们最好在底层处理;然后把处理的图片数据再转换成图片,最后展示给用户,美白相机的大体流程就是这样的,不过今天主要练习代码的抽取能力;虽然上次已经写过了,只有经过反复的训练,我们才能对怎样抽取代码,并进行封装得心用手;
2、方法(来自疯狂Androud讲义)
Android应用提供了Camera来控制拍照,使用Camera进行拍照比较简单,按如下步骤进行即可。 1:调用Camera的open()方法打开相机。该方法默认打开后置摄像头。如果需要打开指定摄像头,可以为该方法传入声响头ID. 2:调用Camera的getParameters()方法获取拍照参数,该方法返回一个Camera.Parameters对象。 3:调用Camera.Parameters对象方法设置拍照参数; 4:调用Camera的startPreview()方法开始预览取景,在预览取景之前调用Camera的setPreviewDisplay(SurfaceViewHolder holder)方法设置使用哪个SurfaceView来显示取景图片。 5:调用Camera的takePicture()方法进行拍照。 6:结束程序时,调用Camera的stopPreview()结束取景预览,并调用release()方法释放资源;
3、实例
该实例通过预览,当我们点击拍照后,会弹出一个对话框,让用户输入图片的名字;
1、MainActivity布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center_horizontal"
android:layout_marginBottom="8dp"
>
<Button
android:id="@+id/btn_capture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/normal_capture"
/>
</LinearLayout>
</RelativeLayout>
2、对话框布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="5dp"
>
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="文件名:"
android:textSize="20sp"
/>
<EditText
android:id="@+id/et_filename"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
<ImageView
android:id="@+id/iv_picture"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter"
/>
</LinearLayout>
3、MainActivity代码:
public class MyActivity01 extends Activity implements SurfaceHolder.Callback,OnClickListener{
private SurfaceView surfaceView;
private Button ib_capture;
private Camera mCamera;
private int screenWidth;
private int screenHeight;
private boolean isPreview =
false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initView();
}
private void initData() {
DisplayMetrics outMetrics =
new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(outMetrics);;
screenWidth = outMetrics.widthPixels;
screenHeight = outMetrics.heightPixels;
}
private void initView() {
surfaceView = (SurfaceView)
this.findViewById(R.id.surfaceView);
surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceView.getHolder().addCallback(
this);
ib_capture = (Button)
this.findViewById(R.id.btn_capture);
ib_capture.setOnClickListener(
this);
}
@Override
public void surfaceChanged(SurfaceHolder holder,
int format,
int width,
int height) {
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
initCamera();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if(
null != mCamera){
if(isPreview)
mCamera.stopPreview();
mCamera.release();
mCamera =
null;
}
}
@Override
public void onClick(View v) {
if(
null != mCamera){
mCamera.autoFocus(
new MyAutoFocusCallback());
}
}
private void initCamera() {
if(!isPreview){
mCamera = Camera.open();
mCamera.setDisplayOrientation(
90);
}
if(
null != mCamera && !isPreview){
try {
mCamera.setPreviewDisplay(surfaceView.getHolder());
Parameters mParameters = mCamera.getParameters();
mParameters.setPreviewSize(screenWidth, screenHeight);
mParameters.setPreviewFpsRange(
4,
10);
mParameters.setPictureFormat(ImageFormat.JPEG);
mParameters.setJpegQuality(
88);
mParameters.setPictureSize(screenWidth, screenHeight);
mCamera.startPreview();
}
catch (Exception e) {
e.printStackTrace();
}
}
isPreview =
true;
}
@Override
protected void onDestroy() {
super.onDestroy();
if(
null != mCamera){
if(isPreview)
mCamera.stopPreview();
mCamera.release();
mCamera =
null;
}
}
private final class MyAutoFocusCallback implements AutoFocusCallback{
@Override
public void onAutoFocus(
boolean success, Camera camera) {
if(success){
camera.takePicture(
new ShutterCallback() {
@Override
public void onShutter() {
}
},
new PictureCallback() {
@Override
public void onPictureTaken(
byte[] data, Camera camera) {
}
},
new MyPictureCallback());
}
}
}
private final class MyPictureCallback implements PictureCallback{
@Override
public void onPictureTaken(
byte[] data, Camera camera) {
final Bitmap bitmap = BitmapFactory.decodeByteArray(data,
0, data.length);
View view = View.inflate(MainActivity.
this, R.layout.dialog_view,
null);
ImageView mImageView = (ImageView) view.findViewById(R.id.iv_picture);
final EditText et_filename = (EditText) view.findViewById(R.id.et_filename);
mImageView.setImageBitmap(bitmap);
new AlertDialog.Builder(MainActivity.
this)
.setView(view)
.setPositiveButton(
"保存",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
String fileName = et_filename.getText().toString().trim();
if(
null != fileName || !
"".equals(fileName)){
try {
File file =
new File(Environment.getExternalStorageDirectory(),fileName+
".jpeg");
OutputStream outStream =
new FileOutputStream(file);
bitmap.compress(CompressFormat.JPEG,
100, outStream );
outStream.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
else{
Toast.makeText(MainActivity.
this,
"文件名为空,保存失败!!!", Toast.LENGTH_LONG).show();
}
}
})
.setNegativeButton(
"取消",
null)
.show();
mCamera.stopPreview();
mCamera.startPreview();
isPreview =
true;
}
}
}
我们通过initView()、initData()等方法来把我们的代码逻辑清晰, 当大量的代码都放在MainActivity中时,依旧效果不是很好。 我们通过分析可以发现在MainActivity中Came的设置占据了大量代码,比如:Camera的initCamera()以及Camera拍照时设置的回调方法;所以我们可以把这些方法抽取出来,放到CameraEngine中:
4、CameraEngine类:
public class CameraEngine {
private MainActivity context;
private Camera mCamera;
private int screenWidth;
private int screenHeight;
private boolean isPreview =
false;
public CameraEngine(Context context){
this.context = (MainActivity) context;
initData();
}
public void initData(){
DisplayMetrics outMetrics =
new DisplayMetrics();
context.getWindowManager().getDefaultDisplay().getMetrics(outMetrics);;
screenWidth = outMetrics.widthPixels;
screenHeight = outMetrics.heightPixels;
}
public void onDestroy(){
if(
null != mCamera){
if(isPreview)
mCamera.stopPreview();
mCamera.release();
mCamera =
null;
}
}
public void initCamera(SurfaceView surfaceView){
if(!isPreview){
mCamera = Camera.open();
mCamera.setDisplayOrientation(
90);
}
if(
null != mCamera && !isPreview){
try {
mCamera.setPreviewDisplay(surfaceView.getHolder());
Parameters mParameters = mCamera.getParameters();
mParameters.setPreviewSize(screenWidth, screenHeight);
mParameters.setPreviewFpsRange(
4,
10);
mParameters.setPictureFormat(ImageFormat.JPEG);
mParameters.setJpegQuality(
88);
mParameters.setPictureSize(screenWidth, screenHeight);
mCamera.startPreview();
}
catch (Exception e) {
e.printStackTrace();
}
}
isPreview =
true;
}
public void autoFocus(){
if(
null != mCamera){
mCamera.autoFocus(
new MyAutoFocusCallback());
}
}
private final class MyAutoFocusCallback implements AutoFocusCallback{
@Override
public void onAutoFocus(
boolean success, Camera camera) {
if(success){
camera.takePicture(
new ShutterCallback() {
@Override
public void onShutter() {
}
},
new PictureCallback() {
@Override
public void onPictureTaken(
byte[] data, Camera camera) {
}
},
new MyPictureCallback());
}
}
}
private final class MyPictureCallback implements PictureCallback{
@Override
public void onPictureTaken(
byte[] data, Camera camera) {
final Bitmap bitmap = BitmapFactory.decodeByteArray(data,
0, data.length);
View view = View.inflate(context, R.layout.dialog_view,
null);
ImageView mImageView = (ImageView) view.findViewById(R.id.iv_picture);
final EditText et_filename = (EditText) view.findViewById(R.id.et_filename);
mImageView.setImageBitmap(bitmap);
new AlertDialog.Builder(context)
.setView(view)
.setPositiveButton(
"保存",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
String fileName = et_filename.getText().toString().trim();
if(
null != fileName || !
"".equals(fileName)){
try {
File file =
new File(Environment.getExternalStorageDirectory(),fileName+
".jpeg");
OutputStream outStream =
new FileOutputStream(file);
bitmap.compress(CompressFormat.JPEG,
100, outStream );
outStream.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
else{
Toast.makeText(context,
"文件名为空,保存失败!!!", Toast.LENGTH_LONG).show();
}
}
})
.setNegativeButton(
"取消",
null)
.show();
mCamera.stopPreview();
mCamera.startPreview();
isPreview =
true;
}
}
}
5、抽取之后的MainActivity代码:
public class MainActivity extends Activity implements SurfaceHolder.Callback,OnClickListener{
private SurfaceView surfaceView;
private Button ib_capture;
private CameraEngine cameraEngine;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
cameraEngine =
new CameraEngine(
this);
initView();
}
private void initView() {
surfaceView = (SurfaceView)
this.findViewById(R.id.surfaceView);
surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceView.getHolder().addCallback(
this);
ib_capture = (Button)
this.findViewById(R.id.btn_capture);
ib_capture.setOnClickListener(
this);
}
@Override
public void surfaceChanged(SurfaceHolder holder,
int format,
int width,
int height) {
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
cameraEngine.initCamera(surfaceView);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
cameraEngine.onDestroy();
}
@Override
public void onClick(View v) {
cameraEngine.autoFocus();
}
@Override
protected void onDestroy() {
super.onDestroy();
cameraEngine.onDestroy();
}
}
是不是很简单,MainActivity还可以更进一步的抽取;剩下的就交给你们了;