亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

條碼掃描二維碼掃描——ZXing android 源碼簡化

系統 1832 0

前言

  最近公司的Android項目需要用到攝像頭做條碼或二維碼的掃描,Google一下,發現一個以 Apache License 2.0 ?開源的 ?ZXing 項目。Zxing項目里的Android實現太過復雜多余東西太多,得對其進行簡化。

前提條件

  下載源代碼:點擊 這里

  編譯核心庫:Zxing的主頁上有介紹具體步驟,大家也可以參照這篇博文: android 條碼識別軟件開發全解析(續2詳解絕殺!)

導入項目

  打開Eclipse 導入 源碼中的 Android 項目,然后右擊項目 選擇“Build path”——》"Add External Archives" 把核心庫 core.jar文件加入到項目中。

此時編譯一下項目,會發現報錯,“? Multiple substitutions specified in non-positional format; did you mean to add the formatted="false" attribute? ”之類的。打開raw 下的Values 發現錯誤是在一個<String>上。這里把 “ preferences_custom_product_search_summary ” 里的 ?%s ?%f ?全部都改成 ?%1$s ?%1$f(因為我們用不到多國語言,建議只保留默認的Value ,其他全部刪除)。

  原因:由于新的SDK采用了新版本的aapt(Android項目編譯器),這個版本的aapt編譯起來會比老版本更加的嚴格,然后在Android最新的開發文檔的描述String的部分,已經說明如何去設置 %s 等符號

“If you need to format your strings using String.format(String, Object...) , then you can do so by putting your format arguments in the string resource. For example, with the following resource:

  <string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>

  In this example, the format string has two arguments: %1$s is a string and %2$d is a decimal number. You can format the string with arguements from your application...“

  經過以上步驟后項目應該就可以運行了。

  但是ZXing的android項目東西太多了,有很多是我們不需要的,得新建另一個項目簡化它。

簡化

  在開始前大致介紹一下簡化ZXing需要用到各個包 、類的職責。

  • CaptureActivity。這個是啟動Activity 也就是掃描器(如果是第一安裝,它還會跳轉到幫助界面)。
  • CaptureActivityHandler 解碼處理類,負責調用另外的線程進行解碼。
  • DecodeThread 解碼的線程。
  • com.google.zxing.client.android.camera 包,攝像頭控制包。
  • ViewfinderView 自定義的View,就是我們看見的拍攝時中間的框框了。

新建另一個項目

  新建另一個項目將啟動的Activity命名為CaptureActivity,并導入核心庫。項目新建完成后我們打開 CaptureActivity 的布局文件,我這里為main。把里面的XML修改為:

        
1 < FrameLayout xmlns:android ="http://schemas.android.com/apk/res/android" 2 android:layout_width ="fill_parent" android:layout_height ="fill_parent" > 3 < SurfaceView android:id ="@+id/preview_view" 4 android:layout_width ="fill_parent" android:layout_height ="fill_parent" 5 android:layout_centerInParent ="true" /> 6 7 < com.Zxing.Demo.view.ViewfinderView 8 android:id ="@+id/viewfinder_view" android:layout_width ="fill_parent" 9 android: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 ? </ FrameLayout >

  可以看到在XML里面用到了 ViewfinderView 自定義view 。所以新建一個View 的包,然后把:ViewfinderView 和?ViewfinderResultPointCallback 靠到里面(記得對應修改XML里面的包)。

