Android之zxing二维码

人的活动如果没有理想的鼓舞,就会变得空虚而渺小。


本讲内容:二维码


一、zxing简介:
zxing是一个开放源码的,zxing可以实现使用手机的内置的摄像头完成条形码和二维码的扫描与解码。


二、Android上zxing的使用(二种方法):
1.将zxing的jar包放到工程的lib库中,然后将com.mining.app.zxing.camera,com.mining.app.zxing.decoding,com.mining.app.zxing.view这三个包拷贝到你的项目中
2.将已经弄好zxing的工程作为当前工程的依赖库,然后直接使用就可以了;



示例一:将已经弄好zxing的工程作为当前工程的依赖库

  

下面是res/layout/activity_main.xml 布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <Button
        android:id="@+id/id_b1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="扫一扫" />

</RelativeLayout>

下面是MainActivity.java主界面文件:

public class MainActivity extends Activity implements OnClickListener {

	private static final int PHOTO_PIC = 1;// 拍照

	private Button b1;

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		b1 = (Button) findViewById(R.id.id_b1);
		b1.setOnClickListener(this);
	}

	/**
	 * 由于我们是使用startActivityForResult()方法来启动某活动,
	 * 在某活动被销毁之后会回调上一个活动的onActivityResult()方法
	 * requestCode区分启动不同的活动,resultCode判断处理结果是否成功
	 */
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if (resultCode == RESULT_OK) {
			switch (requestCode) {
			case PHOTO_PIC:
				String result = data.getExtras().getString("result");
				Toast.makeText(MainActivity.this, "解析结果:" + result,Toast.LENGTH_LONG).show();
				break;
			}
		}

	}

	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.id_b1:
			// 跳转到拍照界面扫描二维码
			Intent intent = new Intent(MainActivity.this, CaptureActivity.class);
			startActivityForResult(intent, PHOTO_PIC);
			break;
		}
	}
}

manifest的配置部分,需要加入权限,和依赖库中的一个Activity的声明:

        <uses-permission android:name="android.permission.CAMERA" />  
	<uses-permission android:name="android.permission.VIBRATE" />  
	<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />  
	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
	<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> 

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name="com.zxing.activity.CaptureActivity"></activity>
    </application>


示例二:拷贝相关源码到你的项目中更改扫一扫界面

  

项目的结构


直接将com.mining.app.zxing.camera,com.mining.app.zxing.decoding,com.mining.app.zxing.view这三个包拷贝到你的项目中,还需要引用Zxing.jar资源包。


下面是res/layout/activity_title.xml 布局文件:

<?xml version="1.0" encoding="utf-8"?>  
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="wrap_content"  
    android:background="@drawable/mmtitle_bg_alpha" >  
  
    <Button  
        android:id="@+id/button_back"  
        android:layout_width="75dp"  
        android:layout_height="wrap_content"  
        android:layout_alignParentLeft="true"  
        android:background="@drawable/mm_title_back_btn"  
        android:text="返回"  
        android:textColor="@android:color/white" />  
  
    <TextView  
        android:id="@+id/textview_title"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_centerHorizontal="true"  
        android:layout_centerVertical="true"  
        android:gravity="center_vertical"  
        android:text="二维码扫描"  
        android:textColor="@android:color/white"  
        android:textSize="18sp" />  
  
    <ImageButton  
        android:id="@+id/button_function"  
        android:layout_width="75dp"  
        android:layout_height="wrap_content"  
        android:layout_alignParentRight="true"  
        android:layout_marginRight="2dip"  
        android:background="@drawable/mm_title_right_btn"  
        android:minWidth="70dip"  
        android:src="@drawable/mm_title_btn_menu_normal" />  
  
</RelativeLayout>  

下面是res/layout/activity_capture.xml 布局文件:(改写扫一扫界面)

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <SurfaceView
            android:id="@+id/preview_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerInParent="true" />

        <com.mining.app.zxing.view.ViewfinderView
            android:id="@+id/viewfinder_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <include
            android:id="@+id/include1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            layout="@layout/activity_title" />
    </RelativeLayout>

</FrameLayout>

