博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android自由行之走进zxing,轻松实现二维码扫描
阅读量:5049 次
发布时间:2019-06-12

本文共 7771 字,大约阅读时间需要 25 分钟。

     现在很多App都集成了扫一扫功能,最常用的微信、QQ、手机助手等。二维码也使得生活变得更加简洁,扫一扫订餐、扫一扫下载等等。那么,说到二维码,我们不得不提Google一个开源的扫码框架:zxing。

     开源下载:http://code.google.com/p/zxing/

     zxing是基于多种1D/2D条码处理的开源库,是一个完整的项目。它可以通过手机摄像头实现条码的扫描以及解码,功能及其强大。那么如果要实现二维码的扫描以及解码,我们需要在该开源项目的基础上进行简化,并修改。让我们来看一下

二维码扫描结果      

    上图是仿照QQ的扫一扫进行修改的zxing项目,以zxing项目为基础,结合实际应用,这里作了三点改变:

   (1)竖屏扫描

   (2)自定义取景框

   (3)重新定义扫描结果处理

 

     一、第一步:下载zxing项目,并简化出扫描框架

     1、首先,下载最新zxing开源项目。 下载地址:http://code.google.com/p/zxing/

     2、分析项目结构,明确扫描框架需求。在zxing中,有很多其他的功能,项目结构比较复杂;针对二维码QRCode扫描,我们需要几个包:

        (1)com.google.zxing.client.android.Camera  基于Camera调用以及参数配置,核心包

        (2)DecodeFormatManager、DecodeThread、DecodeHandler 基于解码格式、解码线程、解码结果处理的解码类

        (3)ViewfinderView、ViewfinderResultPointCallBack 基于取景框视图定义的View类

        (4)CaptureActivity、CaptureActivityHandler 基于扫描Activity以及扫描结果处理的Capture类

        (5)InactivityTimer、BeepManager、FinishListener 基于休眠、声音、退出的辅助管理类

        (6)Intents、IntentSource、PrefrencesActivity 基于常量存储的常量类

    3、新建工程,添加如下权限:  

permission

        添加core.jar文件,并BuildPath;将上述类或包加入工程后,会报一系列错误,原因有几点:

       (1)资源文件缺乏,将zxing下需要的资源文件copy到新工程下

       (2)版本兼容问题,zxing下很多技术都是使用4.0版本及以上,集成到低版本之后,须做相应改动,详情参照项目源码

       (3)包结构引用问题,需要重新导入包引用

   4、简化CapyureActivity, camera包以及decode各类异常解决以后,即可对CaptureActivity进行代码简化 ,首先看一下capture.xml布局

1 
3 4
5
9 10
11
15 16
17
22 23
29 30
37 38
39 40
capture.xml

        capture.xml布局去掉结果显示,添加标题栏。那么captureActivity中,onCreate(),onPause(),onResume(),onDestroy涉及到Camera的初始化或销毁  

