这是一个非常长的答案,请仔细阅读以确保您没有遗漏任何内容。
您可以在我的Github Repo上看到示例项目。
首先,您必须将核心zxing库jar添加到项目目录中的libs文件夹中。您还需要为zxing类创建一个包。请参见下面的示例:
foo.bar.yourpackagename.zxing
foo.bar.yourpackagename.zxing.view
在第一个包
foo.bar.yourpackagename.zxing
中,您需要添加以下类:
CameraManager.java
import android.app.Activity;
import android.graphics.Rect;
import android.hardware.Camera;
import android.util.Log;
import android.view.Surface;
import com.google.zxing.PlanarYUVLuminanceSource;
public class CameraManager {
private static final double BOUNDS_FRACTION = 0.6;
private static final double VERTICAL_HEIGHT_FRACTION = 0.3;
private Camera camera;
private int cameraId;
private int orientation;
public CameraManager() {
this.camera = getCameraInstance();
}
public Camera getCamera() {
return camera;
}
public synchronized void startPreview() {
if (camera != null) {
camera.startPreview();
}
}
public synchronized void stopPreview() {
if (camera != null) {
camera.stopPreview();
}
}
public synchronized void release() {
if (camera != null) {
camera.release();
camera = null;
}
}
public synchronized boolean hasCamera() {
return camera != null;
}
public final synchronized Rect getBoundingRectUi(int uiWidth, int uiHeight) {
double heightFraction = BOUNDS_FRACTION;
double widthFraction = BOUNDS_FRACTION;
if (orientation == 90 || orientation == 270) {
heightFraction = VERTICAL_HEIGHT_FRACTION;
}
Log.d("CameraManager", "dimsUI[" + uiWidth + ", " + uiHeight + "]");
int height = (int) (uiHeight * heightFraction);
int width = (int) (uiWidth * widthFraction);
int left = (int) (uiWidth * ((1 - widthFraction) / 2));
int top = (int) (uiHeight * ((1 - heightFraction) / 2));
int right = left + width;
int bottom = top + height;
return new Rect(left, top, right, bottom);
}
public final synchronized Rect getBoundingRect() {
if (camera != null) {
Camera.Size previewSize = camera.getParameters().getPreviewSize();
int previewHeight = previewSize.height;
int previewWidth = previewSize.width;
double heightFraction = BOUNDS_FRACTION;
double widthFraction = BOUNDS_FRACTION;
if (orientation == 90 || orientation == 270) {
widthFraction = VERTICAL_HEIGHT_FRACTION;
}
Log.d("CameraManager", "dimsPrev[" + previewWidth + ", " + previewHeight + "]");
int height = (int) (previewHeight * heightFraction);
int width = (int) (previewWidth * widthFraction);
int left = (int) (previewWidth * ((1 - widthFraction) / 2));
int top = (int) (previewHeight * ((1 - heightFraction) / 2));
int right = left + width;
int bottom = top + height;
return new Rect(left, top, right, bottom);
}
return null;
}
public synchronized void requestNextFrame(Camera.PreviewCallback callback) {
if (camera != null) {
camera.setOneShotPreviewCallback(callback);
}
}
public synchronized PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height, Rect boundingRect) {
switch (orientation) {
case 0:
break;
case 90:
rotate90(data, width, height);
return new PlanarYUVLuminanceSource(data, height, width, boundingRect.top, boundingRect.left,
boundingRect.height(), boundingRect.width(), false);
case 180:
break;
case 270:
rotate90(data, width, height);
break;
}
return new PlanarYUVLuminanceSource(data, width, height, boundingRect.left, boundingRect.top,
boundingRect.width(), boundingRect.height(), false);
}
public void rotate90(byte[] data, int width, int height) {
int length = height * width;
int lengthDec = length - 1;
int i = 0;
do {
int k = (i * height) % lengthDec;
while (k > i) k = (height * k) % lengthDec;
if (k != i) swap(data, k, i);
} while (++i <= (length - 2));
}
public void setCameraDisplayOrientation(Activity activity) {
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360;
} else {
result = (info.orientation - degrees + 360) % 360;
}
orientation = result;
camera.setDisplayOrientation(result);
}
private Camera getCameraInstance() {
Camera c = null;
try {
cameraId = 0;
c = Camera.open();
Camera.Parameters p = c.getParameters();
p.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
c.setParameters(p);
} catch (Exception e) {
Log.e(CameraManager.class.getSimpleName(), "Camera error", e);
}
return c;
}
private static void swap(byte[] data, int k, int i) {
byte temp = data[k];
data[k] = data[i];
data[i] = temp;
}
}
CaptureHandler.java
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.widget.Toast;
public class CaptureHandler extends Handler {
public static final String DECODED_DATA = "decoded_data";
private CameraManager cameraManager;
private Context context;
private OnDecodedCallback callback;
public CaptureHandler(CameraManager cameraManager, Context context, OnDecodedCallback callback) {
this.cameraManager = cameraManager;
this.context = context;
this.callback = callback;
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case R.id.decoded:
String data = msg.getData().getString(DECODED_DATA);
Toast.makeText(context, data, Toast.LENGTH_LONG).show();
if (callback != null){
callback.onDecoded(data);
}
break;
case R.id.decode_failed:
cameraManager.requestNextFrame(new PreviewCallback(this, cameraManager));
break;
}
}
public static interface OnDecodedCallback {
void onDecoded(String decodedData);
}
}
PreviewCallback.java
import android.hardware.Camera;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import com.google.zxing.*;
import com.google.zxing.common.HybridBinarizer;
import foo.bar.yourpackagename.R;
public class PreviewCallback implements Camera.PreviewCallback {
private static final String TAG = PreviewCallback.class.getSimpleName();
private final MultiFormatReader multiFormatReader = new MultiFormatReader();
private Handler handler;
private CameraManager cameraManager;
public PreviewCallback(Handler handler, CameraManager cameraManager) {
this.handler = handler;
this.cameraManager = cameraManager;
}
@Override
public void onPreviewFrame(byte[] bytes, Camera camera) {
try {
Camera.Size previewSize = camera.getParameters().getPreviewSize();
new DecodeAsyncTask(previewSize.width, previewSize.height).execute(bytes);
} catch (Exception e) {
}
}
private class DecodeAsyncTask extends AsyncTask<byte[], Void, Result> {
private int width;
private int height;
private DecodeAsyncTask(int width, int height) {
this.width = width;
this.height = height;
}
@Override
protected void onPostExecute(Result result) {
if (result != null) {
Log.i(TAG, "Decode success.");
if (handler != null) {
Message message = Message.obtain(handler, R.id.decoded);
Bundle bundle = new Bundle();
bundle.putString(CaptureHandler.DECODED_DATA, result.toString());
message.setData(bundle);
message.sendToTarget();
}
} else {
Log.i(TAG, "Decode fail.");
if (handler != null) {
Message message = Message.obtain(handler, R.id.decode_failed);
message.sendToTarget();
}
}
}
@Override
protected Result doInBackground(byte[]... datas) {
if (!cameraManager.hasCamera()) {
return null;
}
Result rawResult = null;
final PlanarYUVLuminanceSource source =
cameraManager.buildLuminanceSource(datas[0], width,
height, cameraManager.getBoundingRect());
if (source != null) {
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
try {
rawResult = multiFormatReader.decodeWithState(bitmap);
} catch (Exception re) {
Log.e(TAG, "ERROR", re);
} finally {
multiFormatReader.reset();
}
}
return rawResult;
}
}
}
然后
将这三个类添加到foo.bar.yourpackagename.zxing
包后,您需要将以下类添加到foo.bar.yourpackagename.zxing.view
包中。
BoundingView.java
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import foo.bar.yourpackagename.zxing.CameraManager;
public class BoundingView extends View {
private CameraManager cameraManager;
public BoundingView(Context context) {
super(context);
}
public BoundingView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setCameraManager(CameraManager cameraManager) {
this.cameraManager = cameraManager;
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (cameraManager != null) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.parseColor("#00000000"));
Rect boundingRect = cameraManager.getBoundingRect();
canvas.drawRect(boundingRect, paint);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.parseColor("#44FF0000"));
paint.setStrokeWidth(5);
int incY = (canvas.getHeight() - boundingRect.height())/2;
int incX = (canvas.getWidth() - boundingRect.width())/2;
int y = (boundingRect.height()/2) + incY;
int x = boundingRect.width() + incX;
canvas.drawLine(incX, y, x, y, paint);
canvas.drawRect(new Rect(incX, boundingRect.top, x, boundingRect.bottom), paint);
}
}
}
CameraPreviewView.java
import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import foo.bar.yourpackagename.zxing.CameraManager;
import java.io.IOException;
public class CameraPreviewView extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = CameraPreviewView.class.getSimpleName();
private SurfaceHolder surfaceHolder;
private CameraManager cameraManager;
public CameraPreviewView(Context context) {
super(context);
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public CameraPreviewView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCameraManager(CameraManager cameraManager) {
this.cameraManager = cameraManager;
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
cameraManager.setCameraDisplayOrientation((Activity) getContext());
cameraManager.getCamera().setPreviewDisplay(holder);
cameraManager.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (surfaceHolder.getSurface() == null) {
return;
}
try {
cameraManager.stopPreview();
} catch (Exception e) {
}
try {
cameraManager.setCameraDisplayOrientation((Activity) getContext());
cameraManager.getCamera().setPreviewDisplay(surfaceHolder);
cameraManager.startPreview();
} catch (Exception e) {
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
完成上述操作后,您可以开始实现Activity
。请注意,有些类需要您为某些状态创建ID,例如:
R.id.decode_failed
您需要在应用程序的资源文件夹中创建这些ID。接下来,我们可以进入
Activity
的实现。
CaptureActivity.java
(注:此处为文件名)
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.RelativeLayout;
import foo.bar.yourpackagename.R;
import foo.bar.yourpackagename.zxing.CameraManager;
import foo.bar.yourpackagename.zxing.CaptureHandler;
import foo.bar.yourpackagename.zxing.PreviewCallback;
import foo.bar.yourpackagename.zxing.view.BoundingView;
import foo.bar.yourpackagename.zxing.view.CameraPreviewView;
public class CaptureActivity extends Activity {
public static String PUBLIC_STATIC_STRING_IDENTIFIER;
private CameraPreviewView cameraPreview;
private CameraManager cameraManager;
private Handler captureHandler;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getContentView());
initializeCamera();
initializeCameraPreview();
initializeBoundingView();
}
private View getContentView() {
RelativeLayout contentView = new RelativeLayout(this);
contentView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
contentView.addView(getBoundingView());
contentView.addView(getCameraPreviewView());
return contentView;
}
private CameraPreviewView getCameraPreviewView() {
CameraPreviewView camPreview = new CameraPreviewView(this);
camPreview.setId(R.id.camera_preview);
camPreview.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
return camPreview;
}
private BoundingView getBoundingView() {
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
params.addRule(RelativeLayout.CENTER_IN_PARENT);
BoundingView boundingView = new BoundingView(this);
boundingView.setId(R.id.bounding_view);
boundingView.setLayoutParams(params);
return boundingView;
}
private void initializeCamera() {
cameraManager = new CameraManager();
captureHandler = new CaptureHandler(cameraManager, this, new OnDecoded());
cameraManager.requestNextFrame(new PreviewCallback(captureHandler, cameraManager));
}
private void initializeCameraPreview() {
cameraPreview = (CameraPreviewView) findViewById(R.id.camera_preview);
cameraPreview.setCameraManager(cameraManager);
}
private void initializeBoundingView() {
((BoundingView) findViewById(R.id.bounding_view)).setCameraManager(cameraManager);
}
@Override
protected void onPause() {
super.onPause();
cameraManager.release();
}
private class OnDecoded implements CaptureHandler.OnDecodedCallback {
@Override
public void onDecoded(String decodedData) {
Intent resultIntent = new Intent();
resultIntent.putExtra(PUBLIC_STATIC_STRING_IDENTIFIER, decodedData);
setResult(Activity.RESULT_OK, resultIntent);
finish();
}
}
}
开始活动,你只需要调用以下代码:
```
startActivity(new Intent(this, CaptureActivity.class));
同样记得添加以下权限。
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
<uses-feature android:name="android.hardware.camera.flash" android:required="false" />
And your Activity
<activity
android:name=".CaptureActivity"
android:configChanges="orientation|keyboardHidden"
android:screenOrientation="landscape"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:windowSoftInputMode="stateAlwaysHidden" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="com.google.zxing.client.android.SCAN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
< p >到达
清单
!
如果您正确实现了所有这些类,那么就可以开始扫描条形码。