如何解决 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 将特效应用到照片上

如何解决CameraX闪屏问题

如何解决移动设备(Wordpress 主题)的“响应式设计模式”问题?

iOS UIButton 点击无响应的解决办法

如何使用 cameraX 在相机应用程序中实现 FlashToggle 按钮?

校园网inode连接网络之后直接认证无响应,5分钟后重试