首页 > 解决方案 > 使用带线程的相机

问题描述

我正在尝试获取相机的图像并连续处理它,所以,我使用的是 CameraKit 包:

package com.example.alex.tfmobile;

import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.camerakit.CameraKitView;
import java.io.InputStream;

public class MainActivity extends AppCompatActivity {

    private HandlerThread backgroundThread;
    private Handler backgroundHandler;
    private final Object lock = new Object();
    private boolean runClassifier = false;
    private static final String HANDLE_THREAD_NAME = "CameraBackground";

    TextView resultView;
    private CameraKitView cameraView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        cameraView = (CameraKitView) findViewById(R.id.camera);

        resultView = (TextView) findViewById(R.id.results);
        startBackgroundThread();
    }

    @Override
    protected void onResume() {
        super.onResume();
        cameraView.onResume();
        startBackgroundThread();
    }

    @Override
    protected void onPause() {
        cameraView.onPause();
        stopBackgroundThread();
        super.onPause();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        cameraView.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    private void startBackgroundThread() {
        backgroundThread = new HandlerThread(HANDLE_THREAD_NAME);
        backgroundThread.start();
        backgroundHandler = new Handler(backgroundThread.getLooper());
        synchronized (lock) {
            runClassifier = true;
        }
        backgroundHandler.post(periodicClassify);
    }

    private Runnable periodicClassify =
            new Runnable() {
                @Override
                public void run() {
                    synchronized (lock) {
                        if (runClassifier) {
                            classifyFrame();
                        }
                    }
                    backgroundHandler.post(periodicClassify);
                }
            };

    private void classifyFrame() {
        cameraView.captureImage(new CameraKitView.ImageCallback() {
            @Override
            public void onImage(CameraKitView cameraKitView, final byte[] picture) {
                Bitmap bitmap = BitmapFactory.decodeByteArray(picture, 0, picture.length);
            }
        });
    }

    private void stopBackgroundThread() {
        backgroundThread.quitSafely();
        try {
            backgroundThread.join();
            backgroundThread = null;
            backgroundHandler = null;
            synchronized (lock) {
                runClassifier = false;
            }
        } catch (InterruptedException e) {
            Log.e("TfMobile", "Interrupted when stopping background thread", e);
        }
    }
}

布局:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.camerakit.CameraKitView
        android:id="@+id/camera"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:camera_facing="back"/>

    <TextView
        android:id="@+id/results"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


</android.support.constraint.ConstraintLayout>

但问题出在classifyFrame方法上,当我尝试访问变量cameraView时,它抛出了 Null 指针异常。我想知道如何使用带有线程的相机来处理帧。

错误:

    Process: com.example.alex.tfmobile, PID: 26659
    java.lang.NullPointerException: Attempt to invoke virtual method 'int com.camerakit.CameraKitView$Size.getWidth()' on a null object reference
        at com.camerakit.CameraKitView$Camera2$1$7.run(CameraKitView.java:1844)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.os.HandlerThread.run(HandlerThread.java:61)
10-06 02:07:29.848 26659-26659/? E/ViewRootImpl@3b4860a[MainActivity]: ViewRootImpl #2 Surface is not valid.

标签: androidmultithreadingcameraandroid-cameraandroid-thread

解决方案


看起来您正在尝试在表面准备之前访问它,您可以尝试注释掉 startBackgroundThread(); 从 onCreate. 您已经从 onResume 调用它。希望它应该工作,或者你可以等到表面准备好。


推荐阅读