1、导入项目
zxing的源码下载了,并导入到as里面。导入的应该是下载源码的android部分。
现在最新的版本是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下面的代码注释即可。
有什么建议或者错误,请留言,以便改正。感谢浏览