打開?CaptureActivity 覆蓋 onCreate 方法:

        
1 @Override 2 public void onCreate(Bundle savedInstanceState) { 3 super .onCreate(savedInstanceState); 4 setContentView(R.layout.main); 5 // 初始化 CameraManager 6 ? CameraManager.init(getApplication()); 7 8 viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view); 9 txtResult = (TextView) findViewById(R.id.txtResult); 10 hasSurface = false ; 11 inactivityTimer = new InactivityTimer( this ); 12 }

??這里調用到的 CameraManager 類是控制攝像頭的包里的類。新建一個camera包把:com.google.zxing.client.android.camera 里面的類全部拷入,另外我把PlanarYUVLuminanceSource也拷入到這個包里面。根據錯誤的提示來修正代碼,主要是修改正包結構。(整個簡化的流程都是如此:“ 根據錯誤提示,修改代碼 ”)。

條碼掃描二維碼掃描——ZXing android 源碼簡化

  在修改的過程中,有很多是關于R 資源的問題,在此我們需要將Values ?里面的兩個xml資源文件拷入項目中:colos.xml 和ids.xml 。 ctrl+b 一下看看error 是不是少了很多。在CameraManager中有些地方需要用到項目的配置,這里需要把配置直接寫入代碼中:

        
// SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); // 是否使用前燈 // if (prefs.getBoolean(PreferencesActivity.KEY_FRONT_LIGHT, false)) { // FlashlightManager.enableFlashlight(); // } FlashlightManager.enableFlashlight();

?  使用攝像頭需要加入相應的權限:

        
< uses - permission android:name = " android.permission.CAMERA " ></ uses - permission > < uses - permission android:name = " android.permission.WRITE_EXTERNAL_STORAGE " ></ uses - permission > < uses - feature android:name = " android.hardware.camera " /> < uses - feature android:name = " android.hardware.camera.autofocus " /> < uses - permission android:name = " android.permission.VIBRATE " /> < uses - permission android:name = " android.permission.FLASHLIGHT " />

  當View 和 camera 包里的錯誤修正完成后,我們繼續來看CaptureActivity。

覆蓋onResume方法初始化攝像頭:

        
@Override protected void 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 ; }
initCamera
          
