我正在开发一个相机应用程序,您可以在该应用程序中拍照并在AlertDialog中对其进行查看。在此对话框中,您可以拍照并保存或拍摄新照片。 完成后,我意识到我的代码非常慢。 当我触摸takePic-Button时,我等待5秒钟,直到显示AlertDialog。
这是模型类:
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class Model {
private static final int statePreview = 0;
private static final int waitLock = 1;
private int mState;
private Bitmap bitmap;
private Context context;
private File file;
private Activity activity;
private ImageView imageView;
private AlertDialog.Builder adb;
private static final SparseIntArray orientation = new SparseIntArray();
private CameraDevice cameraDevice;
private String cameraID;
private Size dimension;
private CameraCaptureSession cameraCaptureSession;
private CaptureRequest captureRequest;
private CaptureRequest.Builder captureRequestBuilder;
private Handler mBackgroundHandler;
private HandlerThread handlerThread;
private TextureView textureView;
public Boolean done;
public Model(Context context, TextureView textureView,Activity activity) {
this.activity = activity;
this.context = context;
this.textureView = textureView;
done = false;
adb = new AlertDialog.Builder(context);
}
/**
*Diese Methode lässt die Kamera den Bereich fokussieren auf den man Clickt
*und bleibt bei dem Fokus
*
* @param view
* @param motionEvent
* @return boolean
*
*
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public Boolean focusTouch(View view, MotionEvent motionEvent) {
int pointerId = motionEvent.getPointerId(0);
int pointerIndex = motionEvent.findPointerIndex(pointerId);
float x = motionEvent.getX(pointerIndex);
float y = motionEvent.getY(pointerIndex);
Rect touchRect = new Rect((int) (x - 100), (int) (y - 100), (int) (x + 100), (int) (y + 100));
if (cameraID == null) return false;
MeteringRectangle focusArea = new MeteringRectangle(touchRect, MeteringRectangle.METERING_WEIGHT_DONT_CARE);
try {
cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(),null,mBackgroundHandler);
mState = statePreview;
} catch (CameraAccessException e) {
e.printStackTrace();
}catch (IllegalStateException e){
Toast.makeText(context,"Not focused yet",Toast.LENGTH_SHORT).show();
}
try {
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_AUTO);
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, new MeteringRectangle[]{focusArea});
cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(),null,mBackgroundHandler);
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,CaptureRequest.CONTROL_AF_TRIGGER_START);
cameraCaptureSession.capture(captureRequestBuilder.build(),null,mBackgroundHandler);
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
cameraCaptureSession.capture(captureRequestBuilder.build(),null,mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
return false;
}
/**
* Ruft die openCamera() Funktion auf wenn die Bedingungen erfüllt sind
*/
TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
try {
openCamera();
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
};
CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
cameraDevice = camera;
try {
createCamerPreview();
}catch (CameraAccessException e){
e.printStackTrace();
}
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
cameraDevice.close();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void onError(@NonNull CameraDevice camera, int error) {
cameraDevice.close();
cameraDevice = null;
}
};
/**
* Erstellt die klassische Kamera perspektive
* @throws CameraAccessException
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void createCamerPreview() throws CameraAccessException {
SurfaceTexture texture = textureView.getSurfaceTexture();
texture.setDefaultBufferSize(dimension.getWidth(),dimension.getHeight());
Surface surface = new Surface(texture);
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(surface);
cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
if (cameraDevice == null) {
return;
}
cameraCaptureSession = session;
try {
updatePreview();
}catch (CameraAccessException e){
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
Toast.makeText(context, "Configuration Changed", Toast.LENGTH_LONG).show();
}
},null);
}
/**
* erneuert die Kamera perspektive
* @throws CameraAccessException
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void updatePreview() throws CameraAccessException {
if(cameraDevice==null){
return;
}
//captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
try {
cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);
}catch (IllegalStateException e){
e.printStackTrace();
}
}
/**
* Öffnet die Kamera
* @throws CameraAccessException
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void openCamera() throws CameraAccessException {
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
cameraID = manager.getCameraIdList()[0];
CameraCharacteristics cc = manager.getCameraCharacteristics(cameraID);
StreamConfigurationMap map = cc.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
dimension = map.getOutputSizes(SurfaceTexture.class)[0];
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED)
{
ActivityCompat.requestPermissions(((Activity)context),new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},101);
return;
}
manager.openCamera(cameraID, stateCallback, null);
}
/**
* Nimmt ein Foto auf und ruft die Überprüfung auf
* @throws CameraAccessException
*/
@RequiresApi(api = Build.VERSION_CODES.O)
public void takePic() throws CameraAccessException {
//lockFocus();
done = false;
//CameraStateHandler csh = new CameraStateHandler(getActivity(),this);
if(cameraDevice==null){
return;
}
CameraManager manager = (CameraManager)context.getSystemService(Context.CAMERA_SERVICE);
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
Size[] jpegSize = null;
jpegSize = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);
int width = 640;
int height = 480;
if(jpegSize!=null && jpegSize.length>0){
width = jpegSize[0].getWidth();
height = jpegSize[0].getHeight();
}
final ImageReader reader = ImageReader.newInstance(width,height,ImageFormat.JPEG,1);
List<Surface> outputSurface = new ArrayList<>(2);
outputSurface.add(reader.getSurface());
outputSurface.add(new Surface(textureView.getSurfaceTexture()));
final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(reader.getSurface());
//captureBuilder.set(CaptureRequest.CONTROL_MODE,CameraMetadata.CONTROL_MODE_AUTO);
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
//getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION,orientation.get(rotation));
Long tsLong = System.currentTimeMillis()/1000;
file = new File(Environment.getExternalStorageDirectory()+"/"+tsLong.toString()+".jpg");
// System.out.println(file.getAbsolutePath());
ImageReader.OnImageAvailableListener readerListenenr = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader imageReader) {
Image image = null;
image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
Matrix matrix = new Matrix();
matrix.postRotate(90);
bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, null);
bitmap = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);
check();
if (image != null) {
image.close();
}
}
};
reader.setOnImageAvailableListener(readerListenenr,mBackgroundHandler);
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
private void process(CaptureResult result){
switch (mState){
case statePreview:
break;
case waitLock:
Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
if (afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED) {
//unLockFocus();
//Toast.makeText(getApplicationContext(), "Focus Locked", Toast.LENGTH_LONG).show();
}
break;
}
}
@Override
public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber) {
super.onCaptureStarted(session, request, timestamp, frameNumber);
}
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
process(result);
try {
createCamerPreview();
}catch (CameraAccessException e){
e.printStackTrace();
}
}
@Override
public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) {
super.onCaptureFailed(session, request, failure);
Toast.makeText(context, "Focus don't Locked", Toast.LENGTH_LONG).show();
}
};
cameraDevice.createCaptureSession(outputSurface, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
try {
cameraCaptureSession.setRepeatingRequest(captureBuilder.build(), captureListener, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
}
},mBackgroundHandler);
}
/**
* Fragt den Benutzer ob er das geschossen Foto behalten will.
* Falls Ja wird das Bild gespeichert ansonsten kann er noch ein Bild machen
*/
public void check(){
AlertDialog.Builder adb = new AlertDialog.Builder(context);
imageView = new ImageView(context);
imageView.setImageBitmap(bitmap);
adb.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onClick(DialogInterface dialogInterface, int i) {
System.out.println("Ok Button gedrückt");
try {
save(toBase64());
dialogInterface.cancel();
} catch (IOException e) {
e.printStackTrace();
}
}
}).setView(imageView);
adb.setNegativeButton("Nochmal", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.cancel();
}
});
if(done==false) {
adb.create().show();
done=true;
}
}
/**
* Speicher das Bild auf dem Gerät und wandelt es in eine String um.
* Mit dem String wird das Bild im JSON-String gespeichert
* @param meta
* @throws IOException
*/
public void save(String meta) throws IOException {
// Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
// imageView.setImageBitmap(bitmap);
byte[] bytes = Base64.decode(meta.getBytes(),Base64.DEFAULT);
Toast.makeText(context,"Saved",Toast.LENGTH_LONG).show();
OutputStream outputStream = null;
outputStream = new FileOutputStream(file);
outputStream.write(bytes);
outputStream.close();
// addImagetoGallery(file.getAbsolutePath(), PictureActivity.this);
}
/**
* Konventiert ein Bild in einen String mit Hilfe von Base64
*
* @return String der das Bild representier
*
*/
@RequiresApi(api = Build.VERSION_CODES.O)
public String toBase64(){
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG,40,byteArrayOutputStream);
byte[] bytes = byteArrayOutputStream.toByteArray();
return Base64.encodeToString(bytes,Base64.DEFAULT);
}
/**
* Startet den Kamerahintergrund-Thread
*/
public void startBackgroundThread(){
handlerThread = new HandlerThread("Camera Background");
handlerThread.start();
mBackgroundHandler = new Handler(handlerThread.getLooper());
}
/**
* Stoppt den Kamerahintergrund-Thread
*/
@SuppressLint("NewApi")
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
protected void stopBackgroundThread() throws InterruptedException {
handlerThread.quitSafely();
handlerThread.join();
handlerThread = null;
mBackgroundHandler = null;
}
public Bitmap getBitmap() {return bitmap;
}
public void setBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
}
public AlertDialog.Builder getAdb() {
return adb;
}
public void setAdb(AlertDialog.Builder adb) {
}
这是控制器
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class PictureActivity extends AppCompatActivity {
private ImageReader imageReader;
private File file;
private Bitmap bitmap;
private Model model;
private ImageButton button;
private TextureView textureView;
/**
* Initialisiert View-Komponenten und das Model
* @param savedInstanceState
*/
@SuppressLint({"ClickableViewAccessibility", "ResourceType"})
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_picture);
textureView = (TextureView) findViewById(R.id.texture);
button = (ImageButton) findViewById(R.id.takePic);
textureView.setSurfaceTextureListener(textureListener);
model = new Model(PictureActivity.this,textureView,this);
button.setOnClickListener(new View.OnClickListener() {
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onClick(View view) {
try {
model.takePic();
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
});
textureView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
return model.focusTouch(view, motionEvent);
}
});
}
/**
* Stellt das Texture zur verfügung
*/
TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
try {
model.openCamera();
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
};
/**
* Überprüft on die Rechte für die Kamera gegeben sind
* @param requestCode
* @param permissions
* @param grantReesults
*/
@Override
public void onRequestPermissionsResult(int requestCode,@NonNull String[] permissions,@NonNull int[] grantReesults){
if(requestCode == 101){
if(grantReesults[0]==PackageManager.PERMISSION_DENIED){
Toast.makeText(getApplicationContext(),"Sorry, camera permission is neccesary",Toast.LENGTH_LONG).show();
//finsh
}
}
}
/**
* Stellt Kamera uf Texture dar
*/
@Override
protected void onResume() {
super.onResume();
model.startBackgroundThread();
if (textureView.isAvailable()){
try {
model.openCamera();
}catch (CameraAccessException e){
e.printStackTrace();
}
}else{
textureView.setSurfaceTextureListener(textureListener);
}
}
/**
* Stoppt die übertragung
*/
@SuppressLint("NewApi")
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
@Override
protected void onPause(){
try {
model.stopBackgroundThread();
}catch (InterruptedException e){
e.printStackTrace();
}
super.onPause();
}
}
this.adb = adb;
}
public ImageView getImageView() {
return imageView;
}
public void setImageView(ImageView imageView) {
this.imageView = imageView;
}
}