android 二维码生成+扫描
1.在Android应用当中,很多时候都要用到二维码扫描,来避免让用户手动输入的麻烦。
Google官方自己推出了一个二维码开源项目:ZXing库.
2.这里简单介绍一下ZXing库:ZXing是一个开放源码的,用Java实现的多种格式的1D/2D条码图像处理库,它包含了联系到其他语言的端口。Zxing可以实现使用手机的内置的摄像头完成条形码的扫描及解码。
该项目可实现的条形码编码和解码。目前支持以下格式:UPC-A,UPC-E、EAN-8,EAN-13、39码、93码。ZXing是个很经典的条码/二维码识别的开源类库,以前在功能机上,就有开发者使用J2ME运用ZXing了,
不过要支持JSR-234规范(自动对焦)的手机才能发挥其威力。
3.官方demo运行后的效果是:
扫描后就直接进入到我的博客当中了。
4.ZXing库主要类:
- CaptureActivity。这个是启动Activity 也就是扫描器。
- CaptureActivityHandler 解码处理类,负责调用另外的线程进行解码。
- DecodeThread 解码的线程。
- com.google.zxing.client.android.camera 包,摄像头控制包。
- ViewfinderView 自定义的View,就是我们看见的拍摄时中间的框框了
5.二维码生成的方法:
1 //Edited by mythou 2 //http://www.cnblogs.com/mythou/ 3 //要转换的地址或字符串,可以是中文 4 public void createQRImage(String url) 5 { 6 try 7 { 8 //判断URL合法性 9 if (url == null || "".equals(url) || url.length() < 1) 10 { 11 return; 12 } 13 Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>(); 14 hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); 15 //图像数据转换,使用了矩阵转换 16 BitMatrix bitMatrix = new QRCodeWriter().encode(url, BarcodeFormat.QR_CODE, QR_WIDTH, QR_HEIGHT, hints); 17 int[] pixels = new int[QR_WIDTH * QR_HEIGHT]; 18 //下面这里按照二维码的算法,逐个生成二维码的图片, 19 //两个for循环是图片横列扫描的结果 20 for (int y = 0; y < QR_HEIGHT; y++) 21 { 22 for (int x = 0; x < QR_WIDTH; x++) 23 { 24 if (bitMatrix.get(x, y)) 25 { 26 pixels[y * QR_WIDTH + x] = 0xff000000; 27 } 28 else 29 { 30 pixels[y * QR_WIDTH + x] = 0xffffffff; 31 } 32 } 33 } 34 //生成二维码图片的格式,使用ARGB_8888 35 Bitmap bitmap = Bitmap.createBitmap(QR_WIDTH, QR_HEIGHT, Bitmap.Config.ARGB_8888); 36 bitmap.setPixels(pixels, 0, QR_WIDTH, 0, 0, QR_WIDTH, QR_HEIGHT); 37 //显示到一个ImageView上面 38 sweepIV.setImageBitmap(bitmap); 39 } 40 catch (WriterException e) 41 { 42 e.printStackTrace(); 43 } 44 }
6.扫描获取二维码信息的工作稍微复杂一些,主要是需要编写Camera的使用,这个跟我们 一般使用Camera一样,需要使用Surfaceview作为预览,这一部我这里就不说了,这个应该不是太复杂。对于使用过Camera做预览的朋友, 应该是挺简单的事情。获取二维码数据的关键处理是在Camera的自动对焦回调函数哪里,调用ZXing的解码接口。
1 //Edited by mythou 2 //http://www.cnblogs.com/mythou/ 3 private void restartPreviewAndDecode() { 4 if (state == State.SUCCESS) { 5 state = State.PREVIEW; 6 CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode); 7 CameraManager.get().requestAutoFocus(this, R.id.auto_focus); 8 activity.drawViewfinder(); 9 } 10 }
这里稍微多说一句,由于解码需要一定时间,所以ZXing的解码调用,都是使用了Handler作为线程通信机制,解码的工作都是放在独立线程里面使用的,如果你直接在主线程解码,恐怕ANR问题是避免不了。
1 //Edited by mythou 2 //http://www.cnblogs.com/mythou/ 3 public void handleMessage(Message message) { 4 switch (message.what) { 5 case R.id.auto_focus: 6 //Log.d(TAG, "Got auto-focus message"); 7 // When one auto focus pass finishes, start another. This is the closest thing to 8 // continuous AF. It does seem to hunt a bit, but I'm not sure what else to do. 9 if (state == State.PREVIEW) { 10 CameraManager.get().requestAutoFocus(this, R.id.auto_focus); 11 } 12 break; 13 case R.id.restart_preview: 14 Log.d(TAG, "Got restart preview message"); 15 restartPreviewAndDecode(); 16 break; 17 case R.id.decode_succeeded: 18 //解码成功,获取到界面的结果和原来的二维码数据 19 Log.d(TAG, "Got decode succeeded message"); 20 state = State.SUCCESS; 21 Bundle bundle = message.getData(); 22 Bitmap barcode = bundle == null ? null : 23 (Bitmap) bundle.getParcelable(DecodeThread.BARCODE_BITMAP); 24 activity.handleDecode((Result) message.obj, barcode); 25 break; 26 case R.id.decode_failed: 27 // We're decoding as fast as possible, so when one decode fails, start another. 28 state = State.PREVIEW; 29 CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode); 30 break; 31 case R.id.return_scan_result: 32 Log.d(TAG, "Got return scan result message"); 33 activity.setResult(Activity.RESULT_OK, (Intent) message.obj); 34 activity.finish(); 35 break; 36 case R.id.launch_product_query: 37 Log.d(TAG, "Got product query message"); 38 String url = (String) message.obj; 39 Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); 40 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 41 activity.startActivity(intent); 42 break; 43 } 44 }
7.上面是解码的线程处理不同状态的时候需要注意的地方,我们这里只看获取图像成功的地方, 成功获取图片解码的实在DecodeThread里面实现,DecodeThread里面解码成功后,会把数据序列化,然后保存到Bundle里面,我们 可以直接通过Bundle的序列化,获取到图片数据。同时会把解码后的结果保存到MSG里面,然后就可以根据实际情况进行处理,例如上面代码,解码成功 后,会调用一个处理函数:
1 //Edited by mythou 2 //http://www.cnblogs.com/mythou/ 3 public void handleDecode(final Result obj, Bitmap barcode) 4 { 5 inactivityTimer.onActivity(); 6 playBeepSoundAndVibrate(); 7 AlertDialog.Builder dialog = new AlertDialog.Builder(this); 8 if (barcode == null) 9 { 10 dialog.setIcon(null); 11 } 12 else 13 { 14 15 Drawable drawable = new BitmapDrawable(barcode); 16 dialog.setIcon(drawable); 17 } 18 dialog.setTitle("扫描结果"); 19 dialog.setMessage(obj.getText()); 20 dialog.setNegativeButton("确定", new DialogInterface.OnClickListener() 21 { 22 @Override 23 public void onClick(DialogInterface dialog, int which) 24 { 25 //用默认浏览器打开扫描得到的地址 26 Intent intent = new Intent(); 27 intent.setAction("android.intent.action.VIEW"); 28 Uri content_url = Uri.parse(obj.getText()); 29 intent.setData(content_url); 30 startActivity(intent); 31 finish(); 32 } 33 }); 34 dialog.setPositiveButton("取消", new DialogInterface.OnClickListener() 35 { 36 @Override 37 public void onClick(DialogInterface dialog, int which) 38 { 39 finish(); 40 } 41 }); 42 dialog.create().show(); 43 }
8.上面就是整个二维码的解码流程,里面因为涉及很多Camera的使用,所以你如果需要使用二维码识别,需要注意一下你的程序需要申请下面的权限,一般的Camera使用以及Camera的自动对焦等。
1 <uses-permission android:name="android.permission.CAMERA"></uses-permission> 2 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission> 3 <uses-feature android:name="android.hardware.camera" /> 4 <uses-feature android:name="android.hardware.camera.autofocus" />
Edited by 泡泡糖
ZXing开源项目Google Code地址:https://code.google.com/p/zxing/
Demo下载地址:http://pan.baidu.com/s/1hqBXPGw