1、导入项目

zxing的源码下载了,并导入到as里面。导入的应该是下载源码的android部分。修改zxing的源码实现无预览扫描

 

现在最新的版本是3.3.3,大家根据当时最新的版本来做出调整,只提供思路。但只导入android的话,是运行不了的,会报错,因为对应的包没有导入,网上有很多导入的方法。这个是其中一个方法,但as有gradle,本人偏向于使用gradle导入,在gradle加入如下依赖(请根据实际情况,查找对应的版本,如果不知道怎么查找gradle的各个版本,就百度:maven仓库,在仓库的页面里面搜索对应的类库,例如:zxing,这个方法适用于很多类库,里面提供了各种导入方法。)

dependencies {
·······
    compile 'com.google.zxing:core:3.3.3';
    compile 'com.google.zxing:android-core:3.3.0';
·······
}

这样运行应该是能通过的了。

 

2、修改

通常的扫描二维码都是使用surfaceView来做,但这样的话,不把摄像头的数据输出到屏幕是做不到的,现在是不预览,直接就扫描二维码。所以要换一种方式来做。(方法一二适用于非常旧的系统,因为SurfaceTexture在3.0就出现)

方法一

网上的方法,通常都是把预览的surfaceView做得很少,只有1px这样来解决预览输出的问题

方法二

其实surfaceView是可以给覆盖的,代码只不过是要输出到,但用户看不看得到时没有所谓的,只要布局合理,把surfaceView挡住,在surfaceView上面布局自己的控件即可

方法三

首先是搜索到这篇文章,这篇文章就是说怎么实现的,但只有几行代码,但起码提供了思路就好了。

在CaptureActivity就是主界面,现在的思路是用SurfaceTexture来取代SurfaceView,所以做了以下处理:

protected void onResume() {
    super.onResume();
    
    ·······

//    SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
//    SurfaceHolder surfaceHolder = surfaceView.getHolder();
//    if (hasSurface) {
      // The activity was paused but not stopped, so the surface still exists. Therefore
      // surfaceCreated() won't be called, so init the camera here.
      initCamera(null);
//    } else {
      // Install the callback and wait for surfaceCreated() to init the camera.
//      surfaceHolder.addCallback(this);
//    }
  }

private SurfaceTexture surfaceTexture = new SurfaceTexture(1);

  private void initCamera(SurfaceHolder surfaceHolder) {
//    if (surfaceHolder == null) {
//      throw new IllegalStateException("No SurfaceHolder provided");
//    }
    if (cameraManager.isOpen()) {
      Log.w(TAG, "initCamera() while already open -- late SurfaceView callback?");
      return;
    }
    try {

      cameraManager.openDriver(surfaceTexture);
      // Creating the handler starts the preview, which can also throw a RuntimeException.
      if (handler == null) {
        handler = new CaptureActivityHandler(this, decodeFormats, decodeHints, characterSet, cameraManager);
      }
      decodeOrStoreSavedBitmap(null, null);
    } catch (IOException ioe) {
      Log.w(TAG, ioe);
      displayFrameworkBugMessageAndExit();
    } catch (RuntimeException e) {
      // Barcode Scanner has seen crashes in the wild of this variety:
      // java.?lang.?RuntimeException: Fail to connect to camera service
      Log.w(TAG, "Unexpected error initializing camera", e);
      displayFrameworkBugMessageAndExit();
    }
  }

在onResume里面的最后面,把代码都注释掉,只留下initCamera(),这里在initCamera()的时候是需要一个surfaceView的,所以就传一个null进去(其实可以变成没有参数的函数,但在改代码的时候通常都维持源代码不变最好)。surfaceView的生成只要一个就行了,不然可能会导致一个BufferQueue has been abandoned这个问题。

在surfaceCreated的回调注释initCamera

  @Override
  public void surfaceCreated(SurfaceHolder holder) {
    if (holder == null) {
      Log.e(TAG, "*** WARNING *** surfaceCreated() gave us a null surface!");
    }
    if (!hasSurface) {
      hasSurface = true;
//      initCamera(holder);
    }
  }

