如何解决 CameraX 应用程序无响应的问题?
Posted
技术标签:
【中文标题】如何解决 CameraX 应用程序无响应的问题?【英文标题】:How to solve the CameraX app's being unresponsive? 【发布时间】:2019-10-28 10:51:12 【问题描述】:当基于GitHub repository 的示例CameraX
应用程序正在运行时,模拟器变得几乎没有响应(我无法平移相机)并消耗过多的计算能力(CPU 和GPU)。由于这种情况,您能指导我完成吗?
更新 (11.07.2019): 随着 CameraX
库 (1.0.0-alpha03
) 的最新更新,屏幕上除了图像按钮外没有显示任何内容。
这是我的活动代码:
public class MainActivity extends AppCompatActivity
private TextureView textureView;
private ImageButton captureButton;
private int REQUEST_CODE_CAMERA = 10;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initComponents();
checkPermissions();
private void initComponents()
textureView = findViewById(R.id.viewFinder);
captureButton = findViewById(R.id.captureButton);
private void checkPermissions()
final String permission = Manifest.permission.CAMERA;
boolean isPermissionGranted = PermissionUtil.checkForPermission(this, permission);
if (!isPermissionGranted)
boolean rationale = ActivityCompat.shouldShowRequestPermissionRationale(
MainActivity.this, permission);
if (rationale)
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("Camera Permission");
builder.setMessage("In order to take the photo of your vein, you need to grant camera permission.");
builder.setIcon(R.drawable.ic_info_accent);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
ActivityCompat.requestPermissions(MainActivity.this, new String[]permission, REQUEST_CODE_CAMERA);
);
AlertDialog alertDialog = builder.create();
alertDialog.show();
else
ActivityCompat.requestPermissions(MainActivity.this, new String[]permission, REQUEST_CODE_CAMERA);
else
startCamera();
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
if (requestCode == REQUEST_CODE_CAMERA)
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
startCamera();
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
private void startCamera()
//make sure there isn't another camera instance running before starting
CameraX.unbindAll();
/* start preview */
int aspRatioW = textureView.getWidth(); //get width of screen
int aspRatioH = textureView.getHeight(); //get height
Rational asp = new Rational(aspRatioW, aspRatioH); //aspect ratio
Size screen = new Size(aspRatioW, aspRatioH); //size of the screen
//config obj for preview/viewfinder thingy.
PreviewConfig pConfig = new PreviewConfig.Builder().setTargetAspectRatio(asp).setTargetResolution(screen).build();
Preview preview = new Preview(pConfig); //lets build it
preview.setOnPreviewOutputUpdateListener(
new Preview.OnPreviewOutputUpdateListener()
//to update the surface texture we have to destroy it first then re-add it
@Override
public void onUpdated(Preview.PreviewOutput output)
ViewGroup parent = (ViewGroup) textureView.getParent();
parent.removeView(textureView);
parent.addView(textureView, 0);
textureView.setSurfaceTexture(output.getSurfaceTexture());
updateTransform();
);
/* image capture */
//config obj, selected capture mode
ImageCaptureConfig imgCConfig = new ImageCaptureConfig.Builder().setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
.setTargetRotation(getWindowManager().getDefaultDisplay().getRotation()).build();
final ImageCapture imgCap = new ImageCapture(imgCConfig);
captureButton.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
ContextWrapper contextWrapper = new ContextWrapper(MainActivity.this);
String path = contextWrapper.getFilesDir().getPath();
File file = new File(path + "/" + System.currentTimeMillis() + ".jpg");
imgCap.takePicture(file, new ImageCapture.OnImageSavedListener()
@Override
public void onImageSaved(@NonNull File file)
String msg = "Photo capture succeeded: " + file.getAbsolutePath();
Toast.makeText(getBaseContext(), msg, Toast.LENGTH_LONG).show();
@Override
public void onError(@NonNull ImageCapture.UseCaseError useCaseError, @NonNull String message, @Nullable Throwable cause)
String msg = "Photo capture failed: " + message;
Toast.makeText(getBaseContext(), msg, Toast.LENGTH_LONG).show();
if (cause != null)
cause.printStackTrace();
);
);
/* image analyser */
ImageAnalysisConfig imgAConfig = new ImageAnalysisConfig.Builder().setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE).build();
ImageAnalysis analysis = new ImageAnalysis(imgAConfig);
analysis.setAnalyzer(
new ImageAnalysis.Analyzer()
@Override
public void analyze(ImageProxy image, int rotationDegrees)
//y'all can add code to analyse stuff here idek go wild.
);
//bind to lifecycle:
CameraX.bindToLifecycle((LifecycleOwner) this, analysis, imgCap, preview);
private void updateTransform()
//compensates the changes in orientation for the viewfinder, bc the rest of the layout stays in portrait mode.
//methinks :thonk:
Matrix mx = new Matrix();
float w = textureView.getMeasuredWidth();
float h = textureView.getMeasuredHeight();
float cX = w / 2f; //calc centre of the viewfinder
float cY = h / 2f;
int rotationDgr;
int rotation = (int) textureView.getRotation(); //cast to int bc switches don't like floats
switch (rotation) //correct output to account for display rotation
case Surface.ROTATION_0:
rotationDgr = 0;
break;
case Surface.ROTATION_90:
rotationDgr = 90;
break;
case Surface.ROTATION_180:
rotationDgr = 180;
break;
case Surface.ROTATION_270:
rotationDgr = 270;
break;
default:
return;
mx.postRotate((float) rotationDgr, cX, cY);
textureView.setTransform(mx); //apply transformations to textureview
布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
tools:context=".CameraActivity">
<TextureView
android:id="@+id/textureView"
android:layout_
android:layout_
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:id="@+id/btnCapture"
android:layout_
android:layout_
android:layout_margin="24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:srcCompat="@android:drawable/ic_menu_camera" />
</androidx.constraintlayout.widget.ConstraintLayout>
【问题讨论】:
【参考方案1】:我也遇到了这个问题,即使是来自 CameraX 的示例应用程序在我的模拟器上也有同样的问题。一行代码为我解决了这个问题。 改变这个:
ImageAnalysisConfig imgAConfig = new ImageAnalysisConfig.Builder()
.setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE).build();
到这里:
ImageAnalysisConfig imgAConfig = new ImageAnalysisConfig.Builder()
.setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE)
.setTargetResolution(Size(1280, 720)).build();
通过设置目标分辨率,我的问题得到了解决。希望它可以帮助您或其他人。
【讨论】:
【参考方案2】:我注意到了同样的事情,但它确实适用于普通手机。 ImageAnalysis
类似乎是问题所在。当我将analysis
用例从CameraX.bindToLifecycle
调用中退出时,我就可以使用模拟器了。我希望这有帮助。你可以肯定地说 CameraX 处于 alpha 阶段。
【讨论】:
以上是关于如何解决 CameraX 应用程序无响应的问题?的主要内容,如果未能解决你的问题,请参考以下文章
使用 CameraX Extensions API 将特效应用到照片上
如何解决移动设备(Wordpress 主题)的“响应式设计模式”问题?