Android移动开发-基于百度地图API与ZXing二维码开源库实现共享单车界面

前 言

2016年底以来,国内共享单车突然就火爆了起来,而在街头,仿佛一夜之间,共享单车已经到了“泛滥”的地步,各大城市路边排满各种颜色的共享单车。
通过一番梳理发现,除了较早入局的摩拜单车、ofo外,整个2016年至少有25个新品牌汹涌入局,其中甚至还包括电动自行车共享品牌。
——来自百度百科

那么,既然共享单车那么火,那它们的App页面是怎样实现的,本博客将简单的介绍基于百度地图API与ZXing二维码开源库实现共享单车界面。

开发环境

Android Studio 3.1.2
JDK 1.8

开发前准备

编码与实现

  • 共享单车主界面布局activity_main.xml文件代码如下:
<?xml version="1.0" encoding="utf-8"?>
<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"
    tools:context=".MainActivity">


    <com.baidu.mapapi.map.MapView
        android:id="@+id/id_bmapView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:clickable="true" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="2dp"
            android:orientation="horizontal">

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="50dp"
                android:gravity="center_vertical"
                android:orientation="horizontal">

                <ImageView
                    android:layout_width="48dp"
                    android:layout_height="48dp"
                    android:paddingLeft="10dp"
                    android:src="@drawable/icon_bike" />

                <TextView
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:gravity="center_vertical"
                    android:paddingLeft="3dp"
                    android:text="共享单车"
                    android:textColor="#FF4500"
                    android:textSize="20sp" />
            </LinearLayout>

            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:onClick="onPopupMenuClick"
                android:text="地图模式"
                android:textSize="16sp" />

        </RelativeLayout>

    </LinearLayout>

    <ImageButton
        android:id="@+id/id_bn_getMyLocation"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="60dp" />

    <Button
        android:id="@+id/sweep_QRcode"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="50dp"
        android:background="@mipmap/button_bg"
        android:textSize="20sp" />

</RelativeLayout>
  • 共享单车主界面逻辑MainActivity.java文件核心代码如下:
public class MainActivity extends Activity {

    private static final int BAIDU_READ_PHONE_STATE = 100;

    private MapView mMapView = null;
    private BaiduMap mBaiduMap;
    private LocationClient mlocationClient;
    private MylocationListener mlistener;
    private Context context;
    private Button mQRcode;

    private double mLatitude;
    private double mLongitude;
    private float mCurrentX;

    private ImageButton mGetMylocationBN;

    PopupMenu popup = null;

    //自定义图标
    private BitmapDescriptor mIconLocation;

    private MyOrientationListener myOrientationListener;
    //定位图层显示方式
    private MyLocationConfiguration.LocationMode locationMode;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SDKInitializer.initialize(getApplicationContext());
        setContentView(R.layout.activity_main);
        this.context = this;

        initView();
        //判断是否为Android 6.0 以上的系统版本,如果是,需要动态添加权限
        if (Build.VERSION.SDK_INT >= 23) {
            showContacts();
        } else {
            initLocation();//initLocation为定位方法
        }

    }

    private void initView() {
        mMapView = (MapView) findViewById(R.id.id_bmapView);

        mBaiduMap = mMapView.getMap();
        //根据给定增量缩放地图级别
        MapStatusUpdate msu = MapStatusUpdateFactory.zoomTo(18.0f);
        mBaiduMap.setMapStatus(msu);
        MapStatus mMapStatus;//地图当前状态
        MapStatusUpdate mMapStatusUpdate;//地图将要变化成的状态
        mMapStatus = new MapStatus.Builder().overlook(-45).build();
        mMapStatusUpdate = MapStatusUpdateFactory.newMapStatus(mMapStatus);
        mBaiduMap.setMapStatus(mMapStatusUpdate);
        mGetMylocationBN = (ImageButton) findViewById(R.id.id_bn_getMyLocation);
        mGetMylocationBN.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getMyLocation();
            }
        });

        mQRcode = (Button) findViewById(R.id.sweep_QRcode);
        mQRcode.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MainActivity.this, FindScanActivity.class);
                startActivity(intent);
            }
        });

    }

    /**
     * 定位方法
     */
    private void initLocation() {
        locationMode = MyLocationConfiguration.LocationMode.NORMAL;

        //定位服务的客户端。宿主程序在客户端声明此类,并调用,目前只支持在主线程中启动
        mlocationClient = new LocationClient(this);
        mlistener = new MylocationListener();

        //注册监听器
        mlocationClient.registerLocationListener(mlistener);
        //配置定位SDK各配置参数,比如定位模式、定位时间间隔、坐标系类型等
        LocationClientOption mOption = new LocationClientOption();
        //设置坐标类型
        mOption.setCoorType("bd09ll");
        //设置是否需要地址信息,默认为无地址
        mOption.setIsNeedAddress(true);
        //设置是否打开gps进行定位
        mOption.setOpenGps(true);
        //设置扫描间隔,单位是毫秒,当<1000(1s)时,定时定位无效
        int span = 1000;
        mOption.setScanSpan(span);
        //设置 LocationClientOption
        mlocationClient.setLocOption(mOption);

        //初始化图标,BitmapDescriptorFactory是bitmap 描述信息工厂类.
        mIconLocation = BitmapDescriptorFactory
                .fromResource(R.mipmap.icon_geo);

        myOrientationListener = new MyOrientationListener(context);
        //通过接口回调来实现实时方向的改变
        myOrientationListener.setOnOrientationListener(new MyOrientationListener.OnOrientationListener() {
            @Override
            public void onOrientationChanged(float x) {
                mCurrentX = x;
            }
        });

    }

    @Override
    protected void onStart() {
        super.onStart();
        //开启定位
        mBaiduMap.setMyLocationEnabled(true);
        if (!mlocationClient.isStarted()) {
            mlocationClient.start();
        }
        myOrientationListener.start();
    }

    @Override
    protected void onStop() {
        super.onStop();
        //停止定位
        mBaiduMap.setMyLocationEnabled(false);
        mlocationClient.stop();
        myOrientationListener.stop();
    }

    @Override
    protected void onResume() {
        super.onResume();
        mMapView.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mMapView.onPause();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mMapView.onDestroy();
    }

    public void getMyLocation() {
        LatLng latLng = new LatLng(mLatitude, mLongitude);
        MapStatusUpdate msu = MapStatusUpdateFactory.newLatLng(latLng);
        mBaiduMap.setMapStatus(msu);
    }

    public void onPopupMenuClick(View v) {
        // 创建PopupMenu对象
        popup = new PopupMenu(this, v);
        // 将R.menu.menu_main菜单资源加载到popup菜单中
        getMenuInflater().inflate(R.menu.menu_main, popup.getMenu());
        // 为popup菜单的菜单项单击事件绑定事件监听器
        popup.setOnMenuItemClickListener(
                new PopupMenu.OnMenuItemClickListener() {
                    @Override
                    public boolean onMenuItemClick(MenuItem item) {
                        switch (item.getItemId()) {
                            case R.id.id_map_common:
                                mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
                                break;
                            case R.id.id_map_site:
                                mBaiduMap.setMapType(BaiduMap.MAP_TYPE_SATELLITE);
                                break;
                            case R.id.id_map_traffic:
                                if (mBaiduMap.isTrafficEnabled()) {
                                    mBaiduMap.setTrafficEnabled(false);
                                    item.setTitle("实时交通(off)");
                                } else {
                                    mBaiduMap.setTrafficEnabled(true);
                                    item.setTitle("实时交通(on)");
                                }
                                break;
                            case R.id.id_map_mlocation:
                                getMyLocation();
                                break;
                            case R.id.id_map_model_common:
                                //普通模式
                                locationMode = MyLocationConfiguration.LocationMode.NORMAL;
                                break;
                            case R.id.id_map_model_following:
                                //跟随模式
                                locationMode = MyLocationConfiguration.LocationMode.FOLLOWING;
                                break;
                            case R.id.id_map_model_compass:
                                //罗盘模式
                                locationMode = MyLocationConfiguration.LocationMode.COMPASS;
                                break;
                        }
                        return true;
                    }
                });
        popup.show();
    }

    /**
     * 所有的定位信息都通过接口回调来实现
     */
    public class MylocationListener implements BDLocationListener {
        //定位请求回调接口
        private boolean isFirstIn = true;

        //定位请求回调函数,这里面会得到定位信息
        @Override
        public void onReceiveLocation(BDLocation bdLocation) {
            //BDLocation 回调的百度坐标类,内部封装了如经纬度、半径等属性信息
            //MyLocationData 定位数据,定位数据建造器
            /**
             * 可以通过BDLocation配置如下参数
             * 1.accuracy 定位精度
             * 2.latitude 百度纬度坐标
             * 3.longitude 百度经度坐标
             * 4.satellitesNum GPS定位时卫星数目 getSatelliteNumber() gps定位结果时,获取gps锁定用的卫星数
             * 5.speed GPS定位时速度 getSpeed()获取速度,仅gps定位结果时有速度信息,单位公里/小时,默认值0.0f
             * 6.direction GPS定位时方向角度
             * */
            mLatitude = bdLocation.getLatitude();
            mLongitude = bdLocation.getLongitude();
            MyLocationData data = new MyLocationData.Builder()
                    .direction(mCurrentX)//设定图标方向
                    .accuracy(bdLocation.getRadius())//getRadius 获取定位精度,默认值0.0f
                    .latitude(mLatitude)//百度纬度坐标
                    .longitude(mLongitude)//百度经度坐标
                    .build();
            //设置定位数据, 只有先允许定位图层后设置数据才会生效,参见 setMyLocationEnabled(boolean)
            mBaiduMap.setMyLocationData(data);
            //配置定位图层显示方式,三个参数的构造器
            /**
             * 1.定位图层显示模式
             * 2.是否允许显示方向信息
             * 3.用户自定义定位图标
             * */
            MyLocationConfiguration configuration
                    = new MyLocationConfiguration(locationMode, true, mIconLocation);
            //设置定位图层配置信息,只有先允许定位图层后设置定位图层配置信息才会生效,参见 setMyLocationEnabled(boolean)
            mBaiduMap.setMyLocationConfigeration(configuration);
            //判断是否为第一次定位,是的话需要定位到用户当前位置
            if (isFirstIn) {
                //地理坐标基本数据结构
                LatLng latLng = new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude());
                //描述地图状态将要发生的变化,通过当前经纬度来使地图显示到该位置
                MapStatusUpdate msu = MapStatusUpdateFactory.newLatLng(latLng);
                //改变地图状态
                mBaiduMap.setMapStatus(msu);
                isFirstIn = false;
                Utils.showToast2(context, "亲,您当前的位置为:" + bdLocation.getAddrStr());

                //定义Maker坐标点
                LatLng point = new LatLng(mLatitude + 0.00056, mLongitude);
                //构建Marker图标
                BitmapDescriptor bitmap = BitmapDescriptorFactory
                        .fromResource(R.drawable.car_small);
                //构建MarkerOption,用于在地图上添加Marker
                OverlayOptions option = new MarkerOptions()
                        .position(point)
                        .icon(bitmap);
                //在地图上添加Marker,并显示
                mBaiduMap.addOverlay(option);
                //定义Maker坐标点
                LatLng point1 = new LatLng(mLatitude, mLongitude + 0.0003);
                //构建Marker图标
                BitmapDescriptor bitmap1 = BitmapDescriptorFactory
                        .fromResource(R.drawable.car_small);
                //构建MarkerOption,用于在地图上添加Marker
                OverlayOptions option1 = new MarkerOptions()
                        .position(point1)
                        .icon(bitmap1);
                //在地图上添加Marker,并显示
                mBaiduMap.addOverlay(option1);
                //定义Maker坐标点
                LatLng point2 = new LatLng(mLatitude + 0.0005, mLongitude + 0.001);
                //构建Marker图标
                BitmapDescriptor bitmap2 = BitmapDescriptorFactory
                        .fromResource(R.drawable.car_small);
                //构建MarkerOption,用于在地图上添加Marker
                OverlayOptions option2 = new MarkerOptions()
                        .position(point2)
                        .icon(bitmap2);
                //在地图上添加Marker,并显示
                mBaiduMap.addOverlay(option2);
                //定义Maker坐标点
                LatLng point3 = new LatLng(mLatitude + 0.0003, mLongitude + 0.0001);
                //构建Marker图标
                BitmapDescriptor bitmap3 = BitmapDescriptorFactory
                        .fromResource(R.drawable.car_small);
                //构建MarkerOption,用于在地图上添加Marker
                OverlayOptions option3 = new MarkerOptions()
                        .position(point3)
                        .icon(bitmap3);
                //在地图上添加Marker,并显示
                mBaiduMap.addOverlay(option3);
                //定义Maker坐标点
                LatLng point4 = new LatLng(mLatitude + 0.0006, mLongitude);
                //构建Marker图标
                BitmapDescriptor bitmap4 = BitmapDescriptorFactory
                        .fromResource(R.drawable.car_small);
                //构建MarkerOption,用于在地图上添加Marker
                OverlayOptions option4 = new MarkerOptions()
                        .position(point4)
                        .icon(bitmap4);
                //在地图上添加Marker,并显示
                mBaiduMap.addOverlay(option4);
                //定义Maker坐标点
                LatLng point5 = new LatLng(mLatitude, mLongitude + 0.0004);
                //构建Marker图标
                BitmapDescriptor bitmap5 = BitmapDescriptorFactory
                        .fromResource(R.drawable.car_small);
                //构建MarkerOption,用于在地图上添加Marker
                OverlayOptions option5 = new MarkerOptions()
                        .position(point5)
                        .icon(bitmap5);
                //在地图上添加Marker,并显示
                mBaiduMap.addOverlay(option5);

                //定义Maker坐标点
                LatLng point6 = new LatLng(mLatitude, mLongitude - 0.0008);
                //构建Marker图标
                BitmapDescriptor bitmap6 = BitmapDescriptorFactory
                        .fromResource(R.drawable.car_small);
                //构建MarkerOption,用于在地图上添加Marker
                OverlayOptions option6 = new MarkerOptions()
                        .position(point6)
                        .icon(bitmap6);
                //在地图上添加Marker,并显示
                mBaiduMap.addOverlay(option1);
                //定义Maker坐标点
                LatLng point7 = new LatLng(mLatitude - 0.0005, mLongitude + 0.0004);
                //构建Marker图标
                BitmapDescriptor bitmap7 = BitmapDescriptorFactory
                        .fromResource(R.drawable.car_small);
                //构建MarkerOption,用于在地图上添加Marker
                OverlayOptions option7 = new MarkerOptions()
                        .position(point7)
                        .icon(bitmap7);
                //在地图上添加Marker,并显示
                mBaiduMap.addOverlay(option7);
                //定义Maker坐标点
                LatLng point8 = new LatLng(mLatitude - 0.0003, mLongitude - 0.0005);
                //构建Marker图标
                BitmapDescriptor bitmap8 = BitmapDescriptorFactory
                        .fromResource(R.drawable.car_small);
                //构建MarkerOption,用于在地图上添加Marker
                OverlayOptions option8 = new MarkerOptions()
                        .position(point8)
                        .icon(bitmap8);
                //在地图上添加Marker,并显示
                mBaiduMap.addOverlay(option8);
                //定义Maker坐标点
                LatLng point9 = new LatLng(mLatitude - 0.0003, mLongitude);
                //构建Marker图标
                BitmapDescriptor bitmap9 = BitmapDescriptorFactory
                        .fromResource(R.drawable.car_small);
                //构建MarkerOption,用于在地图上添加Marker
                OverlayOptions option9 = new MarkerOptions()
                        .position(point9)
                        .icon(bitmap9);
                //在地图上添加Marker,并显示
                mBaiduMap.addOverlay(option9);
                //定义Maker坐标点
                LatLng point10 = new LatLng(mLatitude, mLongitude - 0.0003);
                //构建Marker图标
                BitmapDescriptor bitmap10 = BitmapDescriptorFactory
                        .fromResource(R.drawable.car_small);
                //构建MarkerOption,用于在地图上添加Marker
                OverlayOptions option10 = new MarkerOptions()
                        .position(point10)
                        .icon(bitmap10);
                //在地图上添加Marker,并显示
                mBaiduMap.addOverlay(option10);
            }
        }
    }

    /**
     * Android 6.0 以上的版本的定位方法
     */
    public void showContacts() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
                != PackageManager.PERMISSION_GRANTED
                || ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED
                || ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE)
                != PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(getApplicationContext(), "没有权限,请手动开启定位权限", Toast.LENGTH_SHORT).show();
            // 申请一个(或多个)权限,并提供用于回调返回的获取码(用户定义)
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{
                    Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_PHONE_STATE
            }, BAIDU_READ_PHONE_STATE);
        } else {
            initLocation();
        }
    }

    //Android 6.0 以上的版本申请权限的回调方法
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            // requestCode即所声明的权限获取码,在checkSelfPermission时传入
            case BAIDU_READ_PHONE_STATE:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // 获取到权限,作相应处理(调用定位SDK应当确保相关权限均被授权,否则可能引起定位失败)
                    initLocation();
                } else {
                    // 没有获取到权限,做特殊处理
                    Toast.makeText(getApplicationContext(), "获取位置权限失败,请手动开启", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
                break;
        }
    }
}
  • 共享单车扫描界面activity_find_scan.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="match_parent">

    <SurfaceView
        android:id="@+id/sv_scan"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center" />

    <com.fukaimei.scanqrcodetest.zxing.view.ViewfinderView
        android:id="@+id/vv_finder"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:background="@drawable/bg_alpha"
        android:gravity="center"
        android:text="扫码开锁"
        android:textColor="#ffffffff"
        android:textSize="20sp" />

