条码扫描二维码扫描——ZXing androi…
来源:互联网 发布:日吹神户制钢造假 知乎 编辑:程序博客网 时间:2024/05/01 12:15
前言
最近公司的Android项目需要用到摄像头做条码或二维码的扫描,Google一下,发现一个以ApacheLicense 2.0
前提条件
下载源代码:点击这里
编译核心库:Zxing的主页上有介绍具体步骤,大家也可以参照这篇博文:android条码识别软件开发全解析(续2详解绝杀!)
导入项目
打开Eclipse 导入 源码中的 Android 项目,然后右击项目 选择“Build path”——》"AddExternal Archives" 把核心库 core.jar文件加入到项目中。
此时编译一下项目,会发现报错,“
原因:由于新的SDK采用了新版本的aapt(Android项目编译器),这个版本的aapt编译起来会比老版本更加的严格,然后在Android最新的开发文档的描述String的部分,已经说明如何去设置%s 等符号
“If you need to format yourstrings using String.format(String, Object...) , then you can do soby putting your format arguments in the string resource. Forexample, with the following resource:
<stringname="welcome_messages">Hello, %1$s! You have %2$dnew messages.</string>
In this example, the formatstring has two arguments: %1$s is a string and %2$d is a decimalnumber. You can format the string with arguements from yourapplication...“
经过以上步骤后项目应该就可以运行了。
但是ZXing的android项目东西太多了,有很多是我们不需要的,得新建另一个项目简化它。
简化
在开始前大致介绍一下简化ZXing需要用到各个包 、类的职责。
- CaptureActivity。这个是启动Activity 也就是扫描器(如果是第一安装,它还会跳转到帮助界面)。
- CaptureActivityHandler 解码处理类,负责调用另外的线程进行解码。
- DecodeThread 解码的线程。
- com.google.zxing.client.android.camera 包,摄像头控制包。
- ViewfinderView 自定义的View,就是我们看见的拍摄时中间的框框了。
新建另一个项目
新建另一个项目将启动的Activity命名为CaptureActivity,并导入核心库。项目新建完成后我们打开CaptureActivity 的布局文件,我这里为main。把里面的XML修改为:
2 android:layout_width="fill_parent" android:layout_height="fill_parent">
3 <SurfaceView android:id="@+id/preview_view"
4android:layout_width="fill_parent"android:layout_height="fill_parent"
5android:layout_centerInParent="true"/>
6
7 <com.Zxing.Demo.view.ViewfinderView
8android:id="@+id/viewfinder_view" android:layout_width="fill_parent"
9android:layout_height="fill_parent" android:background="@android:color/transparent"/>
10 <TextView android:layout_width="wrap_content"
11 android:id="@+id/txtResult"
12 android:layout_height="wrap_content" android:text="@string/hello"/>
13
14
可以看到在XML里面用到了 ViewfinderView 自定义view 。所以新建一个View的包,然后把:ViewfinderView和
打开
2 publicvoid onCreate(Bundle savedInstanceState){
3 super.onCreate(savedInstanceState);
4setContentView(R.layout.main);
5 //初始化CameraManager
6
7
8 viewfinderView =(ViewfinderView) findViewById(R.id.viewfinder_view);
9 txtResult = (TextView)findViewById(R.id.txtResult);
10 hasSurface =false;
11 inactivityTimer=newInactivityTimer(this);
12 }
在修改的过程中,有很多是关于R 资源的问题,在此我们需要将Values
// if(prefs.getBoolean(PreferencesActivity.KEY_FRONT_LIGHT, false)){
// FlashlightManager.enableFlashlight();
//}
FlashlightManager.enableFlashlight();
<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-featureandroid:name="android.hardware.camera"/>
<uses-featureandroid:name="android.hardware.camera.autofocus"/>
<uses-permissionandroid:name="android.permission.VIBRATE"/>
<uses-permissionandroid:name="android.permission.FLASHLIGHT"/>
当View 和 camera 包里的错误修正完成后,我们继续来看CaptureActivity。
覆盖onResume方法初始化摄像头:
protectedvoid onResume() {
super.onResume();
SurfaceView surfaceView = (SurfaceView)findViewById(R.id.preview_view);
SurfaceHolder surfaceHolder = surfaceView.getHolder();
if (hasSurface) {
initCamera(surfaceHolder);
} else {
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
decodeFormats =null;
characterSet =null;
playBeep =true;
AudioManager audioService = (AudioManager)getSystemService(AUDIO_SERVICE);
if(audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL){
playBeep =false;
}
initBeepSound();
vibrate =true;
}
2 try {
3CameraManager.get().openDriver(surfaceHolder);
4 } catch (IOException ioe) {
5 return;
6 } catch (RuntimeException e) {
7 return;
8 }
9 if (handler ==null) {
10 handler =new CaptureActivityHandler(this, decodeFormats,
11 characterSet);
12 }
13 }
publicvoid surfaceChanged(SurfaceHolder holder,int format, int width,
int height) {
}
@Override
publicvoid surfaceCreated(SurfaceHolder holder){
if (!hasSurface) {
hasSurface =true;
initCamera(holder);
}
}
@Override
publicvoid surfaceDestroyed(SurfaceHolder holder){
hasSurface =false;
}
initCamera () 方法用于初始化摄像头,如果排除了所有的error,运行项目时就可以看到大致扫描界面了。
handler = new CaptureActivityHandler(this,decodeFormats,characterSet) 用于进行扫描解码处理。
解码
上面的步骤主要都是用于对摄像头的控制,而解码的真正工作入口是在CaptureActivityHandler里面的。新建一个Decoding包把以下文件拷入包中:
- CaptureActivityHandler
- DecodeFormatManager
- DecodeHandler
- DecodeThread
- FinishListener
- InactivityTimer
- Intents
由于我们的包结构和Zxing项目的有所不同所以需要注意一下类的可访问性
同样开始ctrl+B 编译一下,然后开始修正错误。
在CaptureActivityHandler 里 把
在DecodeThread 类里,修改部分涉及Preference配置的代码:
Vector<BarcodeFormat>decodeFormats,
String characterSet,
ResultPointCallback resultPointCallback) {
this.activity = activity;
handlerInitLatch =newCountDownLatch(1);
hints =newHashtable<DecodeHintType,Object>(3);
//// The prefscan't change while the thread is running, so pick them up oncehere.
//if (decodeFormats == null ||decodeFormats.isEmpty()) {
// SharedPreferences prefs =PreferenceManager.getDefaultSharedPreferen
//if(prefs.getBoolean(PreferencesActivity.KEY_DECODE_1D, true)){
// decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS);
// }
// if(prefs.getBoolean(PreferencesActivity.KEY_DECODE_QR, true)){
// decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);
// }
// if(prefs.getBoolean(PreferencesActivity.KEY_DECODE_DATA_MATRIX,true)) {
//decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);
// }
// }
if (decodeFormats ==null|| decodeFormats.isEmpty()) {
decodeFormats =newVector<BarcodeFormat>();
decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS);
decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);
decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);
}
hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);
if (characterSet !=null) {
hints.put(DecodeHintType.CHARACTER_SET, characterSet);
}
hints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK,resultPointCallback);
}
这里是设置 解码的类型,我们现在默认将所有类型都加入。
错误类型基本上都是:包结构、PreferencesActivity 的配置、类可访问性的问题。根据错误提示耐心把错误解决。
返回解码结果
inactivityTimer.onActivity();
viewfinderView.drawResultBitmap(barcode);
playBeepSoundAndVibrate();
txtResult.setText(obj.getBarcodeFormat().toString() +":"
+ obj.getText());
}
最后
ZXing的简化已基本完成,有几位是可以运行成功的?呵呵。
下面是CaptureActivity的源码:
private CaptureActivityHandlerhandler;
private ViewfinderViewviewfinderView;
privateboolean hasSurface;
privateVector<BarcodeFormat>decodeFormats;
private StringcharacterSet;
private TextViewtxtResult;
private InactivityTimerinactivityTimer;
private MediaPlayermediaPlayer;
privateboolean playBeep;
privatestaticfinalfloat BEEP_VOLUME =0.10f;
privateboolean vibrate;
@Override
publicvoid onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//初始化 CameraManager
CameraManager.init(getApplication());
viewfinderView = (ViewfinderView)findViewById(R.id.viewfinder_view);
txtResult = (TextView) findViewById(R.id.txtResult);
hasSurface =false;
inactivityTimer =newInactivityTimer(this);
}
@Override
protectedvoid onResume() {
super.onResume();
SurfaceView surfaceView = (SurfaceView)findViewById(R.id.preview_view);
SurfaceHolder surfaceHolder = surfaceView.getHolder();
if (hasSurface) {
initCamera(surfaceHolder);
} else {
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
decodeFormats =null;
characterSet =null;
playBeep =true;
AudioManager audioService = (AudioManager)getSystemService(AUDIO_SERVICE);
if(audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL){
playBeep =false;
}
initBeepSound();
vibrate =true;
}
@Override
protectedvoid onPause() {
super.onPause();
if (handler !=null) {
handler.quitSynchronously();
handler =null;
}
CameraManager.get().closeDriver();
}
@Override
protectedvoid onDestroy() {
inactivityTimer.shutdown();
super.onDestroy();
}
privatevoid initCamera(SurfaceHoldersurfaceHolder) {
try {
CameraManager.get().openDriver(surfaceHolder);
} catch (IOException ioe){
return;
} catch (RuntimeException e){
return;
}
if (handler ==null) {
handler =newCaptureActivityHandler(this,decodeFormats,
characterSet);
}
}
@Override
publicvoid surfaceChanged(SurfaceHolder holder,int format, int width,
int height) {
}
@Override
publicvoid surfaceCreated(SurfaceHolder holder){
if (!hasSurface) {
hasSurface =true;
initCamera(holder);
}
}
@Override
publicvoid surfaceDestroyed(SurfaceHolder holder){
hasSurface =false;
}
public ViewfinderViewgetViewfinderView() {
return viewfinderView;
}
public Handler getHandler(){
return handler;
}
publicvoid drawViewfinder() {
viewfinderView.drawViewfinder();
}
publicvoid handleDecode(Result obj, Bitmapbarcode) {
inactivityTimer.onActivity();
viewfinderView.drawResultBitmap(barcode);
playBeepSoundAndVibrate();
txtResult.setText(obj.getBarcodeFormat().toString() +":"
+ obj.getText());
}
privatevoid initBeepSound() {
if (playBeep&& mediaPlayer ==null) {
// The volume on STREAM_SYSTEM is not adjustable, andusers found it
//too loud,
// so we nowplay on the music stream.
setVolumeControlStream(AudioManager.STREAM_MUSIC);
mediaPlayer =newMediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setOnCompletionListener(beepListener);
AssetFileDescriptor file = getResources().openRawResourceFd(
R.raw.beep);
try {
mediaPlayer.setDataSource(file.getFileDescriptor(),
file.getStartOffset(), file.getLength());
file.close();
mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
mediaPlayer.prepare();
} catch (IOException e) {
mediaPlayer =null;
}
}
}
privatestaticfinallong VIBRATE_DURATION =200L;
privatevoid playBeepSoundAndVibrate() {
if (playBeep&& mediaPlayer !=null) {
mediaPlayer.start();
}
if (vibrate) {
Vibrator vibrator = (Vibrator)getSystemService(VIBRATOR_SERVICE);
vibrator.vibrate(VIBRATE_DURATION);
}
}
privatefinal OnCompletionListener beepListener=new OnCompletionListener(){
publicvoid onCompletion(MediaPlayer mediaPlayer){
mediaPlayer.seekTo(0);
}
};
简化过的包结构图:
简化后的ZXing 更加方便我们了解ZXing项目是如何解码的。只要仔细查看源码,进行单点跟踪调试,相信大家很容易能理解。
顾客是上帝
下面是我简化的版本:Zxing简化
很多人需要Core 核心包(其实ZXing的源码里面就有),这里提供下我写文章时的版本 1.6的:
Zxing
- 条码扫描二维码扫描——ZXing androi…
- 条码扫描二维码扫描——ZXing android 源码简化
- 条码扫描二维码扫描——ZXing android 源码简化
- 条码扫描二维码扫描——ZXing android 源码简化
- 条码扫描二维码扫描——ZXing android
- 条码扫描二维码扫描——ZXing android 源码简化
- android 条码扫描二维码扫描——ZXing 源码简化
- 条码扫描二维码扫描——ZXing android 源码简化
- 条码扫描二维码扫描——ZXing android 源码简化
- 条码扫描二维码扫描——ZXing android 源码简化
- 条码扫描二维码扫描——ZXing android 源码简化
- 条码扫描二维码扫描——ZXing android 源码简化
- 条码扫描二维码扫描——ZXing android 源码简化
- 条码扫描二维码扫描——ZXing android 源码简化
- 条码扫描二维码扫描——ZXing android 源码简化
- 条码扫描二维码扫描——ZXing android 源码简化
- 条码扫描二维码扫描——ZXing android 源码简化
- Android 条码扫描二维码扫描—ZXing android 改进版本
- 用Java写黑软-后门篇
- 突破防火墙——基于Http协议的Java隧…
- 利用netstat和tasklist查看PC的端…
- Tasklist、Taskkill与筛选器
- ByteArrayOutputStream的用…
- 条码扫描二维码扫描——ZXing androi…
- 二维码 整理 以及豆瓣读…
- 软件版本相关英文
- 6个可以隐藏运行bat,浏览器等程序…
- Java访问共享目录(samba和NFS配置…
- Net Use 命令用法
- Android手机中获取手机号码和运营…
- JAVA自动更新程序
- 命令运行的判断依据: ; , &…