Mobile VisionbarcodeScanner:SurfaceView为啥不更新CameraSource?

Posted

技术标签:

【中文标题】Mobile VisionbarcodeScanner:SurfaceView为啥不更新CameraSource?【英文标题】:Mobile Vision barcodeScanner: Why does SurfaceView not update CameraSource?Mobile VisionbarcodeScanner:SurfaceView为什么不更新CameraSource? 【发布时间】:2017-05-08 20:02:58 【问题描述】:

我一直在关注以下tutorial,它使用移动视觉 api 创建条形码/二维码扫描仪。虽然我已经输入了它所说的确切代码(至少我认为),但摄像头来自cameraSource

我在这个过程中添加了一些额外的代码,看看它是否会有所作为,但它仍然没有。问题是当我启动应用程序时,SurfaceView 应该显示CAMERA_FACING_BACK 提要,但它是纯黑色的。如果您能告诉我为什么提要没有显示,如果有任何需要更改的代码,将不胜感激。

MainActivity.java:

package com.example.neekondev.barcodeshortened;

import android.Manifest;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.util.SparseArray;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.TextView;

import com.google.android.gms.vision.CameraSource;
import com.google.android.gms.vision.Detector;
import com.google.android.gms.vision.barcode.Barcode;
import com.google.android.gms.vision.barcode.BarcodeDetector;

import java.io.IOException;

import static com.google.android.gms.vision.CameraSource.CAMERA_FACING_BACK;
import static com.google.android.gms.vision.CameraSource.CAMERA_FACING_FRONT;

public class MainActivity extends AppCompatActivity 

    SurfaceView cameraView;
    TextView barcodeInfo;

    BarcodeDetector barcodeDetector;
    CameraSource cameraSource;


    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        cameraView = (SurfaceView) findViewById(R.id.camera_view);
        barcodeInfo = (TextView) findViewById(R.id.code_info);
        barcodeDetector =
                new BarcodeDetector.Builder(this)
                        .setBarcodeFormats(Barcode.CODE_39 | Barcode.CODE_93 | Barcode.CODE_128)
                        .build();

        cameraSource = new CameraSource
                .Builder(this, barcodeDetector)
                .setRequestedPreviewSize(640, 480)
                .setRequestedFps(20.0f)
                .setFacing(CAMERA_FACING_BACK)
                .build();
        cameraView.getHolder().addCallback(new SurfaceHolder.Callback() 
            @Override
            public void surfaceCreated(SurfaceHolder holder) 
                try 
                    if (ActivityCompat.checkSelfPermission(getApplicationContext(),
                            Manifest.permission.CAMERA) !=
                            PackageManager.PERMISSION_GRANTED) 
                        // TODO: Consider calling
                        //    ActivityCompat#requestPermissions
                        // here to request the missing permissions, and then overriding
                        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                        //                                          int[] grantResults)
                        // to handle the case where the user grants the permission. See the documentation
                        // for ActivityCompat#requestPermissions for more details.
                        return;
                    
                    cameraSource.start(cameraView.getHolder());
                 catch (IOException ie) 
                    Log.e("CAMERA SOURCE", ie.getMessage());
                
            

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
            

            

            @Override
            public void surfaceDestroyed(SurfaceHolder holder)
            
                cameraSource.stop();
            
        );
        barcodeDetector.setProcessor(new Detector.Processor<Barcode>() 
            @Override
            public void release() 

            

            @Override
            public void receiveDetections(Detector.Detections<Barcode> detections) 
                final SparseArray<Barcode> barcodes = detections.getDetectedItems();

                if (barcodes.size() != 0) 
                    barcodeInfo.post(new Runnable()     // Use the post method of the TextView
                        public void run() 
                            barcodeInfo.setText(    // Update the TextView
                                    barcodes.valueAt(0).displayValue
                            );
                        
                    );
                
            
        );
    

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_
    android:layout_
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.neekondev.barcodeshortened.MainActivity">

    <SurfaceView
        android:layout_
        android:layout_
        android:layout_centerVertical="true"
        android:layout_alignParentLeft="true"
        android:id="@+id/camera_view"
        />

    <TextView
        android:layout_
        android:layout_
        android:id="@+id/code_info"
        android:layout_toRightOf="@+id/camera_view"
        android:textSize="20sp"
        android:layout_marginLeft="16dp"
        android:text="Nothing yet..."
        android:layout_alignParentTop="true"
        />
