基于Android TextureView与SurfaceTexture实现相机Camera拍照预览与保存照片
写一个简单的例子,实现一个常见的开发功能:拍照功能。
技术路线:通过TextureView的通道获取SurfaceTexture作为相机的预览,然后通过Camera的take方法把相机抓取的byte字节数据转换为Bitmap,然后存放到手机的存储器上,至此,一个最简单的拍照功能完成。
注意,本例如果运行在Android高版本(6.0+,7.0+或更高),需要多写运行时权限申请代码。本例出于功能演示,不再冗余的写这部分代码。只给出最骨干的关键代码逻辑。
布局文件activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<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"
android:background="@android:color/holo_blue_light"
tools:context="zhangphil.view.MainActivity">
<zhangphil.view.MyTextureView
android:id="@+id/textureView"
android:layout_width="300dp"
android:layout_height="200dp"
android:layout_centerInParent="true" />
<Button
android:id="@+id/capture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="拍摄" />
</RelativeLayout>
MyTextureView.java:
package zhangphil.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Environment;
import android.util.AttributeSet;
import android.util.Log;
import android.view.TextureView;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
/**
* Created by Phil on 2017/9/13.
*/
public class MyTextureView extends TextureView {
public Camera mCamera;
public MyTextureView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mCamera = Camera.open();
this.setSurfaceTextureListener(new SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
try {
mCamera.setPreviewTexture(surfaceTexture);
mCamera.startPreview();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
return true;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
});
}
public void take() {
if(mCamera!=null)
mCamera.takePicture(null, null, mPictureCallback);
}
Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
mCamera.stopPreview();
new FileSaver(data).save();
}
};
private class FileSaver implements Runnable {
private byte[] buffer;
public FileSaver(byte[] buffer) {
this.buffer = buffer;
}
public void save() {
new Thread(this).start();
}
@Override
public void run() {
try {
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "zhangphil.png");
file.createNewFile();
FileOutputStream os = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(os);
Bitmap bitmap = BitmapFactory.decodeByteArray(buffer, 0, buffer.length);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
bos.flush();
bos.close();
os.close();
Log.d("照片已保存", file.getAbsolutePath());
mCamera.startPreview();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
MainActivity.java:
package zhangphil.view;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
private MyTextureView textureView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textureView = (MyTextureView) findViewById(R.id.textureView);
findViewById(R.id.capture).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
textureView.take();
}
});
}
}
权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/>
代码运行结果: