Android 详解 LBS

1. LBS 的核心是什么?实现方式有?区别是?

答:

  • 核心:确定用户所在的位置,即定位
  • 实现方式:
    • GPS 定位:原理是基于手机内置的 GPS 硬件直接和卫星交互来获取当前的经纬度信息。
      • 优点:精度高。
      • 缺点:只能在室外使用,室内基本无法接收到卫星信号。
    • 网络定位:原理是根据手机当前网络附近的三个基站进行测速,以此计算出手机和每个基站之间的距离,再通过三角定位确定出一个大概的位置。
      • 优点:室内室外都可以使用。
      • 缺点:精度一般。

2. 【笔试题】手写一个使用百度地图 SDK 的 Demo?

答:

// 准备工作:申请 API Key、导入 SDK、声明权限等
// 实际开发时,肯定要参考官方文档
public class MainActivity extends AppCompatActivity {
    public LocationClient mLocationClient;
    private TextView positionText; // 显示定位信息,经纬度或者详细的地址信息

    private MapView mapView; // 百度提供的自定义控件,在页面显示百度地图
    private BaiduMap baiduMap; // 地图的总控制器
    private boolean isFirstLocate = true; // 防止多次调用 animateMapStatus() 方法,因为将地图移动到用户当前位置只需要在程序第一次定位的时候调用一次就可以了

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mLocationClient = new LocationClient(getApplicationContext());
        mLocationClient.registerLocationListener(new MyLocationListener());
        SDKInitializer.initialize(getApplicationContext()); // 参考百度地图 SDK 接入文档:初始化这行代码要在 setContentView() 方法前调用
        setContentView(R.layout.activity_main);
        mapView = (MapView) findViewById(R.id.bmapView);
        baiduMap = mapView.getMap();
        baiduMap.setMylocationEnabled(true); // 百度地图的限制,在地图上显示设备当前位置时需要调用这行代码开启这项功能
        positionText = (TextView) findViewById(R.id.position_text_view);
        List<String> permissionList = new ArrayList<> ();
        if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
        }
        if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
            permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
        }
        if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
        }
        if(!permissionList.isEmpty()) {
            String[] permissions = permissionList.toArray(new String[permissionList.size()]);
            ActivityCompat.requestPermissions(MainActivity.this, permission, 1);
        } else {
            requestLocation();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        mapView.onResume(); // 保证资源能够及时得到释放
    }

    @Override
    protected void onPause() {
        super.onPause();
        mapView.onPause(); // 保证资源能够及时得到释放
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mLocationClient.stop(); // 活动销毁时,调用 stop() 方法停止定位,否则会严重耗电
        mapView.onDestroy(); // 保证资源能够及时得到释放
        baiduMap.setMyLocationEnabled(false); // 程序退出时,关闭在地图上显示设备当前位置这一功能
    }

    private void navigateTo(BDLocation location) {
        if(isFirstLocate) {
            Latlng ll = new Latlng(location.getLatitude(), location.getLongtitude()); // Latlng 类并没有太多的用法,主要就是用于存放经纬度值的
            MapStatusUpdate update = MapStatusUpdateFactory.newLatlng(ll);
            baiduMap.animateMapStatus(update); // 移动到指定的经纬度
            // 百度地图将缩放级别的取值范围限定在 3 到 19 之间,其中小数点的值也是可以取的,值越大,地图显示的信息就越精细
            // 这里为了让地图信息可以显示得更加丰富一些,将缩放级别设置成了 16
            update = MapStatusUpdateFactory.zoomTo(16f);
            baiduMap.animateMapStatus(update); // 完成缩放功能
            isFirstLocate = false;
        }
        MyLocationData.Builder locationBuilder = new MyLocationData.Builder();
        locationBuilder.latitude(location.getLatitude());
        locationBuilder.longtitude(location.getLongtitude());
        MyLocationData locationData = locationBuilder.build();
        baiduMap.setMyLocationData(locationData); // 让设备当前位置显示在地图上
    }

    private void requestLocation() {
        initLocation();
        mLocationClient.start(); // 开始定位,默认情况下 start() 只会定位一次
    }

    private void initLocation() {
        LocationClientOption option = new LocationClientOption();
        option.setScanSpan(5000); // 设置实时更新的间隔为 5 秒
        option.setLocationMode(LocationClientOption.LocationMode.Device_Sensor); // 默认就是 GPS 定位,这里强制指定使用 GPS 进行定位。当然定位成功还需要用户在手机上手动打开 GPS 定位开关

        // 获取当前位置的详细信息,而不是几乎看不懂的经纬度
        // 需要注意的是,由于获取地址信息一定需要用到网络,因此即使将定位模式指定成了 Device_Sensors,也会自动开启网络定位功能
        option.setInNeedAddress(true);
        mLocationClient.setLocOption(option);
    }

    @Override
    public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case 1:
                if(grantResults.length > 0) {
                    for(int result : grantResults) {
                        if(result != PackageManager.PERMISSION_GRANTED) {
                            Toast.makeText(this, "必须同意所有权限才能使用本程序", Toast.LENGTH_SHORT).show();
                            finish();
                            return;
                        }
                    }
                    requestLocation();
                } else {
                    Toast.makeText(this, "发送未知错误", Toast.LENGTH_SHORT).show();
                    finish();
                }
                break;
            default:
                break;
        }
    }
}

public class MyLocationListener implements BDLocationListener {
    @Override
    public void onReceiveLocation(BDLocation location) {
        StringBuilder currentPosition = new StringBuilder();
        currentPosition.append("纬度:").append(location.getLatitude()).append("\n");
        currentPosition.append("经度:").append(location.getLongtitude()).append("\n");
        currentPosition.append("国家:").append(location.getCountry()).append("\n");
        currentPosition.append("省:").append(location.getProvince()).append("\n");
        currentPosition.append("市:").append(location.getCity()).append("\n");
        currentPosition.append("区:").append(location.getDistrict()).append("\n");
        currentPosition.append("街道:").append(location.getStreet()).append("\n");
        currentPosition.append("定位方式");
        if(location.getLocType() == BDLocation.TypeGpsLocation) {
            currentPosition.append("GPS 定位");
        } else if(location.getLocType() == BDLocation.TypeNetWorkLocation) {
            currentPosition.append("网络定位");
        }
        positionText.setText(currentPosition);

        if(location.getLocType() == BDLocation.TypeGpsLocation || location.getLocType() == BDLocation.TypeNetWorkLocation) {
            navigateTo(location);
        }
    }
}
-------------本文结束感谢您的阅读-------------