下面是CaptureActivity.java扫一扫界面文件:(改写之前直接引入我项目的代码的,主要处理扫描界面的类

public class CaptureActivity extends Activity implements Callback,OnClickListener {

	private CaptureActivityHandler handler;
	private ViewfinderView viewfinderView;
	private boolean hasSurface;
	private Vector<BarcodeFormat> decodeFormats;
	private String characterSet;
	private InactivityTimer inactivityTimer;
	private MediaPlayer mediaPlayer;
	private boolean playBeep;
	private static final float BEEP_VOLUME = 0.10f;
	private boolean vibrate;
	
	private static final int REQUEST_CODE = 100;
	private static final int PARSE_BARCODE_SUC = 300;
	private static final int PARSE_BARCODE_FAIL = 303;
	private ProgressDialog mProgress;
	private String photo_path;
	private Bitmap scanBitmap;

	private Button mButtonBack;
	private ImageButton mImageButton;

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_capture);
		CameraManager.init(getApplication());
		viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);

		mButtonBack = (Button) findViewById(R.id.button_back);
		mButtonBack.setOnClickListener(this);
		hasSurface = false;
		inactivityTimer = new InactivityTimer(this);
		
		mImageButton=(ImageButton) findViewById(R.id.button_function);
		mImageButton.setOnClickListener(this);
	}

	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.button_back:
			CaptureActivity.this.finish();
			break;
		case R.id.button_function:
			//打开手机中的相册
			Intent innerIntent=new Intent(Intent.ACTION_GET_CONTENT);
			innerIntent.setType("image/*");//所有图片格式
			Intent wrapperIntent=Intent.createChooser(innerIntent, "选择二维码图片");
			this.startActivityForResult(wrapperIntent, REQUEST_CODE);
			break;
		}
	}
	
	private Handler mHandler = new Handler(){
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			
			mProgress.dismiss();
			switch (msg.what) {
			case PARSE_BARCODE_SUC:
				onResultHandler((String)msg.obj, scanBitmap);
				break;
			case PARSE_BARCODE_FAIL:
				Toast.makeText(CaptureActivity.this, (String)msg.obj, Toast.LENGTH_LONG).show();
				break;
			}
		}
	};
	
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if(resultCode == RESULT_OK){
			switch (requestCode) {
			case REQUEST_CODE:
				// 获取选中图片的路径
				String[] proj = new String[] { MediaStore.Images.Media.DATA };
				Cursor cursor = getContentResolver().query(data.getData(), proj, null, null, null);
				if (cursor.moveToFirst()) {
					int columnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
					// 获取到用户选择的二维码图片的绝对路径
					photo_path = cursor.getString(columnIndex);
				}
				cursor.close();
				
				mProgress = new ProgressDialog(CaptureActivity.this);
				mProgress.setMessage("正在扫描...");
				mProgress.setCancelable(false);
				mProgress.show();
				
				new Thread(new Runnable(){
					public void run() {
						Result result =parseBitmap(photo_path);
						if (result != null) {
							Message m = mHandler.obtainMessage();
							m.what = PARSE_BARCODE_SUC;
							m.obj = result.getText();
							mHandler.sendMessage(m);
						} else {
							Message m = mHandler.obtainMessage();
							m.what = PARSE_BARCODE_FAIL;
							m.obj = "Scan failed!";
							mHandler.sendMessage(m);
						}
					}
				}).start();
				break;
			}
		}
	}
	
	// 解析二维码图片,返回结果封装在Result对象中
		private Result parseBitmap(String path) {
			if (TextUtils.isEmpty(path)) {
				return null;
			}
			// 解析转换类型UTF-8
			Hashtable<DecodeHintType, String> hints = new Hashtable<DecodeHintType, String>();
			hints.put(DecodeHintType.CHARACTER_SET, "utf-8");
			// 获取到待解析的图片
			BitmapFactory.Options options = new BitmapFactory.Options();
			// 如果我们把inJustDecodeBounds设为true,那么BitmapFactory.decodeFile(String path,
			// Options opt)
			// 并不会真的返回一个Bitmap给你,它仅仅会把它的宽,高取回来给你
			options.inJustDecodeBounds = true;
			// 此时的bitmap是null,这段代码之后,options.outWidth 和 options.outHeight就是我们想要的宽和高了
			Bitmap bitmap = BitmapFactory.decodeFile(path, options);
			// 我们现在想取出来的图片的边长(二维码图片是正方形的)设置为400像素
			/**
			 * options.outHeight = 400; options.outWidth = 400;
			 * options.inJustDecodeBounds = false; bitmap =
			 * BitmapFactory.decodeFile(bitmapPath, options);
			 */
			// 以上这种做法,虽然把bitmap限定到了我们要的大小,但是并没有节约内存,如果要节约内存,我们还需要使用inSimpleSize这个属性
			options.inSampleSize = options.outHeight / 400;
			if (options.inSampleSize <= 0) {
				options.inSampleSize = 1; // 防止其值小于或等于0
			}
			/**
			 * 辅助节约内存设置
			 * 
			 * options.inPreferredConfig = Bitmap.Config.ARGB_4444; //
			 * 默认是Bitmap.Config.ARGB_8888 options.inPurgeable = true;
			 * options.inInputShareable = true;
			 */
			options.inJustDecodeBounds = false;
			bitmap = BitmapFactory.decodeFile(path, options);
			// 新建一个RGBLuminanceSource对象,将bitmap图片传给此对象
			RGBLuminanceSource rgbLuminanceSource = new RGBLuminanceSource(bitmap);
			// 将图片转换成二进制图片
			BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(
					rgbLuminanceSource));
			// 初始化解析对象
			QRCodeReader reader = new QRCodeReader();
			// 开始解析
			Result result = null;
			try {
				result = reader.decode(binaryBitmap, hints);
			} catch (Exception e) {
				e.printStackTrace();
			}
			return result;
		}

	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;
	}

	protected void onPause() {
		super.onPause();
		if (handler != null) {
			handler.quitSynchronously();
			handler = null;
		}
		CameraManager.get().closeDriver();
	}

	protected void onDestroy() {
		inactivityTimer.shutdown();
		super.onDestroy();
	}

	/**
	 * 处理扫描结果
	 * 
	 * @param surfaceHolder
	 */
	public void handleDecode(Result result, Bitmap barcode) {
		inactivityTimer.onActivity();
		playBeepSoundAndVibrate();
		String resultString = result.getText();
		onResultHandler(resultString, barcode);
	}
	
	/**
	 * 跳转到上一个页面
	 * @param surfaceHolder
	 */
	private void onResultHandler(String resultString, Bitmap bitmap){
		if(TextUtils.isEmpty(resultString)){
			Toast.makeText(CaptureActivity.this, "Scan failed!", Toast.LENGTH_SHORT).show();
			return;
		}
		Intent resultIntent = new Intent();
		Bundle bundle = new Bundle();
		bundle.putString("result", resultString);
		bundle.putParcelable("bitmap", bitmap);
		resultIntent.putExtras(bundle);
		this.setResult(RESULT_OK, resultIntent);
		CaptureActivity.this.finish();
	}

	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);
		}
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {

	}

	public void surfaceCreated(SurfaceHolder holder) {
		if (!hasSurface) {
			hasSurface = true;
			initCamera(holder);
		}
	}

	public void surfaceDestroyed(SurfaceHolder holder) {
		hasSurface = false;

	}

	public ViewfinderView getViewfinderView() {
		return viewfinderView;
	}

	public Handler getHandler() {
		return handler;
	}

	public void drawViewfinder() {
		viewfinderView.drawViewfinder();
	}

	private void initBeepSound() {
		if (playBeep && mediaPlayer == null) {
			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);
		}
	}

	private final OnCompletionListener beepListener = new OnCompletionListener() {
		public void onCompletion(MediaPlayer mediaPlayer) {
			mediaPlayer.seekTo(0);
		}
	};
}