1 @Override 2     public void onCreate(Bundle icicle) { 3         super.onCreate(icicle); 4         // 保持Activity处于唤醒状态 5         Window window = getWindow(); 6         window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 7         setContentView(R.layout.capture); 8  9         hasSurface = false;10 11         inactivityTimer = new InactivityTimer(this);12         beepManager = new BeepManager(this);13 14         imageButton_back = (ImageButton) findViewById(R.id.capture_imageview_back);15         imageButton_back.setOnClickListener(new View.OnClickListener() {16 17             @Override18             public void onClick(View v) {19                 finish();20             }21         });22     }23 24     @Override25     protected void onResume() {26         super.onResume();27 28         // CameraManager必须在这里初始化,而不是在onCreate()中。29         // 这是必须的,因为当我们第一次进入时需要显示帮助页,我们并不想打开Camera,测量屏幕大小30         // 当扫描框的尺寸不正确时会出现bug31         cameraManager = new CameraManager(getApplication());32 33         viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);34         viewfinderView.setCameraManager(cameraManager);35 36         handler = null;37 38         SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);39         SurfaceHolder surfaceHolder = surfaceView.getHolder();40         if (hasSurface) {41             // activity在paused时但不会stopped,因此surface仍旧存在;42             // surfaceCreated()不会调用,因此在这里初始化camera43             initCamera(surfaceHolder);44         } else {45             // 重置callback,等待surfaceCreated()来初始化camera46             surfaceHolder.addCallback(this);47         }48 49         beepManager.updatePrefs();50         inactivityTimer.onResume();51 52         source = IntentSource.NONE;53         decodeFormats = null;54         characterSet = null;55     }56 57     @Override58     protected void onPause() {59         if (handler != null) {60             handler.quitSynchronously();61             handler = null;62         }63         inactivityTimer.onPause();64         beepManager.close();65         cameraManager.closeDriver();66         if (!hasSurface) {67             SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);68             SurfaceHolder surfaceHolder = surfaceView.getHolder();69             surfaceHolder.removeCallback(this);70         }71         super.onPause();72     }73 74     @Override75     protected void onDestroy() {76         inactivityTimer.shutdown();77         super.onDestroy();78     }
View Code

        surfaceview是基于Camera而实现,surfaceview的使用需要实现SurfaceHolder.Callback接口,在开启屏幕surfaceview的时候初始化camera

1 @Override 2     public void surfaceCreated(SurfaceHolder holder) { 3         if (!hasSurface) { 4             hasSurface = true; 5             initCamera(holder); 6         } 7     } 8  9     @Override10     public void surfaceDestroyed(SurfaceHolder holder) {11         hasSurface = false;12     }13 14     @Override15     public void surfaceChanged(SurfaceHolder holder, int format, int width,16             int height) {17 18     }
View Code

        接下来看如何初始化Camera,代码简化之后如下

1 private void initCamera(SurfaceHolder surfaceHolder) { 2         if (surfaceHolder == null) { 3             throw new IllegalStateException("No SurfaceHolder provided"); 4         } 5         if (cameraManager.isOpen()) { 6             return; 7         } 8         try { 9             // 打开Camera硬件设备10             cameraManager.openDriver(surfaceHolder);11             // 创建一个handler来打开预览,并抛出一个运行时异常12             if (handler == null) {13                 handler = new CaptureActivityHandler(this, decodeFormats,14                         decodeHints, characterSet, cameraManager);15             }16         } catch (IOException ioe) {17             Log.w(TAG, ioe);18             displayFrameworkBugMessageAndExit();19         } catch (RuntimeException e) {20             Log.w(TAG, "Unexpected error initializing camera", e);21             displayFrameworkBugMessageAndExit();22         }23     }
View Code

       在CaptureActivity中,有一个核心方法,用来返回并处理解码结果,也即扫描结果。handleDecode(),如果需要对解码后的内容进行自己的处理,需要对该方法进行改动,这里修改        为将解码的bitmap以及内容回传到开启扫描的Activiity进行处理。

1 public void handleDecode(Result rawResult, Bitmap barcode, float scaleFactor) { 2         inactivityTimer.onActivity(); 3  4         boolean fromLiveScan = barcode != null; 5         //这里处理解码完成后的结果,此处将参数回传到Activity处理 6         if (fromLiveScan) { 7             beepManager.playBeepSoundAndVibrate(); 8  9             Toast.makeText(this, "扫描成功", Toast.LENGTH_SHORT).show();10 11             Intent intent = getIntent();12             intent.putExtra("codedContent", rawResult.getText());13             intent.putExtra("codedBitmap", barcode);14             setResult(RESULT_OK, intent);15             finish();16         }17 18     }
View Code

   5、将指定Url生成二维码

1 /** 2      * 生成QRCode(二维码) 3      *  4      * @param str 5      * @return 6      * @throws WriterException 7      */ 8     public static Bitmap createQRCode(String url) throws WriterException { 9 10         if (url == null || url.equals("")) {11             return null;12         }13 14         // 生成二维矩阵,编码时指定大小,不要生成了图片以后再进行缩放,这样会模糊导致识别失败15         BitMatrix matrix = new MultiFormatWriter().encode(url,16                 BarcodeFormat.QR_CODE, 300, 300);17 18         int width = matrix.getWidth();19         int height = matrix.getHeight();20 21         // 二维矩阵转为一维像素数组,也就是一直横着排了22         int[] pixels = new int[width * height];23 24         for (int y = 0; y < height; y++) {25             for (int x = 0; x < width; x++) {26                 if (matrix.get(x, y)) {27                     pixels[y * width + x] = 0xff000000;28                 }29 30             }31         }32 33         Bitmap bitmap = Bitmap.createBitmap(width, height,34                 Bitmap.Config.ARGB_8888);35         bitmap.setPixels(pixels, 0, width, 0, 0, width, height);36         return bitmap;37     }
View Code

 

       通过以上四步,zxing项目的简化工作基本完成。至于一些类需要进行小修小改,希望可以对着源码进行,这里不再赘述。二维码扫描的整体构架主要包含三部分:

       1、定义取景框,也即扫描的View,通过surfaceview进行绘制

       2、Camera, 扫描的核心在于camera的配置使用,包括预览,自动聚焦,打开设备等处理

       3、Decode解码,扫描完成后整个工程的核心

       除去以上三个模块,需要明确的就是CaptureActivitiy中handleDeCode()方法做自己的处理。

       点击下面链接,即可下载源码

       http://pan.baidu.com/s/1c0yADUS 

转载于:https://www.cnblogs.com/exmyth/p/5142600.html

你可能感兴趣的文章
一步一步学MySQL-日志文件
查看>>
bzoj3994: [SDOI2015]约数个数和
查看>>
hdu5306 Gorgeous Sequence
查看>>
Android中使用ListView实现下拉刷新和上拉加载功能
查看>>
proc文件系统的简介
查看>>
连续自然数和
查看>>
[SDOI2015]星际战争
查看>>
用好lua+unity,让性能飞起来——luajit集成篇/平台相关篇
查看>>
JS控制页面跳转
查看>>
递归与循环的区别
查看>>
【USACO】Watering Hole 2008 Oct
查看>>
动态链接的步骤
查看>>
emacs 缩写词功能
查看>>
Api demo源码学习(2)--App/Activity/Custom Dialog --自定义Activity样式
查看>>
Velocity脚本简明教程
查看>>
虚拟机类加载机制
查看>>
RTSP流媒体数据传输的两种方式(TCP和UDP)
查看>>
大数n!
查看>>
TreeView控件使用总结
查看>>
PowerDesigner 生成的脚本取掉双引号
查看>>