在CameraManager里面做如下修改:

  public synchronized void openDriver(SurfaceTexture holder) throws IOException {
    OpenCamera theCamera = camera;
    ······
//    cameraObject.setPreviewDisplay(holder);
      cameraObject.setPreviewTexture(holder);
//    int buffersize = ImageFormat.getBitsPerPixel(ImageFormat.NV21);

//    cameraObject.addCallbackBuffer();
  }

把camera的setPreviewDisplay变成setPreVIewTexture就好了。

到现在为止应该是可以的了,但我的项目是需要前置摄像头,那么就要再做一些修改

在OpenCameraInterface做如下修改:

public static OpenCamera open(int cameraId) {

    int numCameras = Camera.getNumberOfCameras();
    if (numCameras == 0) {
      Log.w(TAG, "No cameras!");
      return null;
    }
    if (cameraId >= numCameras) {
      Log.w(TAG, "Requested camera does not exist: " + cameraId);
      return null;
    }

    if (cameraId <= NO_REQUESTED_CAMERA) {
      cameraId = 0;
      while (cameraId < numCameras) {
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        Camera.getCameraInfo(cameraId, cameraInfo);
        if (CameraFacing.values()[cameraInfo.facing] == CameraFacing.FRONT) {
          break;
        }
        cameraId++;
      }
      if (cameraId == numCameras) {
        Log.i(TAG, "No camera facing " + CameraFacing.BACK + "; returning camera #0");
        cameraId = 0;
      }
    }

    Log.i(TAG, "Opening camera #" + cameraId);
    Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
    Camera.getCameraInfo(cameraId, cameraInfo);
    Camera camera = Camera.open(cameraId);
    if (camera == null) {
      return null;
    }
    return new OpenCamera(cameraId,
                          camera,
                          CameraFacing.values()[cameraInfo.facing],
                          cameraInfo.orientation);
  }

把cameraFace改成Front就可以了。

但这样的话,有可能会出现分辨率不足的问题。遇到就如下解决:

CameraManager

  public synchronized Rect getFramingRectInPreview() {
    if (framingRectInPreview == null) {
      Rect framingRect = getFramingRect();
      if (framingRect == null) {
        return null;
      }
      Rect rect = new Rect(framingRect);
      Point cameraResolution = configManager.getCameraResolution();
      Point screenResolution = configManager.getScreenResolution();
      if (cameraResolution == null || screenResolution == null) {
        // Called early, before init even finished
        return null;
      }
//      rect.left = rect.left * cameraResolution.x / screenResolution.x;
//      rect.right = rect.right * cameraResolution.x / screenResolution.x;
//      rect.top = rect.top * cameraResolution.y / screenResolution.y;
//      rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y;

      rect.left = 0;
      rect.right = 1280;
      rect.top = 0;
      rect.bottom = 768;

      framingRectInPreview = rect;
    }
    return framingRectInPreview;
  }

这个rect取恰当的值,这个就根据自己的情况进行处理。

如果遇到程序自动关闭做如下修改:

InactivityTimer
 private final class InactivityAsyncTask extends AsyncTask<Object,Object,Object> {
    @Override
    protected Object doInBackground(Object... objects) {
      try {
        Thread.sleep(INACTIVITY_DELAY_MS);
        Log.i(TAG, "Finishing activity due to inactivity");
        //TODO 这里注释了不然能测试长久打开会怎么样
//        activity.finish();
      } catch (InterruptedException e) {
        // continue without killing
      }
      return null;
    }
  }

留意todo,把todo下面的代码注释即可。

 

 

有什么建议或者错误,请留言,以便改正。感谢浏览

相关文章:

  • 2021-07-04
  • 2022-12-23
  • 2021-12-04
  • 2021-07-25
  • 2021-10-13
  • 2021-08-16
猜你喜欢
  • 2022-02-03
  • 2021-08-27
  • 2021-12-14
  • 2021-05-23
相关资源
相似解决方案