蛰伏半月有余,一直在准备期末考试,期间抽空研究了一些Android的源代码,现在我就把在这其中的一些收获分享给大家。
今天想分享给大家的是二维码扫描。说起二维码,大家一定不会陌生,尤其是微信火了以后,在我们的生活中几乎随处都可以看到二维码的影
子。相关科技媒体甚至把二维码当成是未来移动互联网的入口,因此研究二维码的相关技术就显得意义非凡。目前在移动开发领域,使用最为广泛的二
维码库有两个,分别是ZXing和ZBar,其中ZXing在Android开发中较为常见,而ZBar则在IOS开发中较为常见,更重要的一点是,这两个库都是开源
的,因此我们可以从源代码中获得很多有用的东西。关于ZXing,网上有很多相关的博文,我今天不想多说,我今天想说的是ZBar,你可能会说,ZBar
不是用在IOS中,怎么今天要说ZBar呢?其实我是从这两个库使用的难易程度来选择的,ZXing功能强大,但是使用起来比较繁琐,网上有很多简化的
教程,大家可以自行前去研究。相比较而言,ZBar则比较简单,使用起来容易上手,因此我们今天选择了ZBar作为我们的库来使用。
一、准备工作
下载ZBar的SDK:由于ZBar的项目托管在sourceforge,所以在这里给出下载地址:http://download.csdn.net/detail/qinyuanpei/6794713
二、导入项目
下载完成后,我们直接解压,可以看到下面的目录结构
打开android文件夹,我们可以找到一个Example的文件夹,这是官方给出的示例代码,我们下面的所有工作都是基于这个示例程序而来。我们
自行创建一个Android项目,并将这两个文件拷贝到我们的项目中,同时引入ZBar相关的库文件。
三、建立布局
首先建立主界面,即扫描二维码的界面,界面布局代码如下:
<!--?xml version="1.0" encoding="utf-8"?--> <linearlayout android:layout_height="match_parent" android:layout_width="match_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"> <relativelayout android:layout_height="40dp" android:layout_width="match_parent" android:background="@drawable/title_bg"> <textview android:layout_height="wrap_content" android:layout_width="wrap_content" android:textsize="18sp" android:textcolor="#ffffff" android:text="@string/Scan" android:layout_centervertical="true" android:layout_centerhorizontal="true"> <button android:id="@+id/BtnAbout" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="@string/BtnAbout" android:layout_alignparenttop="true" android:layout_alignparentright="true"> <frameLayout android:id="@+id/cameraPreview" android:layout_width="match_parent" android:layout_height="0dip" android:layout_weight="1"/> </button></textview></relativelayout></linearlayout>
实现的布局效果如下图所示:
接下里,我们在来设计一个用于显示结果的界面,界面布局代码如下:
<!--?xml version="1.0" encoding="utf-8"?--> <linearlayout android:layout_height="match_parent" android:layout_width="match_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android" android:background="#ffffff"> <relativelayout android:layout_height="40dp" android:layout_width="match_parent" android:background="@drawable/title_bg"> <textview android:layout_height="wrap_content" android:layout_width="wrap_content" android:textsize="18sp" android:textcolor="#ffffff" android:text="@string/Result" android:layout_centervertical="true" android:layout_centerhorizontal="true"> <button android:id="@+id/BtnBack" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="@string/BtnBack" android:layout_alignparenttop="true" android:layout_alignparentleft="true"> <textview android:id="@+id/TextResult" android:layout_height="wrap_content" android:layout_width="match_parent" android:textcolor="#000000" android:textisselectable="true" android:layout_margin="8dp"> </textview></button></textview></relativelayout></linearlayout>
实现的界面效果如图所示:
四、编写代码
首先我们来写一个用于扫描的相机预览视图CameraPreview,此文件由ZBar的SDK提供,这里我做了下简单的修改
package com.Android.ZBar4Android; import java.io.IOException; import android.util.Log; import android.view.SurfaceView; import android.view.SurfaceHolder; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Canvas; import android.hardware.Camera; import android.hardware.Camera.Parameters; import android.hardware.Camera.PreviewCallback; import android.hardware.Camera.AutoFocusCallback; //此类由ZBar项目的SDK提供,我做了下修改 @SuppressLint("ViewConstructor") public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder mHolder; private Camera mCamera; private PreviewCallback mPreviewCallBack; private AutoFocusCallback mAutoFocusCallBack; public CameraPreview(Context context, Camera camera, PreviewCallback previewCb, AutoFocusCallback autoFocusCb) { super(context); mCamera = camera; mPreviewCallBack = previewCb; mAutoFocusCallBack = autoFocusCb; /* * 自动聚焦 * 要求API版本>9 */ Camera.Parameters parameters = camera.getParameters(); for (String f : parameters.getSupportedFocusModes()) { if (f == Parameters.FOCUS_MODE_CONTINUOUS_PICTURE) { parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); mAutoFocusCallBack = null; break; } } // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. mHolder = getHolder(); mHolder.addCallback(this); // deprecated setting, but required on Android versions prior to 3.0 mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } public void surfaceCreated(SurfaceHolder holder) { // The Surface has been created, now tell the camera where to draw the preview. try { mCamera.setPreviewDisplay(holder); } catch (IOException e) { Log.d("DBG", "Error setting camera preview: " + e.getMessage()); } } public void surfaceDestroyed(SurfaceHolder holder) { // Camera preview released in activity } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { /* * If your preview can change or rotate, take care of those events here. * Make sure to stop the preview before resizing or reformatting it. */ if (mHolder.getSurface() == null){ // preview surface does not exist return; } // stop preview before making changes try { mCamera.stopPreview(); } catch (Exception e){ // ignore: tried to stop a non-existent preview } try { // Hard code camera surface rotation 90 degs to match Activity view in portrait mCamera.setDisplayOrientation(90); mCamera.setPreviewDisplay(mHolder); mCamera.setPreviewCallback(mPreviewCallBack); mCamera.startPreview(); mCamera.autoFocus(mAutoFocusCallBack); } catch (Exception e){ Log.d("DBG", "Error starting camera preview: " + e.getMessage()); } } /* * 绘制校准框 * 修改:秦元培 * 时间:2013年11月22日 * */ @Override protected void onDraw(Canvas mCanvas) { //这里不会写了? } }
接下来,我们来编写主界面的逻辑代码,在这里我们需要搞清楚的几个问题有:
1、相机的获取及相机的交互处理
2、二维码图片的获取
3、二维码图片的解析
对于第一个问题,需要我们深入地了解相机的工作原理,即我们需要了解Camera类。
获取相机的代码如下:
//获取照相机的方法 public static Camera getCameraInstance() { Camera mCamera = null; try { mCamera = Camera.open(); //没有后置摄像头,尝试打开前置摄像头******************* if (mCamera == null) { Camera.CameraInfo mCameraInfo = new Camera.CameraInfo(); int cameraCount = Camera.getNumberOfCameras(); for (int camIdx = 0; camIdx < cameraCount; camIdx++) { Camera.getCameraInfo(camIdx, mCameraInfo); if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { mCamera = Camera.open(camIdx); } } } } catch (Exception e) { e.printStackTrace(); } return mCamera; }
释放照相机的方法
//释放照相机 private void releaseCamera() { if (mCamera != null) { IsPreview = false; mCamera.setPreviewCallback(null); mCamera.release(); mCamera = null; } }
相机反馈的方法,即扫描到二维码后的处理
PreviewCallback previewCb = new PreviewCallback() { public void onPreviewFrame(byte[] data, Camera camera) { Camera.Parameters parameters = camera.getParameters(); //获取扫描图片的大小 Size mSize = parameters.getPreviewSize(); //构造存储图片的Image Image mResult = new Image(mSize.width, mSize.height, "Y800");//第三个参数不知道是干嘛的 //设置Image的数据资源 mResult.setData(data); //获取扫描结果的代码 int mResultCode = mScanner.scanImage(mResult); //如果代码不为0,表示扫描成功 if (mResultCode != 0) { //停止扫描 IsPreview = false; mCamera.setPreviewCallback(null); mCamera.stopPreview(); //开始解析扫描图片 SymbolSet Syms = mScanner.getResults(); for (Symbol mSym : Syms) { //mSym.getType()方法可以获取扫描的类型,ZBar支持多种扫描类型,这里实现了条形码、二维码、ISBN码的识别 if (mSym.getType() == Symbol.CODE128 || mSym.getType() == Symbol.QRCODE || mSym.getType() == Symbol.CODABAR || mSym.getType() == Symbol.ISBN10 || mSym.getType() == Symbol.ISBN13|| mSym.getType()==Symbol.DATABAR || mSym.getType()==Symbol.DATABAR_EXP || mSym.getType()==Symbol.I25) { //添加震动效果,提示用户扫描完成 Vibrator mVibrator=(Vibrator)getSystemService(VIBRATOR_SERVICE); mVibrator.vibrate(400); Intent intent=new Intent(MainActivity.this,ResultActivity.class); intent.putExtra("ScanResult", "扫描类型:"+GetResultByCode(mSym.getType())+" "+ mSym.getData()); //这里需要注意的是,getData方法才是最终返回识别结果的方法 //但是这个方法是返回一个标识型的字符串,换言之,返回的值中包含每个字符串的含义 //例如N代表姓名,URL代表一个Web地址等等,其它的暂时不清楚,如果可以对这个进行一个较好的分割 //效果会更好,如果需要返回扫描的图片,可以对Image做一个合适的处理 startActivity(intent); IsScanned = true; } else { //否则继续扫描 IsScanned = false; mCamera.setPreviewCallback(previewCb); mCamera.startPreview(); IsPreview = true; mCamera.autoFocus(autoFocusCB); } } } } };
对于第二个问题,从上面的代码中我们可以看出,Image类用于获取二维码图片,ImageScanner类用于对图片的初步解析,而图片的最终解析是在SymbolSet类和
Symbol中去实现的,由此,第三个问题得以解答。下面给出完整代码:
/* * ZBar4Android * 作者:秦元培 * 时间:2013年12月21日 * 需要解决的问题有: * 1、返回内容的正则解析 * 2、如果锁屏后打开程序会报错 * 3、没有校正框,画不出来啊,郁闷 * 4、可能会与其它相机应用冲突,如微信 * 5、条形码还是读不出来 */ package com.Android.ZBar4Android; import com.Android.ZBar4Android.CameraPreview; import com.Android.ZBar4Android.R; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ActivityInfo; import android.os.Bundle; import android.os.Handler; import android.os.Vibrator; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.view.Window; import android.view.View.OnClickListener; import android.widget.FrameLayout; import android.widget.Button; import android.widget.PopupWindow; import android.hardware.Camera; import android.hardware.Camera.PreviewCallback; import android.hardware.Camera.AutoFocusCallback; import android.hardware.Camera.Size; import net.sourceforge.zbar.ImageScanner; import net.sourceforge.zbar.Image; import net.sourceforge.zbar.Symbol; import net.sourceforge.zbar.SymbolSet; import net.sourceforge.zbar.Config; public class MainActivity extends Activity { //关于按钮 private Button BtnAbout; //相机 private Camera mCamera; //预览视图 private CameraPreview mPreview; //自动聚焦 private Handler mAutoFocusHandler; //图片扫描器 private ImageScanner mScanner; //弹出窗口 private PopupWindow mPopupWindow; //是否扫描完毕 private boolean IsScanned = false; //是否处于预览状态 private boolean IsPreview = true; //是否显示弹出层 private boolean IsShowPopup=false; //加载iconvlib static { System.loadLibrary("iconv"); } public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //去除标题栏 requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.layout_main); //设置屏幕方向为竖屏 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); //自动聚焦线程 mAutoFocusHandler = new Handler(); //获取相机实例 mCamera = getCameraInstance(); if(mCamera == null) { //在这里写下获取相机失败的代码 AlertDialog.Builder mBuilder=new AlertDialog.Builder(this); mBuilder.setTitle("ZBar4Android"); mBuilder.setMessage("ZBar4Android获取相机失败,请重试!"); mBuilder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface mDialogInterface, int mIndex) { MainActivity.this.finish(); } }); AlertDialog mDialog=mBuilder.create(); mDialog.show(); } //实例化Scanner mScanner = new ImageScanner(); mScanner.setConfig(0, Config.X_DENSITY, 3); mScanner.setConfig(0, Config.Y_DENSITY, 3); //设置相机预览视图 mPreview = new CameraPreview(this, mCamera, previewCb, autoFocusCB); FrameLayout preview = (FrameLayout)findViewById(R.id.cameraPreview); preview.addView(mPreview); if (IsScanned) { IsScanned = false; mCamera.setPreviewCallback(previewCb); mCamera.startPreview(); IsPreview = true; mCamera.autoFocus(autoFocusCB); } //获取BtnAbout,显示程序信息 BtnAbout=(Button)findViewById(R.id.BtnAbout); BtnAbout.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //如果弹出层已打开,销毁弹出层 if(IsShowPopup) { mPopupWindow.dismiss(); IsShowPopup=false; } else { //否则显示弹出层 mPopupWindow=new PopupWindow(); LayoutInflater mInflater=LayoutInflater.from(getApplicationContext()); View view=mInflater.inflate(R.layout.layout_about, null); mPopupWindow.setContentView(view); mPopupWindow.setWidth(LayoutParams.WRAP_CONTENT); mPopupWindow.setHeight(LayoutParams.WRAP_CONTENT); mPopupWindow.showAtLocation(mPreview, 0, 100, 100); IsShowPopup=true; } } }); } //实现Pause方法 public void onPause() { super.onPause(); releaseCamera(); } //获取照相机的方法 public static Camera getCameraInstance() { Camera mCamera = null; try { mCamera = Camera.open(); //没有后置摄像头,尝试打开前置摄像头******************* if (mCamera == null) { Camera.CameraInfo mCameraInfo = new Camera.CameraInfo(); int cameraCount = Camera.getNumberOfCameras(); for (int camIdx = 0; camIdx < cameraCount; camIdx++) { Camera.getCameraInfo(camIdx, mCameraInfo); if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { mCamera = Camera.open(camIdx); } } } } catch (Exception e) { e.printStackTrace(); } return mCamera; } //释放照相机 private void releaseCamera() { if (mCamera != null) { IsPreview = false; mCamera.setPreviewCallback(null); mCamera.release(); mCamera = null; } } private Runnable doAutoFocus = new Runnable() { public void run() { if (IsPreview) mCamera.autoFocus(autoFocusCB); } }; PreviewCallback previewCb = new PreviewCallback() { public void onPreviewFrame(byte[] data, Camera camera) { Camera.Parameters parameters = camera.getParameters(); //获取扫描图片的大小 Size mSize = parameters.getPreviewSize(); //构造存储图片的Image Image mResult = new Image(mSize.width, mSize.height, "Y800");//第三个参数不知道是干嘛的 //设置Image的数据资源 mResult.setData(data); //获取扫描结果的代码 int mResultCode = mScanner.scanImage(mResult); //如果代码不为0,表示扫描成功 if (mResultCode != 0) { //停止扫描 IsPreview = false; mCamera.setPreviewCallback(null); mCamera.stopPreview(); //开始解析扫描图片 SymbolSet Syms = mScanner.getResults(); for (Symbol mSym : Syms) { //mSym.getType()方法可以获取扫描的类型,ZBar支持多种扫描类型,这里实现了条形码、二维码、ISBN码的识别 if (mSym.getType() == Symbol.CODE128 || mSym.getType() == Symbol.QRCODE || mSym.getType() == Symbol.CODABAR || mSym.getType() == Symbol.ISBN10 || mSym.getType() == Symbol.ISBN13|| mSym.getType()==Symbol.DATABAR || mSym.getType()==Symbol.DATABAR_EXP || mSym.getType()==Symbol.I25) { //添加震动效果,提示用户扫描完成 Vibrator mVibrator=(Vibrator)getSystemService(VIBRATOR_SERVICE); mVibrator.vibrate(400); Intent intent=new Intent(MainActivity.this,ResultActivity.class); intent.putExtra("ScanResult", "扫描类型:"+GetResultByCode(mSym.getType())+" "+ mSym.getData()); //这里需要注意的是,getData方法才是最终返回识别结果的方法 //但是这个方法是返回一个标识型的字符串,换言之,返回的值中包含每个字符串的含义 //例如N代表姓名,URL代表一个Web地址等等,其它的暂时不清楚,如果可以对这个进行一个较好的分割 //效果会更好,如果需要返回扫描的图片,可以对Image做一个合适的处理 startActivity(intent); IsScanned = true; } else { //否则继续扫描 IsScanned = false; mCamera.setPreviewCallback(previewCb); mCamera.startPreview(); IsPreview = true; mCamera.autoFocus(autoFocusCB); } } } } }; //用于刷新自动聚焦的方法 AutoFocusCallback autoFocusCB = new AutoFocusCallback() { public void onAutoFocus(boolean success, Camera camera) { mAutoFocusHandler.postDelayed(doAutoFocus, 1000); } }; //根据返回的代码值来返回相应的格式化数据 public String GetResultByCode(int CodeType) { String mResult=""; switch(CodeType) { //条形码 case Symbol.CODABAR: mResult="条形码"; break; //128编码格式二维码) case Symbol.CODE128: mResult="二维码"; break; //QR码二维码 case Symbol.QRCODE: mResult="二维码"; break; //ISBN10图书查询 case Symbol.ISBN10: mResult="图书ISBN号"; break; //ISBN13图书查询 case Symbol.ISBN13: mResult="图书ISBN号"; break; } return mResult; } } /* * ZBar4Android * 作者:秦元培 * 时间:2013年12月21日 * 需要解决的问题有: * 1、返回内容的正则解析 * 2、如果锁屏后打开程序会报错 * 3、没有校正框,画不出来啊,郁闷 * 4、可能会与其它相机应用冲突,如微信 * 5、条形码还是读不出来 */ package com.Android.ZBar4Android; import com.Android.ZBar4Android.CameraPreview; import com.Android.ZBar4Android.R; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ActivityInfo; import android.os.Bundle; import android.os.Handler; import android.os.Vibrator; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.view.Window; import android.view.View.OnClickListener; import android.widget.FrameLayout; import android.widget.Button; import android.widget.PopupWindow; import android.hardware.Camera; import android.hardware.Camera.PreviewCallback; import android.hardware.Camera.AutoFocusCallback; import android.hardware.Camera.Size; import net.sourceforge.zbar.ImageScanner; import net.sourceforge.zbar.Image; import net.sourceforge.zbar.Symbol; import net.sourceforge.zbar.SymbolSet; import net.sourceforge.zbar.Config; public class MainActivity extends Activity { //关于按钮 private Button BtnAbout; //相机 private Camera mCamera; //预览视图 private CameraPreview mPreview; //自动聚焦 private Handler mAutoFocusHandler; //图片扫描器 private ImageScanner mScanner; //弹出窗口 private PopupWindow mPopupWindow; //是否扫描完毕 private boolean IsScanned = false; //是否处于预览状态 private boolean IsPreview = true; //是否显示弹出层 private boolean IsShowPopup=false; //加载iconvlib static { System.loadLibrary("iconv"); } public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //去除标题栏 requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.layout_main); //设置屏幕方向为竖屏 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); //自动聚焦线程 mAutoFocusHandler = new Handler(); //获取相机实例 mCamera = getCameraInstance(); if(mCamera == null) { //在这里写下获取相机失败的代码 AlertDialog.Builder mBuilder=new AlertDialog.Builder(this); mBuilder.setTitle("ZBar4Android"); mBuilder.setMessage("ZBar4Android获取相机失败,请重试!"); mBuilder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface mDialogInterface, int mIndex) { MainActivity.this.finish(); } }); AlertDialog mDialog=mBuilder.create(); mDialog.show(); } //实例化Scanner mScanner = new ImageScanner(); mScanner.setConfig(0, Config.X_DENSITY, 3); mScanner.setConfig(0, Config.Y_DENSITY, 3); //设置相机预览视图 mPreview = new CameraPreview(this, mCamera, previewCb, autoFocusCB); FrameLayout preview = (FrameLayout)findViewById(R.id.cameraPreview); preview.addView(mPreview); if (IsScanned) { IsScanned = false; mCamera.setPreviewCallback(previewCb); mCamera.startPreview(); IsPreview = true; mCamera.autoFocus(autoFocusCB); } //获取BtnAbout,显示程序信息 BtnAbout=(Button)findViewById(R.id.BtnAbout); BtnAbout.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //如果弹出层已打开,销毁弹出层 if(IsShowPopup) { mPopupWindow.dismiss(); IsShowPopup=false; } else { //否则显示弹出层 mPopupWindow=new PopupWindow(); LayoutInflater mInflater=LayoutInflater.from(getApplicationContext()); View view=mInflater.inflate(R.layout.layout_about, null); mPopupWindow.setContentView(view); mPopupWindow.setWidth(LayoutParams.WRAP_CONTENT); mPopupWindow.setHeight(LayoutParams.WRAP_CONTENT); mPopupWindow.showAtLocation(mPreview, 0, 100, 100); IsShowPopup=true; } } }); } //实现Pause方法 public void onPause() { super.onPause(); releaseCamera(); } //获取照相机的方法 public static Camera getCameraInstance() { Camera mCamera = null; try { mCamera = Camera.open(); //没有后置摄像头,尝试打开前置摄像头******************* if (mCamera == null) { Camera.CameraInfo mCameraInfo = new Camera.CameraInfo(); int cameraCount = Camera.getNumberOfCameras(); for (int camIdx = 0; camIdx < cameraCount; camIdx++) { Camera.getCameraInfo(camIdx, mCameraInfo); if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { mCamera = Camera.open(camIdx); } } } } catch (Exception e) { e.printStackTrace(); } return mCamera; } //释放照相机 private void releaseCamera() { if (mCamera != null) { IsPreview = false; mCamera.setPreviewCallback(null); mCamera.release(); mCamera = null; } } private Runnable doAutoFocus = new Runnable() { public void run() { if (IsPreview) mCamera.autoFocus(autoFocusCB); } }; PreviewCallback previewCb = new PreviewCallback() { public void onPreviewFrame(byte[] data, Camera camera) { Camera.Parameters parameters = camera.getParameters(); //获取扫描图片的大小 Size mSize = parameters.getPreviewSize(); //构造存储图片的Image Image mResult = new Image(mSize.width, mSize.height, "Y800");//第三个参数不知道是干嘛的 //设置Image的数据资源 mResult.setData(data); //获取扫描结果的代码 int mResultCode = mScanner.scanImage(mResult); //如果代码不为0,表示扫描成功 if (mResultCode != 0) { //停止扫描 IsPreview = false; mCamera.setPreviewCallback(null); mCamera.stopPreview(); //开始解析扫描图片 SymbolSet Syms = mScanner.getResults(); for (Symbol mSym : Syms) { //mSym.getType()方法可以获取扫描的类型,ZBar支持多种扫描类型,这里实现了条形码、二维码、ISBN码的识别 if (mSym.getType() == Symbol.CODE128 || mSym.getType() == Symbol.QRCODE || mSym.getType() == Symbol.CODABAR || mSym.getType() == Symbol.ISBN10 || mSym.getType() == Symbol.ISBN13|| mSym.getType()==Symbol.DATABAR || mSym.getType()==Symbol.DATABAR_EXP || mSym.getType()==Symbol.I25) { //添加震动效果,提示用户扫描完成 Vibrator mVibrator=(Vibrator)getSystemService(VIBRATOR_SERVICE); mVibrator.vibrate(400); Intent intent=new Intent(MainActivity.this,ResultActivity.class); intent.putExtra("ScanResult", "扫描类型:"+GetResultByCode(mSym.getType())+" "+ mSym.getData()); //这里需要注意的是,getData方法才是最终返回识别结果的方法 //但是这个方法是返回一个标识型的字符串,换言之,返回的值中包含每个字符串的含义 //例如N代表姓名,URL代表一个Web地址等等,其它的暂时不清楚,如果可以对这个进行一个较好的分割 //效果会更好,如果需要返回扫描的图片,可以对Image做一个合适的处理 startActivity(intent); IsScanned = true; } else { //否则继续扫描 IsScanned = false; mCamera.setPreviewCallback(previewCb); mCamera.startPreview(); IsPreview = true; mCamera.autoFocus(autoFocusCB); } } } } }; //用于刷新自动聚焦的方法 AutoFocusCallback autoFocusCB = new AutoFocusCallback() { public void onAutoFocus(boolean success, Camera camera) { mAutoFocusHandler.postDelayed(doAutoFocus, 1000); } }; //根据返回的代码值来返回相应的格式化数据 public String GetResultByCode(int CodeType) { String mResult=""; switch(CodeType) { //条形码 case Symbol.CODABAR: mResult="条形码"; break; //128编码格式二维码) case Symbol.CODE128: mResult="二维码"; break; //QR码二维码 case Symbol.QRCODE: mResult="二维码"; break; //ISBN10图书查询 case Symbol.ISBN10: mResult="图书ISBN号"; break; //ISBN13图书查询 case Symbol.ISBN13: mResult="图书ISBN号"; break; } return mResult; } }
对于显示扫描结果的界面,代码比较简单
/* * 返回扫描结果 * 作者:秦元培 * 时间:2013年12月21日 * 总结:这里有一个问题,就是在这个界面上按下返回键的时候程序会立即报错,试着重写过相关的方法都解决不了问题 * 谁要是知道这个问题怎么解决,记得给我说一声啊 */ package com.Android.ZBar4Android; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.view.Window; import android.widget.Button; import android.widget.TextView; public class ResultActivity extends Activity { private TextView tv; private Button BtnBack; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.layout_result); //获取扫描结果 Intent intent=getIntent(); Bundle mData=intent.getExtras(); CharSequence mResult=mData.getCharSequence("ScanResult"); StringHelper mHelper=new StringHelper(mResult.toString()); mResult=mHelper.SplitFormDict(); tv=(TextView)findViewById(R.id.TextResult); tv.setText(mResult); //返回扫描界面 BtnBack=(Button)findViewById(R.id.BtnBack); BtnBack.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { Intent intent=new Intent(ResultActivity.this,MainActivity.class); startActivity(intent); } }); } @Override protected void onPause() { super.onPause(); } }
五、总结
经过测试,可以快速地对二维码进行识别,并显示扫描结果。目前尚存在的问题有:
1、官方的文档说它是支持条形码、ISBN、二维码等多种形式的编码的,并且在程序代码中亦有所体现,但是实际测试中,发现二维码可以扫,其余的无法扫描
2、锁屏后再次打开程序会报错
3、与微信等类似的需要相机功能的软件冲突
4、校准框死活画不出来
5、在扫描结果界面下按下返回键,程序报错,无法拦截
欢迎大家积极寻找解决问题的方法,再次谢谢大家!
源代码下载