下面是RGBLuminanceSource.java文件:(识别二维码图片

/**
 * 识别二维码图片
 */
public class RGBLuminanceSource extends LuminanceSource {  
    private final byte[] luminances;  
      
    public RGBLuminanceSource(Bitmap bitmap) {  
        super(bitmap.getWidth(), bitmap.getHeight());  
        //得到图片的宽高  
        int width = bitmap.getWidth();  
        int height = bitmap.getHeight();  
        //得到图片的像素  
        int[] pixels = new int[width * height];  
        bitmap.getPixels(pixels, 0, width, 0, 0, width, height);  
        //为了测量纯解码速度,我们将整个图像灰度阵列前面,这是一样的通道  
        // YUVLuminanceSource在现实应用。  
        //得到像素大小的字节数  
        luminances = new byte[width * height];  
        //得到图片每点像素颜色  
        for (int y = 0; y < height; y++) {  
            int offset = y * width;  
            for (int x = 0; x < width; x++) {  
                int pixel = pixels[offset + x];  
                int r = (pixel >> 16) & 0xff;  
                int g = (pixel >> 8) & 0xff;  
                int b = pixel & 0xff;  
                //当某一点三种颜色值相同时,相应字节对应空间赋值为其值  
                if (r == g && g == b) {  
                    luminances[offset + x] = (byte) r;  
                }   
                //其它情况字节空间对应赋值为:  
                else {    
                    luminances[offset + x] = (byte) ((r + g + g + b) >> 2);  
                }  
            }  
        }  
    }  
  
    public RGBLuminanceSource(String path) throws FileNotFoundException {  
        this(loadBitmap(path));  
    }  
      
    public byte[] getMatrix() {  
        return luminances;  
    }  
  
    public byte[] getRow(int arg0, byte[] arg1) {  
        if (arg0 < 0 || arg0 >= getHeight()) {  
            throw new IllegalArgumentException(  
                    "Requested row is outside the image: " + arg0);  
        }  
        int width = getWidth();  
        if (arg1 == null || arg1.length < width) {  
            arg1 = new byte[width];  
        }  
        System.arraycopy(luminances, arg0 * width, arg1, 0, width);  
        return arg1;  
    }  
  
    private static Bitmap loadBitmap(String path) throws FileNotFoundException {  
        Bitmap bitmap = BitmapFactory.decodeFile(path);  
        if (bitmap == null) {  
            throw new FileNotFoundException("Couldn't open " + path);  
        }  
        return bitmap;  
    }  
} 

下面是MainActivity.java主界面文件:

public class MainActivity extends Activity implements OnClickListener {

	private static final int PHOTO_PIC = 1;// 拍照

	private Button b1;
	/**
	 * 显示扫描结果
	 */
	private TextView mTextView;
	/**
	 * 显示扫描拍的图片
	 */
	private ImageView mImageView;
	private String photo_path;// 选择图片的绝对路径

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);
		b1 = (Button) findViewById(R.id.id_b1);
		b1.setOnClickListener(this);

		mTextView = (TextView) findViewById(R.id.id_result);
		mImageView = (ImageView) findViewById(R.id.id_qrcode_bitmap);
	}

	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.id_b1:
			// 跳转到拍照界面扫描二维码
			Intent intent = new Intent(MainActivity.this, CaptureActivity.class);
			startActivityForResult(intent, PHOTO_PIC);
			break;
		}
	}

	/**
	 * 由于我们是使用startActivityForResult()方法来启动某活动,
	 * 在某活动被销毁之后会回调上一个活动的onActivityResult()方法
	 * requestCode区分启动不同的活动,resultCode判断处理结果是否成功
	 */
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if (resultCode == RESULT_OK) {
			switch (requestCode) {
			case PHOTO_PIC:
				String result = data.getExtras().getString("result");
				mTextView.setText(result);
				mImageView.setImageBitmap((Bitmap) data.getParcelableExtra("bitmap"));
				break;
			}
		}
	}
}

