相机的surfaceview在android棒棒糖操作系统中不起作用
Posted
技术标签:
【中文标题】相机的surfaceview在android棒棒糖操作系统中不起作用【英文标题】:surfaceview for camera is not working in android lollipop os 【发布时间】:2015-10-06 21:34:12 【问题描述】:今天我在 android surfaceview for camera customization
中遇到了一个问题。
我尝试了下面的代码。
问题发生在我拍摄图像时,它会停止相机 预览并且不返回活动。
以下代码将在程序中实现。我从 *** 上的现有参考中获取了这段代码
支持类。
public class AndroidCameraSurfaceview extends Activity implements
SurfaceHolder.Callback
TextView testView;
Camera camera;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
boolean preview;
PictureCallback rawCallback;
ShutterCallback shutterCallback;
PictureCallback jpegCallback;
int displayheight, displaywidth;
Camera.PreviewCallback previewCallback;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.camerasurfaceview);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
jpegCallback = new PictureCallback()
public void onPictureTaken(byte[] data, Camera camera)
Bundle b = new Bundle();
b.putByteArray("Image", data);
Intent intent = new Intent();
intent.putExtras(b);
setResult(RESULT_OK, intent);
finish();
// refreshCamera();
;
public void captureImage(View v) throws IOException
// take the picture
camera.takePicture(null, null, jpegCallback);
public void refreshCamera()
if (surfaceHolder.getSurface() == null)
// preview surface does not exist
return;
try
camera.stopPreview();
catch (Exception e)
try
camera.setDisplayOrientation(90);
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
catch (Exception e)
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height)
if (preview)
camera.stopPreview();
try
Camera.Parameters parameters = camera.getParameters();
List<Size> sizes = parameters.getSupportedPreviewSizes();
Size optimalSize = getOptimalPreviewSize(sizes, width, height);
parameters.setPreviewSize(optimalSize.width, optimalSize.height);
camera.setParameters(parameters);
try
camera.setDisplayOrientation(90);
camera.setPreviewDisplay(holder);
camera.startPreview();
preview = true;
catch (IOException e)
e.printStackTrace();
catch(Exception e)
System.out.println("Surface Exception---=>"+e);
public void surfaceCreated(SurfaceHolder holder)
camera = Camera.open();
if (camera != null)
Camera.Parameters params = camera.getParameters();
camera.setDisplayOrientation(90);
camera.setParameters(params);
public void surfaceDestroyed(SurfaceHolder holder)
// stop preview and release camera
camera.stopPreview();
camera.release();
camera = null;
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h)
final double ASPECT_TOLERANCE = 1;
double targetRatio = (double) w / h;
if (sizes == null)
return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Size size : sizes)
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
continue;
if (Math.abs(size.height - targetHeight) < minDiff)
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
if (optimalSize == null)
minDiff = Double.MAX_VALUE;
for (Size size : sizes)
if (Math.abs(size.height - targetHeight) < minDiff)
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
return optimalSize;
2.在Activity中实现
public void captureImage()
Intent intentDriver = new Intent(AddNewDevice_Activity.this,
AndroidCameraSurfaceview.class);
startActivityForResult(intentDriver, 0);
//
// Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//
// Uri fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
//
// intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
//
// // start the image capture Intent
// startActivityForResult(intent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
// Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//
// fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
//
// intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
//
// // start the image capture Intent
// startActivityForResult(intent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
protected void onActivityResult(int requestCode, int resultCode, Intent data)
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0)
System.out.println("Result Code: " + resultCode);
if (resultCode == RESULT_OK && data != null)
Bundle bundle = data.getExtras();
byte[] test = bundle.getByteArray("Image");
Bitmap bpCamera = BitmapFactory.decodeByteArray(test, 0,
test.length);
Matrix matrix = new Matrix();
matrix.postRotate(90);
bpCamera = Bitmap
.createBitmap(bpCamera, 0, 0, bpCamera.getWidth(),
bpCamera.getHeight(), matrix, true);
imageView_camera.setImageBitmap(bpCamera);
selectedImageStr = encodeTobase64(bpCamera);
else
finish();
【问题讨论】:
你的意思是,onActivityResult()
不是在AndroidCameraSurfaceview.finish()
之后在onPictureTaken()
中调用的吗?您的日志是否显示 onPictureTaken()
被调用?也许,你的主要活动onCreate()
在那之后被调用了?
onPictureTaken() 未显示在我的日志中,它仅显示 LogCat 中的 Failed Binder Transaction,并且 ErrorLog 显示未处理的事件循环异常。我仍然无法解决这个问题,请帮助我。
感谢 sudhAnsu 先生格式化。很抱歉这个错误。
为什么你的 AndroidCameraSurfaceview 扩展了 Activity? (不是SurfaceView吗?)
好吧,就像在 Google 文档中一样,Camera 类自 API 21 以来已被弃用,所以也许你将不得不用这个 developer.android.com/reference/android/hardware/camera2/… 重新实现你的代码
【参考方案1】:
您拥有拆分活动和表面视图。
public class AndroidCameraActivity extends Activity
AndroidCameraSurfaceview surfaceView;
...
@Override
public void onCreate(Bundle savedInstanceState)
...
surfaceView = (AndroidCameraSurfaceview) findViewById(R.id.surfaceView);
class AndroidCameraSurfaceview extends SurfaceView implements SurfaceHolder.Callback
public AndroidCameraSurfaceview(Context context, AttributeSet attrs)
super(context, attrs);
getHolder().addCallback(this);
...
public void surfaceCreated(SurfaceHolder holder)
...
public void surfaceDestroyed(SurfaceHolder holder)
...
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height)
...
【讨论】:
Ecllipse Sdk 不支持此代码,所以我将我的代码迁移到 android studio。谢谢你的回答。 android.view.SurfaceView 无法转换为 com.xxxxxx.xxxxx.ui.ReadCardActivity$AndroidCameraSurfaceView 出现此错误【参考方案2】:Google 已从 API 版本 21 中修改了相机 API,因此我们必须采用新的 camera2 包,并且在相机功能出现的情况下必须遵守。这是 google 发布的示例代码的链接,它使用表面视图实现,它在 Android 5.0 中完美运行。我相信它解决了一些谜团。
https://github.com/googlesamples/android-Camera2Basic
【讨论】:
感谢 arunkarthick,但是在我的开发环境中使用 ecllipse,而不是迁移 android studio,你有什么想法把这段代码转换成 ecllipse 项目。 有什么替代方案吗?【参考方案3】:try this, I have made it from my self :
package com.fragments;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Date;
import java.text.SimpleDateFormat;
import com.jsonparsing.JsonMainActivity;
import com.jsonparsing.MailFragment;
import com.mobehc.R;
import com.sendmail.main;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.PictureCallback;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Environment;
import android.os.Handler;
import android.os.SystemClock;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
public class CamImageCapture2 extends Fragment implements
MediaRecorder.OnInfoListener
private Camera myCamera;
private MyCameraSurfaceView myCameraSurfaceView;
private MediaRecorder mediaRecorder;
Camera c = null;
ImageView myButton, myButton1, backcam;
SurfaceHolder surfaceHolder;
boolean recording;
private Button startButton;
private Button pauseButton;
private TextView timerValue;
private long startTime = 0L;
private Handler customHandler = new Handler();
long timeInMilliseconds = 0L;
long timeSwapBuff = 0L;
long updatedTime = 0L;
String path = Environment.getExternalStorageDirectory().toString()
+ "/00 MHC/VID.MP4";
/** Called when the activity is first created. */
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
View v = inflater.inflate(R.layout.activity_captureimage, container,
false);
recording = false;
getActivity().getWindow().addFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
timerValue = (TextView) v.findViewById(R.id.timer);
// Get Camera for preview
myCamera = getCameraInstance();
if (myCamera == null)
Toast.makeText(getActivity(), "Fail to get Camera",
Toast.LENGTH_LONG).show();
myCameraSurfaceView = new MyCameraSurfaceView(getActivity(), myCamera);
FrameLayout myCameraPreview = (FrameLayout) v
.findViewById(R.id.videoview);
myCameraPreview.addView(myCameraSurfaceView);
myButton = (ImageView) v.findViewById(R.id.rec);
myButton1 = (ImageView) v.findViewById(R.id.rec1);
backcam = (ImageView) v.findViewById(R.id.backcamera);
backcam.setOnClickListener(new OnClickListener()
@Override
public void onClick(View v)
Intent ik = new Intent(getActivity(), Camrec2.class);
startActivity(ik);
// getActivity().finish();
getActivity().getFragmentManager().popBackStack();
);
myButton1.setOnClickListener(new OnClickListener()
@Override
public void onClick(View v)
myCamera.takePicture(null, null, mPicture);
);
myButton.setOnClickListener(new OnClickListener()
@Override
public void onClick(View v)
File attachment1 = new File(Environment
.getExternalStorageDirectory(), "/00 MHC/image.jpg");
if (attachment1.exists())
attachment1.delete();
if (recording)
mediaRecorder.stop(); // stop the recording
releaseMediaRecorder(); // release the MediaRecorder object
// Exit after saved
getActivity().finish();
else
// Release Camera before MediaRecorder start
releaseCamera();
if (!prepareMediaRecorder())
Toast.makeText(getActivity(),
"Fail in prepareMediaRecorder()!\n - Ended -",
Toast.LENGTH_LONG).show();
getActivity().finish();
mediaRecorder.start();
startTime = SystemClock.uptimeMillis();
customHandler.postDelayed(updateTimerThread, 0);
/*
* final TextView _tv = (TextView) findViewById(R.id.timer);
* _tv.setVisibility(View.VISIBLE); new
* CountDownTimer(60000, 1000)
*
* public void onTick(long millisUntilFinished)
* _tv.setText(new SimpleDateFormat("00:ss") .format(new
* Date(millisUntilFinished)));
*
* public void onFinish() _tv.setText("done!"); Intent ii
* = new Intent(Camrecord.this, Emailtry.class);
* startActivity(ii); finish(); .start();
*/recording = true;
// myButton.setText("STOP");
Drawable myDrawable = getResources().getDrawable(
R.drawable.stp);
myButton.setImageDrawable(myDrawable);
backcam.setVisibility(View.INVISIBLE);
);
return v;
PictureCallback mPicture = new PictureCallback()
@Override
public void onPictureTaken(byte[] data, Camera camera)
File externalStorage = Environment.getExternalStorageDirectory();
String sdcardPath = externalStorage.getAbsolutePath() + "/00 MHC/";
File pictureFile = new File(sdcardPath + "/image" + ".jpg");
try
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
File attachment1 = new File(
Environment.getExternalStorageDirectory(),
"/00 MHC/VID.mp4");
if (attachment1.exists())
attachment1.delete();
Toast.makeText(getActivity(), "Captured Successfully...",
Toast.LENGTH_LONG).show();
Fragment fr = new main();
android.support.v4.app.FragmentTransaction fragmentTransaction = getFragmentManager()
.beginTransaction();
fragmentTransaction.replace(R.id.fragment_place, fr);
fragmentTransaction.commit();
// getActivity().finish();
catch (FileNotFoundException e)
catch (IOException e)
;
private Camera getCameraInstance()
// TODO Auto-generated method stub
try
// c = Camera.open(); // attempt to get a Camera instance
if (Camera.getNumberOfCameras() >= 2)
// backcam.setVisibility(View.VISIBLE);
// if you want to open front facing camera use this line
c = Camera.open(CameraInfo.CAMERA_FACING_FRONT);
c = Camera.open(CameraInfo.CAMERA_FACING_BACK);
else
c = Camera.open(CameraInfo.CAMERA_FACING_BACK);
/*
* c.setDisplayOrientation(90); c.setPreviewDisplay(surfaceHolder);
*
* Camera.Parameters p = c.getParameters(); p.set("camera-id", 2);
* c.setParameters(p);
*/
catch (Exception e)
// Camera is not available (in use or does not exist)
return c; // returns null if camera is unavailable
private boolean prepareMediaRecorder()
myCamera = getCameraInstance();
myCamera.setDisplayOrientation(90);
mediaRecorder = new MediaRecorder();
myCamera.unlock();
mediaRecorder.setCamera(myCamera);
mediaRecorder.setAudiosource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setProfile(CamcorderProfile
.get(CamcorderProfile.QUALITY_LOW));
mediaRecorder.setOrientationHint(270);
mediaRecorder.setOutputFile(path);
mediaRecorder.setMaxDuration(60000); // Set max duration 60 sec.
mediaRecorder.setOnInfoListener(this);
mediaRecorder.setMaxFileSize(2500000); // Set max file size 5M
// mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface());
mediaRecorder.setPreviewDisplay(myCameraSurfaceView.getHolder()
.getSurface());
try
mediaRecorder.prepare();
catch (IllegalStateException e)
releaseMediaRecorder();
return false;
catch (IOException e)
releaseMediaRecorder();
return false;
return true;
@Override
public void onPause()
super.onPause();
releaseMediaRecorder(); // if you are using MediaRecorder, release it
// first
releaseCamera(); // release the camera immediately on pause event
private void releaseMediaRecorder()
if (mediaRecorder != null)
mediaRecorder.reset(); // clear recorder configuration
mediaRecorder.release(); // release the recorder object
mediaRecorder = null;
myCamera.lock(); // lock camera for later use
private void releaseCamera()
if (myCamera != null)
myCamera.release(); // release the camera for other applications
myCamera = null;
public class MyCameraSurfaceView extends SurfaceView implements
SurfaceHolder.Callback
private SurfaceHolder mHolder;
private Camera mCamera;
public MyCameraSurfaceView(Context context, Camera camera)
super(context);
mCamera = camera;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
@Override
public void surfaceChanged(SurfaceHolder holder, int format,
int weight, int height)
// If your preview can change or rotate, take care of those events
// here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null)
// preview surface does not exist
return;
// stop preview before making changes
try
mCamera.stopPreview();
catch (Exception e)
// ignore: tried to stop a non-existent preview
// make any resize, rotate or reformatting changes here
// start preview with new settings
try
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
catch (Exception e)
@Override
public void surfaceCreated(SurfaceHolder holder)
// TODO Auto-generated method stub
// The Surface has been created, now tell the camera where to draw
// the preview.
try
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
catch (IOException e)
@Override
public void surfaceDestroyed(SurfaceHolder holder)
private Runnable updateTimerThread = new Runnable()
public void run()
timeInMilliseconds = SystemClock.uptimeMillis() - startTime;
updatedTime = timeSwapBuff + timeInMilliseconds;
int secs = (int) (updatedTime / 1000);
int mins = secs / 60;
secs = secs % 60;
int milliseconds = (int) (updatedTime % 1000);
timerValue.setText("" + mins + ":" + String.format("%02d", secs)
+ ":" + String.format("%03d", milliseconds));
customHandler.postDelayed(this, 0);
;
@Override
public void onInfo(MediaRecorder mr, int what, int extra)
if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED)
Log.v("VIDEOCAPTURE", "Maximum Duration Reached");
mediaRecorder.stop(); // stop the recording
releaseMediaRecorder(); // release the MediaRecorder object
// Exit after saved
// getActivity().finish();
getActivity().getFragmentManager().popBackStack();
【讨论】:
感谢您的回答,Parik dhakan 先生。【参考方案4】:我尝试了 Camera API 2,但我没有时间解决其中的问题 时间线。这就是我找到问题解决方案的方式 使用camera API 1. 当Multiple Views是Handle Single时 活动。请在相机处理的情况下尝试此代码。
protected void onActivityResult(int requestCode, int resultCode, Intent data)
if (requestCode == CAPTURE_IMAGE_CAPTURE_CODE)
if (resultCode == RESULT_OK)
Bitmap bp = (Bitmap) data.getExtras().get("data");
Bitmap resized = Bitmap.createScaledBitmap(bp,
(int) (bp.getWidth() * 0.8),
(int) (bp.getHeight() * 0.8), true);
imageView_camera.setImageBitmap(resized);
SharedPreferences value_1_Details = getSharedPreferences(
"Value_1_Key", MODE_PRIVATE);
Value_1_SelectedPosId = Integer.parseInt(value_1_Details.getString(
"Value_1_ID", ""));
String value_1_Name = value_1_Details.getString("Value_1_Data", "");
btn_popup_value_1_Name.setText(value_1_Name);
SharedPreferences value_2_Details = getSharedPreferences(
"Value_2_Key", MODE_PRIVATE);
value_2_SelectedPosId = Integer.parseInt(value_2_Details.getString(
"Value_2_ID", ""));
String value_2_Name = value_2_Details.getString("Value_2_Data", "");
btn_dropdown_value_2_Name.setText(value_2_Name);
SharedPreferences value_3_Details = getSharedPreferences(
"Value_3_Key", MODE_PRIVATE);
value_3_PosId = Integer.parseInt(value_3_Details
.getString("Value_3_ID", ""));
String value_3_Name = value_3_Details.getString("Value_3_Data",
"");
btn_dropdown_value_3_Name.setText(value_3_Name);
rL_include_ViewDetails.setVisibility(View.GONE);
rL_include_AddNew.setVisibility(View.VISIBLE);
rL_include_View.setVisibility(View.GONE);
selectedImageStr = encodeTobase64(resized);
else if (resultCode == RESULT_CANCELED)
Toast.makeText(this, "Cancelled", Toast.LENGTH_LONG).show();
【讨论】:
以上是关于相机的surfaceview在android棒棒糖操作系统中不起作用的主要内容,如果未能解决你的问题,请参考以下文章
如何在surfaceview中将Android相机更改为人像?