我正在使用Camera2 API创建自定义相机。我想在使用相机预览保存图像后重新打开相机(继续拍摄图像)。我试图在保存图像后重新打开相机,但显示错误。
android.view.ViewRootImpl$CalledFromWrongThread异常:只有创建视图层次结构的原始线程可以触摸其视图。
private final TextureView.SurfaceTextureListener mSurfaceTextureListener
= new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
openCamera(width, height);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
configureTransform(width, height);
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
return true;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture texture) {
}
};
开放式摄像法
private void openCamera(int width, int height) {
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
requestCameraPermission();
return;
}
setUpCameraOutputs(width, height);
configureTransform(width, height);
Activity activity = getActivity();
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("Time out waiting to lock camera opening.");
}
manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
}
}
重新打开相机方法
public void reopenCamera() {
Log.d("REOPENCAMERA", "reopenCamera: called.");
if (mTextureView.isAvailable()) {
Log.d(TAG, "reopenCamera: a surface is available.");
if(stillCapturedImage){
capture++;
changeFrame(capture);
openCamera(mTextureView.getWidth(), mTextureView.getHeight());
}else{
openCamera(mTextureView.getWidth(), mTextureView.getHeight());
}
} else {
Log.d(TAG, "reopenCamera: no surface is available.");
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
}
}
捕获会话
private CameraCaptureSession.CaptureCallback mCaptureCallback
= new CameraCaptureSession.CaptureCallback() {
private void process(CaptureResult result) {
switch (mState) {
case STATE_PREVIEW: {
// We have nothing to do when the camera preview is working normally.
break;
}
case STATE_WAITING_LOCK: {
Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
if (afState == null) {
captureStillPicture();
} else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
mState = STATE_PICTURE_TAKEN;
captureStillPicture();
} else {
runPrecaptureSequence();
}
}
else if(afState == CaptureResult.CONTROL_AF_STATE_INACTIVE){
mState = STATE_PICTURE_TAKEN;
captureStillPicture();
}
break;
}
case STATE_WAITING_PRECAPTURE: {
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
mState = STATE_WAITING_NON_PRECAPTURE;
}
break;
}
case STATE_WAITING_NON_PRECAPTURE: {
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
mState = STATE_PICTURE_TAKEN;
captureStillPicture();
}
break;
}
}
}
@Override
public void onCaptureProgressed(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull CaptureResult partialResult) {
process(partialResult);
}
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
process(result);
}
};
保存图像方法
private void saveTempImageToStorage(){
Log.d(TAG, "saveTempImageToStorage: saving temp image to disk.");
final ICallback callback = new ICallback() {
@Override
public void done(Exception e) {
if(e == null){
Log.d(TAG, "onImageSavedCallback: image saved!");
mBackgroundImageRotater = new BackgroundImageRotater(getActivity());
mBackgroundImageRotater.execute();
mIsImageAvailable = true;
mCapturedImage.close();
}
else{
Log.d(TAG, "onImageSavedCallback: error saving image: " + e.getMessage());
showSnackBar("Error displaying image", Snackbar.LENGTH_SHORT);
}
}
};
ImageSaver imageSaver = new ImageSaver(
mCapturedImage,
getActivity().getExternalFilesDir(null),
callback
);
mBackgroundHandler.post(imageSaver);
}
重新启动摄像头的方法应该还可以,但您需要将一些后台任务(更新UI)移动到主线程。
示例代码:
runOnUiThread(new Runnable() {
@Override
public void run() {
// The code which updates your UI
}
});
最后,请确保您正确使用了生命周期方法。
你可以通过官方留档找到更多
我创建了一个主题为“导航抽屉活动”的项目,我想在左侧菜单上有两个选项: null
我在网站上非常关注教程和答案,但没有成功。花很多时间。 使用,方法TakePhotoAsync()未打开相机(Genymotion 9.0 API-28 |设备三星j7 prime.android 8.0)。 工作精彩。 AndroidManifest。xml 文件路径。xml 汇编信息。反恐精英 主要活动。反恐精英 方法XAML。反恐精英 问题在
我正在尝试使用在Flutter上,它在Android模拟器上运行完美。但是当我尝试在我的真实设备上使用它时,当我点击按钮打开相机时,它崩溃了,没有给出任何错误。我该如何解决它?我的手机是Android(小米8)。 我的代码:
“相机”组件定义用户从哪个角度查看场景。相机通常与允许输入设备移动和旋转相机的控件组件配对。 例子 位于人眼平均高度(1.6米)的照相机。 <a-entity camera= "userHeight: 1.6" look-controls></a-entity> 属性 属性 描述 默认值 active 在具有多个摄影机的场景中,摄影机是否为活动摄
CameraContext jd.createCameraContext() 创建 camera上下文 CameraContext 对象。
我想运行一个动画,文档声明: 返回一个CameraUpdate,用于变换相机,使指定的纬度/经度边界以最大可能的缩放级别在指定尺寸的边界框内的屏幕上居中。可以指定其他填充,以进一步限制边界框的大小。返回的CameraUpdate的方位角为0,倾斜角为0。 但我不想让它在屏幕上居中,我想把焦点区域向上移动,想象一个“align\u parent\u top”。所以我有一个摄像头更新工厂。通过滚动来实