manifest的配置部分(注意包名改变了)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.zxingdemo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="21" />
    
    <uses-permission android:name="android.permission.CAMERA" />  
	<uses-permission android:name="android.permission.VIBRATE" />  
	<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />  
	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
	<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> 

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name="com.<span style="color:#ff0000;">example.zxingdemo</span>.CaptureActivity"></activity>
    </application>

</manifest>



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 是一种操作系统,而 Google 的 ZXing 是一个开源的二维码扫描库。通过使用 ZXing 库,我们可以轻松地在 Android 应用程序中实现二维码扫描功能。 要在 Android 应用中使用 ZXing,首先需要在项目的 build.gradle 文件中添加以下依赖: ``` implementation 'com.google.zxing:core:3.3.3' implementation 'com.journeyapps:zxing-android-embedded:4.0.0' ``` 接下来,在布局文件中添加一个 SurfaceView 控件,用于显示相机预览画面。 然后,在 Activity 或 Fragment 中添加以下代码: ``` private IntentIntegrator integrator; @Override protected void onCreate(Bundle savedInstanceState) { // ... integrator = new IntentIntegrator(this); integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE); integrator.setPrompt("请将二维码放入扫描框中"); integrator.setCameraId(0); // 后置摄像头 integrator.setBeepEnabled(false); // 关闭扫描提示音 integrator.setBarcodeImageEnabled(false); // 保存扫描的图片 integrator.initiateScan(); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data); if (result != null) { if (result.getContents() == null) { // 用户取消了扫描 } else { String scanResult = result.getContents(); // 在这里处理扫描得到的二维码数据 } } } ``` 在上述代码中,通过 `IntentIntegrator` 类来发起扫描,并在 `onActivityResult` 方法中处理扫描结果。 以上是使用 ZXing 库实现 Android 中的二维码扫描的简要介绍。使用 ZXing 库可以方便地实现二维码扫描功能,并且还提供了许多其他定制选项和扩展功能,可以根据需要进行使用和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值