1 private void initCamera(SurfaceHolder surfaceHolder) { 2 try { 3 CameraManager.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 }
SurfaceHolder接口實現
          
@Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { if ( ! hasSurface) { hasSurface = true ; initCamera(holder); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { hasSurface = false ; }

initCamera () 方法用于初始化攝像頭,如果排除了所有的error ,運行項目時就可以看到大致掃描界面了。? surfaceHolder.addCallback( this );表示讓CaptureActivity實現其callback接口。

handler = new CaptureActivityHandler(this, decodeFormats, characterSet) 用于進行掃描解碼處理。

解碼

  上面的步驟主要都是用于對攝像頭的控制,而解碼的真正工作入口是在CaptureActivityHandler 里面的。新建一個Decoding包把以下文件拷入包中:

  • CaptureActivityHandler
  • DecodeFormatManager
  • DecodeHandler
  • DecodeThread
  • FinishListener
  • InactivityTimer
  • Intents

由于我們的包結構和Zxing 項目的有所不同所以需要注意一下類的可訪問性

同樣開始ctrl+B 編譯一下,然后開始修正錯誤。

  在CaptureActivityHandler 里 把?handleMessage 里的部分方法先注釋掉如:“decode_succeeded ”分支,這是解碼成功時調用 CaptureActivity 展示解碼的結果。

在DecodeThread 類里,修改部分涉及Preference配置的代碼:

        
DecodeThread(CaptureActivity activity, Vector < BarcodeFormat > decodeFormats, String characterSet, ResultPointCallback resultPointCallback) { this .activity = activity; handlerInitLatch = new CountDownLatch( 1 ); hints = new Hashtable < DecodeHintType, Object > ( 3 ); // // The prefs can't change while the thread is running, so pick them up once here. // if (decodeFormats == null || decodeFormats.isEmpty()) { // SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity); // decodeFormats = new Vector<BarcodeFormat>(); // 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 = new Vector < 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 的配置 、類可訪問性的問題。根據錯誤提示耐心把錯誤解決。

返回解碼結果

?  還記得在?CaptureActivityHandler 的 messagehandler 里注銷掉的Case分支嗎?現在CaptureActivity 里實現它。

        
public void handleDecode(Result obj, Bitmap barcode) { inactivityTimer.onActivity(); viewfinderView.drawResultBitmap(barcode); playBeepSoundAndVibrate(); txtResult.setText(obj.getBarcodeFormat().toString() + " : " + obj.getText()); }

最后

  ZXing的簡化已基本完成,有幾位是可以運行成功的?呵呵。

下面是CaptureActivity的源碼:

CaputreActivity
          
public class CaptureActivity extends Activity implements Callback { private CaptureActivityHandler handler; private ViewfinderView viewfinderView; private boolean hasSurface; private Vector < BarcodeFormat > decodeFormats; private String characterSet; private TextView txtResult; private InactivityTimer inactivityTimer; private MediaPlayer mediaPlayer; private boolean playBeep; private static final float BEEP_VOLUME = 0.10f ; private boolean vibrate; /** Called when the activity is first created. */ @Override public void 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 = new InactivityTimer( this ); } @Override protected void 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 protected void onPause() { super .onPause(); if (handler != null ) { handler.quitSynchronously(); handler = null ; } CameraManager.get().closeDriver(); } @Override protected void onDestroy() { inactivityTimer.shutdown(); super .onDestroy(); } private void initCamera(SurfaceHolder surfaceHolder) { try { CameraManager.get().openDriver(surfaceHolder); } catch (IOException ioe) { return ; } catch (RuntimeException e) { return ; } if (handler == null ) { handler = new CaptureActivityHandler( this , decodeFormats, characterSet); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { if ( ! hasSurface) { hasSurface = true ; initCamera(holder); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { hasSurface = false ; } public ViewfinderView getViewfinderView() { return viewfinderView; } public Handler getHandler() { return handler; } public void drawViewfinder() { viewfinderView.drawViewfinder(); } public void handleDecode(Result obj, Bitmap barcode) { inactivityTimer.onActivity(); viewfinderView.drawResultBitmap(barcode); playBeepSoundAndVibrate(); txtResult.setText(obj.getBarcodeFormat().toString() + " : " + obj.getText()); } private void initBeepSound() { if (playBeep && mediaPlayer == null ) { // The volume on STREAM_SYSTEM is not adjustable, and users found it // too loud, // so we now play on the music stream. setVolumeControlStream(AudioManager.STREAM_MUSIC); mediaPlayer = new MediaPlayer(); 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 ; } } } private static final long VIBRATE_DURATION = 200L ; private void playBeepSoundAndVibrate() { if (playBeep && mediaPlayer != null ) { mediaPlayer.start(); } if (vibrate) { Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE); vibrator.vibrate(VIBRATE_DURATION); } } /** * When the beep has finished playing, rewind to queue up another one. */ private final OnCompletionListener beepListener = new OnCompletionListener() { public void onCompletion(MediaPlayer mediaPlayer) { mediaPlayer.seekTo( 0 ); } };

簡化過的包結構圖:

條碼掃描二維碼掃描——ZXing android 源碼簡化

 簡化后的ZXing 更加方便我們了解ZXing項目 是如何解碼的。只要仔細查看源碼,進行單點跟蹤調試,相信大家很容易能理解。

顧客是上帝

?? 很多人留言要源碼, 其實我這不是什么源碼,我只是把ZXing的東西簡化了一下而已。事實上我也不喜歡直接放源碼項目,這樣大家就不想讀ZXing的源碼了。

下面是我簡化的版本: Zxing簡化

<script type="text/javascript"></script>

條碼掃描二維碼掃描——ZXing android 源碼簡化


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 日本伦理中文字幕 | 久 在线播放 | 福利视频在线免费观看 | 久久综合九色综合97欧美 | 亚洲精品中文字幕乱码三区一二 | 免费在线激情视频 | 美女视频很黄很黄又免费的 | 成 人 免费 黄 色 视频 | 免费看国产精品久久久久 | 亚洲欧美国产五月天综合 | 四虎影片 | 日韩毛片最新看 | 日韩欧美亚洲国产 | 亚洲免费片 | 亚洲欧洲日韩国产一区二区三区 | 五月婷婷在线观看 | 日韩欧美中文字幕一区二区三区 | 国内精品久久久久久久97牛牛 | 四虎国产精品免费久久麻豆 | 亚洲天堂爱爱 | 日本国产成人精品视频 | 国产精品一二区 | 欧美一级艳片爽快片 | 九九99热久久精品在线6手机 | 婷婷激情在线 | 欧美毛片免费看 | 欧美末成年videos在线观看 | 欧美性大战久久久久久久蜜桃 | 亚洲精品美女久久777777 | 免费成人毛片 | 在线观看国产福利 | 国产精品视频免费看 | 狠狠干成人 | 99热这里只有精品9 99热这里只有精品99 | 亚洲视频一区二区 | 国产精品免费久久久久影院 | 色老头久久网 | 亚洲国产精品成人综合色在线婷婷 | 热久久国产精品 | 女人十八毛片免费特黄 | 欧美兽皇video |