</RelativeLayout>
  • 共享单车扫描界面逻辑FindScanActivity.java文件核心代码如下:
public class FindScanActivity extends Activity implements SurfaceHolder.Callback {
    private final static String TAG = "FindScanActivity";
    private CaptureActivityHandler mHandler;
    private ViewfinderView vv_finder;
    private boolean hasSurface = false;
    private InactivityTimer mTimer;
    private MediaPlayer mPlayer;
    private boolean bBeep;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_find_scan);
        // 获取相机的动态权限
        cameraPermissions();
        CameraManager.init(getApplication(), CameraManager.QR_CODE);
        vv_finder = (ViewfinderView) findViewById(R.id.vv_finder);
        mTimer = new InactivityTimer(this);
    }

    // 定义获取相机的动态权限
    private void cameraPermissions() {
        if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{
                    android.Manifest.permission.CAMERA}, 1);
        }
    }

    /**
     * 重写onRequestPermissionsResult方法
     * 获取动态权限请求的结果,再开启相机扫码
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            CameraManager.init(getApplication(), CameraManager.QR_CODE);
        } else {
            Toast.makeText(this, "用户拒绝了权限", Toast.LENGTH_SHORT).show();
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    @Override
    protected void onResume() {
        super.onResume();
        SurfaceView sv_scan = (SurfaceView) findViewById(R.id.sv_scan);
        SurfaceHolder surfaceHolder = sv_scan.getHolder();
        if (hasSurface) {
            initCamera(surfaceHolder);
        } else {
            surfaceHolder.addCallback(this);
        }
        bBeep = true;
        AudioManager audioService = (AudioManager) getSystemService(AUDIO_SERVICE);
        if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) {
            bBeep = false;
        }
        initBeepSound();
    }

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

    @Override
    protected void onDestroy() {
        mTimer.shutdown();
        super.onDestroy();
    }

    public void handleDecode(Result result, Bitmap barcode) {
        mTimer.onActivity();
        beepAndVibrate();
        String resultString = result.getText();
        if (resultString == null || resultString.length() <= 0) {
            Toast.makeText(this, "Scan failed or result is null", Toast.LENGTH_SHORT).show();
        } else {
            String desc = String.format("barcode width=%d,height=%d",
                    barcode.getWidth(), barcode.getHeight());
//            Toast.makeText(this, desc, Toast.LENGTH_SHORT).show();
            Intent intent = new Intent(this, ScanResultActivity.class);
            intent.putExtra("result", resultString);
            startActivity(intent);
        }
    }

    private void initCamera(SurfaceHolder surfaceHolder) {
        try {
            CameraManager.get().openDriver(surfaceHolder);
            if (mHandler == null) {
                mHandler = new CaptureActivityHandler(this, null, null);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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

    public Handler getHandler() {
        return mHandler;
    }

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

    private void initBeepSound() {
        if (bBeep && mPlayer == null) {
            setVolumeControlStream(AudioManager.STREAM_MUSIC);
            mPlayer = new MediaPlayer();
            mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mPlayer.setOnCompletionListener(beepListener);
            AssetFileDescriptor file = getResources().openRawResourceFd(R.raw.beep);
            try {
                mPlayer.setDataSource(file.getFileDescriptor(),
                        file.getStartOffset(), file.getLength());
                file.close();
                mPlayer.setVolume(0.1f, 0.1f);
                mPlayer.prepare();
            } catch (IOException e) {
                e.printStackTrace();
                mPlayer = null;
            }
        }
    }

    private static final long VIBRATE_DURATION = 200L;

    private void beepAndVibrate() {
        if (bBeep && mPlayer != null) {
            mPlayer.start();
        }
        Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
        vibrator.vibrate(VIBRATE_DURATION);
    }

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

}

测试与运行截图

这里写图片描述 这里写图片描述 这里写图片描述 这里写图片描述

APK下载

apk Demo下载体验地址如下:
这里写图片描述


Demo程序源码下载地址一(GitHub)
Demo程序源码下载地址二(Gitee)

我发布的简书地址

猜你喜欢

转载自blog.csdn.net/fukaimei/article/details/80314575