前言:上篇文章已经让源码运行起来了,但是还存在很多与扫描二维码无关的代码,本篇将删除无用的代码只保留与扫码有关的代码,同时分析解码的步骤。
精简代码
本篇文章的目标是分析出解码的步骤,为了不被无关的代码干扰,将会对源码进行精简,只保留与解码有关的代码。
主要删减的代码就是识别出二维码的内容后,一些其他的操作,如分享,记录扫描的历史,搜索解析结果等。删除之后的android
模块的结构如下
当然,这不是最终删减的版本,可能在分析源码的时候,发现无用的代码,会继续删除,最终的代码,我会在文末给出Github链接。
源码分析
为了方便理解及记忆ZXing
解码的步骤,我会边分析边画UML的序列图,最后,分析完解码的步骤,会有一个完整的序列图。现在,从主程序的入口开始分析,就是CaptureActivity
的onCreate
方法。
onCreate源码分析
代码如下
public void onCreate(Bundle icicle) { super.onCreate(icicle); //扫码的时候屏幕长亮 Window window = getWindow(); window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); setContentView(R.layout.capture); hasSurface = false; //控制activity在一段时间无操作自动finish inactivityTimer = new InactivityTimer(this); //管理扫码后是否有声音和震动 beepManager = new BeepManager(this); //用来根据环境的明暗,自动开启关闭闪光灯 ambientLightManager = new AmbientLightManager(this); //加载一些默认的配置 PreferenceManager.setDefaultValues(this, R.xml.preferences, false); }
这个方法,主要是用来实例化一些对象和获取配置信息,上面的代码中已经有注释,就不再细说。
onResume源码分析
下面继续看Activity
生命周期的第二个方法,代码如下
protected void onResume() { super.onResume(); // CameraManager must be initialized here, not in onCreate(). This is necessary because we don't // want to open the camera driver and measure the screen size if we're going to show the help on // first launch. That led to bugs where the scanning rectangle was the wrong size and partially // off screen. cameraManager = new CameraManager(getApplication());//1 viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view); viewfinderView.setCameraManager(cameraManager); resultView = findViewById(R.id.result_view); statusView = (TextView) findViewById(R.id.status_view); handler = null; //省略不重要代码 //..... SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view); SurfaceHolder surfaceHolder = surfaceView.getHolder();//2 if (hasSurface) { // The activity was paused but not stopped, so the surface still exists. Therefore // surfaceCreated() won't be called, so init the camera here. initCamera(surfaceHolder); } else { // Install the callback and wait for surfaceCreated() to init the camera. surfaceHolder.addCallback(this);//3 } }
上面代码中的一些语句标记了序号,现在来看序号“1”处的代码都做了什么,进入CameraManager
类的构造方法中,代码如下
public CameraManager(Context context) { this.context = context; this.configManager = new CameraConfigurationManager(context);//1.1 previewCallback = new PreviewCallback(configManager);//1.2 }
继续跟进代码,看下“1.1”处的代码,CameraConfigurationManager
构造方法中做了什么,代码如下
CameraConfigurationManager(Context context) { this.context = context; }
上面的代码就是注入了context
。现在看“1.2”处的代码,PreviewCallback
构造方法中做了什么,代码如下
PreviewCallback(CameraConfigurationManager configManager) { this.configManager = configManager; }
上面的这段代码可以看出,在PreviewCallback
构造方法中,将CameraConfigurationManager
类的实例,注入到了PreviewCallback
类中。跟完了“1”处的代码,继续往下看onResume
方法中的代码,这里介绍一下“2”处的代码,SurfaceHolder
的作用,介绍如下
SurfaceHolder是一个接口,其作用就像一个Surface的监听器。提供访问和控制SurfaceView背后的Surface 相关的方法 (providingaccess and control over this SurfaceView's underlying surface),它通过三个回调方法,让我们可以感知到Surface的创建、销毁或者改变。
继续往下看代码,因为在onCreate
方法中,hasSurface
值为false
,所以,会进入else
语句,也就是“3”处的代码,这句代码的作用就是绑定Surface
的监听器,就是在当前的Activity
中绑定Surface
生命周期的回调方法。SurfaceHolder.Callback
中定义了三个接口方法:
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height);
- 当surface发生任何结构性的变化时(格式或者大小),该方法就会被立即调用。
public void surfaceCreated(SurfaceHolder holder);
- 当surface对象创建后,该方法就会被立即调用。
public void surfaceDestroyed(SurfaceHolder holder);
- 当surface对象在将要销毁前,该方法会被立即调用。
知道了这三个方法在什么时候会调用,所以,这里绑定回调之后,会首先调用surfaceCreated
这个回调方法,看下这个方法中的代码,如下
public void surfaceCreated(SurfaceHolder holder) { if (holder == null) { Log.e(TAG, "*** WARNING *** surfaceCreated() gave us a null surface!"); } if (!hasSurface) { hasSurface = true; initCamera(holder); } }
继续跟进代码,看下initCamera(holder);
方法都做了什么,代码如下
private void initCamera(SurfaceHolder surfaceHolder) { if (surfaceHolder == null) { throw new IllegalStateException("No SurfaceHolder provided"); } //相机已经打开 if (cameraManager.isOpen()) { Log.w(TAG, "initCamera() while already open -- late SurfaceView callback?"); return; } try { //打开相机并初始化硬件参数 cameraManager.openDriver(surfaceHolder); // 实例化一个handler并开始预览. if (handler == null) { //3.1 handler = new CaptureActivityHandler(this, decodeFormats, decodeHints, characterSet, cameraManager); } decodeOrStoreSavedBitmap(null, null); } catch (IOException ioe) { Log.w(TAG, ioe); displayFrameworkBugMessageAndExit(); } catch (RuntimeException e) { // Barcode Scanner has seen crashes in the wild of this variety: // java.?lang.?RuntimeException: Fail to connect to camera service Log.w(TAG, "Unexpected error initializing camera", e); displayFrameworkBugMessageAndExit(); } }
“3.1”处的代码实例化了一个CaptureActivityHandler
,看下CaptureActivityHandler
的构造方法,代码如下
CaptureActivityHandler(CaptureActivity activity, Collection<BarcodeFormat> decodeFormats, Map<DecodeHintType,?> baseHints, String characterSet, CameraManager cameraManager) { this.activity = activity;//注入activity //新建一个线程并启动 //3.1.1 decodeThread = new DecodeThread(activity, decodeFormats, baseHints, characterSet, new ViewfinderResultPointCallback(activity.getViewfinderView())); decodeThread.start(); state = State.SUCCESS; // 注入cameraManager this.cameraManager = cameraManager; //要求相机硬件开始将预览帧绘制到屏幕上 cameraManager.startPreview(); //开始预览,并且解码 //3.1.2 restartPreviewAndDecode(); }