參考文章:http://www.cnblogs.com/keyindex/archive/2011/06/08/2074900.html
簡化
在開始前大緻介紹一下簡化ZXing需要用到各個包 、類的職責。
- CaptureActivity。這個是啟動Activity 也就是掃描器(如果是第一安裝,它還會跳轉到幫助界面)。
- CaptureActivityHandler 解碼處理類,負責調用另外的線程進行解碼。
- DecodeThread 解碼的線程。
- com.google.zxing.client.android.camera 包,攝像頭控制包。
- ViewfinderView 自定義的View,就是我們看見的拍攝時中間的框框了。
建立另一個項目
建立另一個項目将啟動的Activity命名為CaptureActivity,并導入核心庫。項目建立完成後我們打開 CaptureActivity 的布局檔案,我這裡為main。把裡面的XML修改為:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<SurfaceView android:id="@+id/preview_view"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:layout_centerInParent="true"/>
<com.Zxing.Demo.view.ViewfinderView
android:id="@+id/viewfinder_view" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:background="@android:color/transparent"/>
<TextView android:layout_width="wrap_content"
android:id="@+id/txtResult"
android:layout_height="wrap_content" android:text="@string/hello"/>
</FrameLayout>
可以看到在XML裡面用到了 ViewfinderView 自定義view 。是以建立一個View 的包,然後把:ViewfinderView 和 ViewfinderResultPointCallback 考到裡面(記得對應修改XML裡面的包)。
打開 CaptureActivity 覆寫 onCreate 方法:
@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);
}
這裡調用到的 CameraManager 類是控制攝像頭的包裡的類。建立一個camera包把:com.google.zxing.client.android.camera 裡面的類全部拷入,另外我把PlanarYUVLuminanceSource也拷入到這個包裡面。
在修改的過程中,有很多是關于R 資源的問題,在此我們需要将Values 裡面的兩個xml資源檔案拷入項目中:colos.xml 和ids.xml 。 ctrl+b 一下看看error 是不是少了很多。在CameraManager中有些地方需要用到項目的配置,這裡需要把配置直接寫入代碼中:
<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()方法的代碼
initCamera
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);
}
}
SurfaceHolder接口實作
@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;
}
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);
}
這裡是設定 解碼的類型,我們現在預設将所有類型都加入。
傳回解碼結果
還記得在 CaptureActivityHandler 的 messagehandler 裡登出掉的Case分支嗎?現在CaptureActivity 裡實作它。
錯誤類型基本上都是:包結構、PreferencesActivity 的配置 、類可通路性的問題。根據錯誤提示耐心把錯誤解決。
publicvoid handleDecode(Result obj, Bitmap barcode) {
inactivityTimer.onActivity();
viewfinderView.drawResultBitmap(barcode);
playBeepSoundAndVibrate();
txtResult.setText(obj.getBarcodeFormat().toString() +":"
+ obj.getText());
}
ZXing的簡化已基本完成,有幾位是可以運作成功的?呵呵。
下面是CaptureActivity的源碼:
CaputreActivity
publicclass CaptureActivity extends Activity implements Callback {
private CaptureActivityHandler handler;
private ViewfinderView viewfinderView;
privateboolean hasSurface;
private Vector<BarcodeFormat> decodeFormats;
private String characterSet;
private TextView txtResult;
private InactivityTimer inactivityTimer;
private MediaPlayer mediaPlayer;
privateboolean playBeep;
privatestaticfinalfloat BEEP_VOLUME =0.10f;
privateboolean vibrate;
/** Called when the activity is first created. */
@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 =new InactivityTimer(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(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
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 ViewfinderView getViewfinderView() {
return viewfinderView;
}
public Handler getHandler() {
return handler;
}
publicvoid drawViewfinder() {
viewfinderView.drawViewfinder();
}
publicvoid handleDecode(Result obj, Bitmap barcode) {
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, 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;
}
}
}
privatestaticfinallong VIBRATE_DURATION =200L;
privatevoid 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.
*/
privatefinal OnCompletionListener beepListener =new OnCompletionListener() {
publicvoid onCompletion(MediaPlayer mediaPlayer) {
mediaPlayer.seekTo(0);
}
};
源碼下載下傳:http://download.csdn.net/detail/kaka89757/5268842