</RelativeLayout>

manifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.neekondev.barcodeshortened">

    <meta-data android:name="com.google.android.gms.vision.DEPENDENCIES" android:value="barcode"/>

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.Camera"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

【问题讨论】:

【参考方案1】:

没关系,我自己解决了这个问题,虽然我认为其他人在教程结束后可能会问同样的问题,所以我会告诉你哪里出了问题。您看,虽然我在 Manifest 中声明了权限,但 android.permissions.CAMERA 是“高风险权限”,这意味着用户需要手动同意才能实施。因为我从来没有直接向用户请求权限对话框,所以无法执行所有使用相机权限的代码,从而给我们提供了空白屏幕与相机的提要。一个简单的解决方法是进入设置并允许那里的权限,但可以使用以下代码代替,方便地通过对话框请求相机权限;

import android.Manifest;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.media.Image;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.util.SparseArray;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.google.android.gms.vision.CameraSource;
import com.google.android.gms.vision.Detector;
import com.google.android.gms.vision.barcode.Barcode;
import com.google.android.gms.vision.barcode.BarcodeDetector;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;

import java.io.IOException;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;

import static junit.framework.Assert.assertNotNull;

public class MainActivity
        extends AppCompatActivity 

    FirebaseDatabase database;
    DatabaseReference myRef;

    SurfaceView cameraView;
    TextView barcodeInfo;

    BarcodeDetector barcodeDetector;
    CameraSource cameraSource;

    private static final int CAMERA_PERMISSION_CAMERA = 0x000000;
    public static boolean position = false;
    //Camera cam;
    //Camera.Parameters p;

    @Override
    protected void onCreate(Bundle savedInstanceState) 

        setRequestedOrientation(ActivityInfo
                .SCREEN_ORIENTATION_PORTRAIT);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (ContextCompat.checkSelfPermission(MainActivity
                .this,
                Manifest
                        .permission
                        .CAMERA)
                != PackageManager
                .PERMISSION_GRANTED) 

            // Should we show an explanation?
            if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity
                    .this,
                    Manifest
                            .permission
                            .CAMERA)) 

                // Show an explanation to the user *asynchronously* -- don't block
                // this thread waiting for the user's response! After the user
                // sees the explanation, try again to request the permission.

             else 

                // No explanation needed, we can request the permission.

                ActivityCompat.requestPermissions(MainActivity
                        .this,
                        new String[]Manifest.permission
                                .CAMERA,
                        CAMERA_PERMISSION_CAMERA);

                // CAMERA_PERMISSION_CAMERA is an
                // app-defined int constant. The callback method gets the
                // result of the request.
            
        

        cameraView = (SurfaceView) findViewById(R
                .id
                .camera_view);
        barcodeInfo = (TextView) findViewById(R
                .id
                .code_info);

        MainActivity
                .this
                .getPackageManager()
                .hasSystemFeature
                        (PackageManager
                                .FEATURE_CAMERA_FLASH);

        barcodeDetector =
                new BarcodeDetector.Builder(getApplicationContext())
                        .setBarcodeFormats(Barcode.ALL_FORMATS)
                        .build();

        cameraSource = new CameraSource
                .Builder(getApplicationContext(), barcodeDetector)
                .setFacing(CameraSource.CAMERA_FACING_BACK)
                .setRequestedFps(35.0f)
                .setRequestedPreviewSize(960, 960)
                .setAutoFocusEnabled(true)
                .build();

        //setupButtons();


        cameraView.getHolder().addCallback(new SurfaceHolder
                .Callback() 
            @Override
            public void surfaceCreated(SurfaceHolder holder) 
                try 
                    if (ActivityCompat.checkSelfPermission(MainActivity.this,
                            Manifest.permission.CAMERA)
                            != PackageManager.PERMISSION_GRANTED) 
                        //      TODO: CONSIDER CALLING
                        //ActivityCompat#requestPermissions
                        // here to request the missing permissions, and then overriding
                        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                        //                                          int[] grantResults)
                        // to handle the case where the user grants the permission. See the documentation
                        // for ActivityCompat#requestPermissions for more details.


                        return;
                    
                    cameraSource.start(cameraView
                            .getHolder());
                 catch (IOException ie) 
                    Log.e("CAMERA SOURCE", ie
                            .getMessage());
                
            

            @Override
            public void surfaceChanged(SurfaceHolder holder,
                                       int format,
                                       int width,
                                       int height)

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) 
                cameraSource.stop();
            
        );
        barcodeDetector.setProcessor(new Detector.Processor<Barcode>()
        
            @Override
            public void release() 
            

            @Override
            public void receiveDetections(Detector.Detections<Barcode> detections)
            
                final SparseArray<Barcode> barcodes = detections.getDetectedItems();
                database = FirebaseDatabase.getInstance();
                myRef = database
                        .getReference(getTime());
                if (barcodes
                        .size() != 0) 
                    barcodeInfo
                            .post(new Runnable()     // Use the post method of the TextView
                        public void run() 
                            barcodeInfo.setText(barcodes
                                    .valueAt(0)
                                    .displayValue
                            );
                            myRef.setValue(barcodes
                                    .valueAt(0)
                                    .displayValue
                            );
                        
                    );
                
            
        );
    
/*
    public void FLASH_ON()
    
        cam = Camera.open();
        p = cam.getParameters();
        p.setFlashMode(Camera
                .Parameters
                .FLASH_MODE_TORCH);
        cam.setParameters(p);
        cam.startPreview();
    

    public void FLASH_OFF()
    cam.stopPreview();
        cam.release();

    public void setupButtons()
    
        ImageButton flash = (ImageButton)findViewById(R.id.flash);
        flash.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v)
            
                if (position == false)
                
                    FLASH_ON();
                    position = true;
                 if (position == true)
                
                    FLASH_OFF();
                    position = false;
                
            
        );
    */

    public String getTime()
    
        String downToSeconds = DateFormat
                .getDateTimeInstance()
                .format(
                        new Date());
        return downToSeconds;
    

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[],
                                           int[] grantResults) 
        switch (requestCode) 
            case CAMERA_PERMISSION_CAMERA: 
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0]
                        == PackageManager
                        .PERMISSION_GRANTED) 

                    Intent startMain = new Intent(MainActivity
                            .this, MainActivity
                            .class);
                    startActivity(startMain);

                 else 
                    if (ContextCompat.checkSelfPermission(MainActivity
                                    .this,
                            Manifest
                                    .permission
                                    .CAMERA)
                            != PackageManager
                            .PERMISSION_GRANTED) 

                        // Should we show an explanation?
                        if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity
                                        .this,
                                Manifest
                                        .permission
                                        .CAMERA)) 

                            // Show an explanation to the user *asynchronously* -- don't block
                            // this thread waiting for the user's response! After the user
                            // sees the explanation, try again to request the permission.

                         else 

                            // No explanation needed, we can request the permission.

                            ActivityCompat.requestPermissions(MainActivity
                                            .this,
                                    new String[]Manifest.permission
                                            .CAMERA,
                                    CAMERA_PERMISSION_CAMERA);

                            // CAMERA_PERMISSION_CAMERA is an
                            // app-defined int constant. The callback method gets the
                            // result of the request.
                        
                    
                
                return;
            
        
    

请原谅我的一些服务器代码。我也在将结果上传到 firebase 数据库。其余的都是相同的。布局对缩放有一些小的调整,但其余部分是相同的。祝你好运!

【讨论】:

当用户允许权限时,您是否重新启动全部活动? @androidnoobdev 是的,activity重启了。 需要重启activity才能触发surfaceCreated(SurfaceHolder holder)。

以上是关于Mobile VisionbarcodeScanner:SurfaceView为啥不更新CameraSource?的主要内容,如果未能解决你的问题,请参考以下文章

JQuery Mobile 1.3.1“$.mobile.loading”不工作

Jquery Mobile - $ .mobile.changepage没有加载外部.JS文件

jQuery Mobile中jQuery.mobile.changePage方法使用详解

我可以使用 $.mobile.loadPage() 一次加载我所有的 jQuery Mobile 页面吗?

Android FFMPEG 开发Android 中执行 FFMPEG 指令 ( mobile-ffmpeg 开源项目介绍 | 集成 mobile-ffmpeg 框架 )

用啥代替 $.mobile.changePage()?