利用百度地图提供的sdk实现定位功能(3) 调用本地app导航、根据经纬度获取两个点的直线距离

参考百度地图提供的开发指南:http://lbsyun.baidu.com/index.php?title=android-locsdk/guide/getloc

 

上面几个文件夹中的文件放的位置可参考:对地图的基本操作,标注地址,公交步行驾车路线搜索,附近搜索等(2)

这里openUtils文件夹放的是实现公交,步行,驾车,附近搜索路线查询等 需要的根据类,这里定位不需要用到

 

package com.workspace.my.baidumaptest;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.location.Poi;
import com.baidu.mapapi.SDKInitializer;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.BitmapDescriptor;
import com.baidu.mapapi.map.BitmapDescriptorFactory;
import com.baidu.mapapi.map.MapStatus;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.MarkerOptions;
import com.baidu.mapapi.map.OverlayOptions;
import com.baidu.mapapi.model.LatLng;

import java.util.List;

/**
 * 定位,在地图上显示
 */
public class MainActivity extends AppCompatActivity {

    private MapView mMapView;

    public LocationClient mLocationClient = null;
    public BDLocationListener myListener = new MyLocationListener();
    private BaiduMap mBaiduMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SDKInitializer.initialize(getApplicationContext());
        setContentView(R.layout.activity_main);
        //获取地图控件引用
        mMapView = (MapView) findViewById(R.id.bmapView);
        mBaiduMap = mMapView.getMap();

        mLocationClient = new LocationClient(getApplicationContext());  //声明LocationClient类
        mLocationClient.registerLocationListener(myListener);//定位的监听回调
        //配置定位SDK参数
        initLocation();
    }

    private void initLocation(){
        LocationClientOption option = new LocationClientOption();
        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy
        );//可选,默认高精度,设置定位模式,高精度,低功耗,仅设备
        option.setCoorType("bd09ll");//可选,默认gcj02,设置返回的定位结果坐标系
        int span=1000;//1秒定位一次
        option.setScanSpan(span);//可选,默认0,即仅定位一次,设置发起定位请求的间隔需要大于等于1000ms才是有效的
        option.setIsNeedAddress(true);//可选,设置是否需要地址信息,默认不需要
        option.setOpenGps(true);//可选,默认false,设置是否使用gps
        option.setLocationNotify(true);//可选,默认false,设置是否当gps有效时按照1S1次频率输出GPS结果
        option.setIsNeedLocationDescribe(true);//可选,默认false,设置是否需要位置语义化结果,可以在BDLocation.getLocationDescribe里得到,结果类似于“在北京天安门附近”
        option.setIsNeedLocationPoiList(true);//可选,默认false,设置是否需要POI结果,可以在BDLocation.getPoiList里得到
        option.setIgnoreKillProcess(false);//可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认不杀死
        option.SetIgnoreCacheException(false);//可选,默认false,设置是否收集CRASH信息,默认收集
        option.setEnableSimulateGps(false);//可选,默认false,设置是否需要过滤gps仿真结果,默认需要
        mLocationClient.setLocOption(option);
    }

    /**
     * 定位结果监听回调的方法
     */
    public class MyLocationListener implements BDLocationListener {

        @Override
        public void onReceiveLocation(BDLocation location) {
            //Receive Location
            StringBuffer sb = new StringBuffer(256);
            sb.append("time : ");
            sb.append(location.getTime());
            sb.append("\nerror code : ");
            sb.append(location.getLocType());
            sb.append("\nlatitude : ");
            sb.append(location.getLatitude());
            sb.append("\nlontitude : ");
            sb.append(location.getLongitude());
            sb.append("\nradius : ");
            sb.append(location.getRadius());
            if (location.getLocType() == BDLocation.TypeGpsLocation) {// GPS定位结果
                sb.append("\nspeed : ");
                sb.append(location.getSpeed());// 单位:公里每小时
                sb.append("\nsatellite : ");
                sb.append(location.getSatelliteNumber());
                sb.append("\nheight : ");
                sb.append(location.getAltitude());// 单位:米
                sb.append("\ndirection : ");
                sb.append(location.getDirection());// 单位度
                sb.append("\naddr : ");
                sb.append(location.getAddrStr());
                sb.append("\ndescribe : ");
                sb.append("gps定位成功");

            } else if (location.getLocType() == BDLocation.TypeNetWorkLocation) {// 网络定位结果
                sb.append("\naddr : ");
                sb.append(location.getAddrStr());
                //运营商信息
                sb.append("\noperationers : ");
                sb.append(location.getOperators());
                sb.append("\ndescribe : ");
                sb.append("网络定位成功");
            } else if (location.getLocType() == BDLocation.TypeOffLineLocation) {// 离线定位结果
                sb.append("\ndescribe : ");
                sb.append("离线定位成功,离线定位结果也是有效的");
            } else if (location.getLocType() == BDLocation.TypeServerError) {
                sb.append("\ndescribe : ");
                sb.append("服务端网络定位失败,可以反馈IMEI号和大体定位时间到loc-bugs@baidu.com,会有人追查原因");
            } else if (location.getLocType() == BDLocation.TypeNetWorkException) {
                sb.append("\ndescribe : ");
                sb.append("网络不同导致定位失败,请检查网络是否通畅");
            } else if (location.getLocType() == BDLocation.TypeCriteriaException) {
                sb.append("\ndescribe : ");
                sb.append("无法获取有效定位依据导致定位失败,一般是由于手机的原因,处于飞行模式下一般会造成这种结果,可以试着重启手机");
            }
            sb.append("\nlocationdescribe : ");
            sb.append(location.getLocationDescribe());// 位置语义化信息
            List<Poi> list = location.getPoiList();// POI数据
            if (list != null) {
                sb.append("\npoilist size = : ");
                sb.append(list.size());
                for (Poi p : list) {
                    sb.append("\npoi= : ");
                    sb.append(p.getId() + " " + p.getName() + " " + p.getRank());
                }
            }
            Log.i("BaiduLocationApiDem", sb.toString());
            //将地图显示到定位的地方
            MapStatus mapStatus = new MapStatus.Builder()
                    .target(new LatLng(location.getLatitude(),location.getLongitude()))
                    .build();
            mBaiduMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(mapStatus));
            //为这个地点增加标注
            //定义Maker坐标点
            LatLng point = new LatLng(location.getLatitude(), location.getLongitude());//纬度,经度
            //构建Marker图标
            BitmapDescriptor bitmap = BitmapDescriptorFactory.fromResource(R.drawable.icon_marka);
            //构建MarkerOption设置参数,用于在地图上添加Marker(标志)
            OverlayOptions option = new MarkerOptions()
                    .position(point)  //设置参数
                    .icon(bitmap);//设置图片
            //在地图上添加Marker(标注),并显示
            mBaiduMap.addOverlay(option);
            //可以在这里进行关闭定位
            mLocationClient.stop();
        }

    }

    /**
     * 单击事件,开始定位,如果不关闭,会一直刷新定位信息(在服务中执行的)
     * 开发者定位场景如果是单次定位的场景,在收到定位结果之后直接调用stop函数即可。
     * 如果stop之后仍然想进行定位,可以再次start等待定位结果回调即可。
     */
    public void onStartLocation(View view){
        mLocationClient.start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
        mMapView.onDestroy();
    }
    @Override
    protected void onResume() {
        super.onResume();
        //在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理
        mMapView.onResume();
    }
    @Override
    protected void onPause() {
        super.onPause();
        //在activity执行onPause时执行mMapView. onPause (),实现地图生命周期管理
        mMapView.onPause();
    }
}

布局文件:

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

    <Button
        android:id="@+id/btn_location"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="开始定位"
        android:onClick="onStartLocation"
        />
    <com.baidu.mapapi.map.MapView
        android:id="@+id/bmapView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:clickable="true" />

</LinearLayout>

清单注册文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.workspace.my.baidumaptest" >

    <!--定位加显示百度地图需要的权限-->
    <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.GET_TASKS" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />

    <!-- 这个权限用于进行网络定位-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
    <!-- 这个权限用于访问GPS定位-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
    <!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位-->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
    <!-- 获取运营商信息,用于支持提供运营商信息相关的接口-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
    <!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
    <!-- 用于读取手机当前的状态-->
    <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
    <!-- 写入扩展存储,向扩展卡写入数据,用于写入离线定位数据-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
    <!-- 访问网络,网络定位需要上网-->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- SD卡读取权限,用户写入离线定位数据-->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"></uses-permission>

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

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    <!--定位需要的服务(百度sdk中要求的)-->
        <service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote">
        </service>

        <!--申请的秘钥-->
        <meta-data
            android:name="com.baidu.lbsapi.API_KEY"
            android:value="Gy5HsOUWn0M77QMNC46CYwvmxHHWvMIv" />
    </application>

</manifest>

 效果图:

检测是否打开了GPS,并去设置:

private void initGPS() {
        LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
        // 判断GPS模块是否开启,如果没有则开启
        if (!locationManager
                .isProviderEnabled(android.location.LocationManager.GPS_PROVIDER)) {
            
             AlertDialog dialog = new AlertDialog.Builder(MainActivity.this)
                 .setTitle("提示对话框").setMessage("没有打开GPS,可能导致定位失败或定位不准")
                .setPositiveButton("登录", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // 转到手机设置界面,用户设置GPS
                        Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                        startActivityForResult(intent, 0); // 设置完成后返回到原来的界面
                        //在manifest文件中将Activity的launchMode设置为了singleTask,获取的结果码会一直为0
                    }

                }).setNegativeButton("退出", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        
                    }
                }).create();
            dialog.show();
        } 
    }
    
    @Override
    protected void onActivityResult(int arg0, int arg1, Intent arg2) {
        super.onActivityResult(arg0, arg1, arg2);
        LocationManager locManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
        if(locManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
            //开启了
            mLocationClient.start();
        }
    }

有时候需要手动去执行定位(比如,点击一个按钮去执行定位):

activity.mLocationClient.requestLocation();//去定位,如果stop了先start就行

文档是这么说的:

start:启动定位SDK。 stop:关闭定位SDK。调用start之后只需要等待定位结果自动回调即可。

开发者定位场景如果是单次定位的场景,在收到定位结果之后直接调用stop函数即可。

如果stop之后仍然想进行定位,可以再次start等待定位结果回调即可。

如果开发者想按照自己逻辑请求定位,可以在start之后按照自己的逻辑请求locationclient.requestLocation()函数,会主动触发定位SDK内部定位逻辑,等待定位回调即可。

 

调用本地地图实现导航:

百度地图:http://lbsyun.baidu.com/index.php?title=uri/api/android

高德地图:http://lbs.amap.com/api/uri-api/android-uri-explain/

腾讯地图:http://lbs.qq.com/uri_v1/index.html

谷歌地图:https://developers.google.com/maps/documentation/android-api/intents

代码如下:

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.util.Log;
import android.widget.Toast;

import java.io.File;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

/**
 * 调用本地百度地图 或者 高德地图 导航
 */

public class MapUtil {

    /* 获取安装的所有软件,并且判断是否安装了指定的软件
     * @param context
     * @param packageName:应用包名
     * @return
     */
    public static boolean isAvilible(Context context, String packageName){
        //获取packagemanager
        final PackageManager packageManager = context.getPackageManager();
        //获取所有已安装程序的包信息
        List<PackageInfo> packageInfos = packageManager.getInstalledPackages(0);
        //用于存储所有已安装程序的包名
        List<String> packageNames = new ArrayList<String>();
        //从pinfo中将包名字逐一取出,压入pName list中
        if(packageInfos != null){
            for(int i = 0; i < packageInfos.size(); i++){
                String packName = packageInfos.get(i).packageName;
                packageNames.add(packName);
            }
        }
        //判断packageNames中是否有目标程序的包名,有TRUE,没有FALSE
        return packageNames.contains(packageName);
    }

    /**
     * 判断是否安装目标应用
     * @param packageName 目标应用安装后的包名
     * @return 是否已安装目标应用
     */
    private boolean isInstallByread(String packageName) {
        return new File("/data/data/" + packageName).exists();
    }

    /**
     * 调用百度地图导航  设置起点 与 终点
     */
    public static void toBaiDuMap(Context context, String startLat, String startLong, String endLat, String endLong){
        Intent intent;
        if(isAvilible(context,"com.baidu.BaiduMap")){//传入指定应用包名
            try {
//intent = Intent.getIntent("intent://map/direction?origin=latlng:34.264642646862,108.95108518068|name:我家&destination=大雁塔&mode=driving®ion=西安&src=yourCompanyName|yourAppName#Intent;scheme=bdapp;package=com.baidu.BaiduMap;end");
                intent = Intent.getIntent("intent://map/direction?" +
                        "origin=latlng:"+startLat + "," + startLong + "|name:起点啊" +
                        "&destination=latlng:"+endLat+","+endLong+"|name:我的目的地"+  //终点
                        "&mode=driving&" +          //导航路线方式  driving=驾车
                        //"region=杭州&" +           //范围
                        "src=事亲健康#Intent;scheme=bdapp;package=com.baidu.BaiduMap;end");
                context.startActivity(intent); //启动调用
            } catch (URISyntaxException e) {
                Log.e("intent", e.getMessage());
            }
        }else{//未安装
            //market为路径,id为包名
            //显示手机上所有的market商店
            Toast.makeText(context, "您尚未安装百度地图", Toast.LENGTH_LONG).show();
            Uri uri = Uri.parse("market://details?id=com.baidu.BaiduMap");
            intent = new Intent(Intent.ACTION_VIEW, uri);
            context.startActivity(intent);
        }
    }

    /**
     * 调用百度地图导航, 当前位置到目标位置
     */
    public static void toBaiDuMap(Context context,String endLat, String endLong){
        Intent intent;
        if(isAvilible(context,"com.baidu.BaiduMap")){//传入指定应用包名
            try {
                intent = Intent.getIntent("intent://map/direction?" +
                        //"origin=latlng:"+"34.264642646862,108.95108518068&" +   //起点  此处不传值默认选择当前位置
                        "destination=latlng:"+endLat+","+endLong+"|name:我的目的地"+        //终点显示的名称= “我的目的地”
                        "&mode=driving&" +          //导航路线方式
                        //"region=杭州&" +           //
                        "src=事亲健康#Intent;scheme=bdapp;package=com.baidu.BaiduMap;end");
                context.startActivity(intent); //启动调用
            } catch (URISyntaxException e) {
                Log.e("intent", e.getMessage());
            }
        }else{//未安装
            //market为路径,id为包名
            //显示手机上所有的market商店
            Toast.makeText(context, "您尚未安装百度地图", Toast.LENGTH_LONG).show();
            Uri uri = Uri.parse("market://details?id=com.baidu.BaiduMap");
            intent = new Intent(Intent.ACTION_VIEW, uri);
            context.startActivity(intent);
        }
    }

    /**
     * 高德地图
     * @param context
     * @param sname  开始位置   在地图上显示的名称
     * @param dname  终点位置   在地图上显示的名称
     */
    public static void toGaoDeMap(Context context, String startLat, String startLong, String endLat, String endLong,String sname,String dname){
        Intent intent;
        if (isAvilible(context, "com.autonavi.minimap")) {
            try{
                String url = "androidamap://route?sourceApplication=amap&slat="+startLat+"&slon="+startLong + "&sname=" + sname
                        +"&dlat="+endLat+"&dlon="+endLong+"&dname="+ dname +"&dev=0&t=1";
                Uri uri = Uri.parse(url);
                intent = new Intent();
                intent.setAction(Intent.ACTION_VIEW);
                intent.addCategory(Intent.CATEGORY_DEFAULT);
                intent.setData(uri);
                context.startActivity(intent);
            } catch (Exception e)
            {e.printStackTrace(); }
        }else{
            Toast.makeText(context, "您尚未安装高德地图", Toast.LENGTH_LONG).show();
            Uri uri = Uri.parse("market://details?id=com.autonavi.minimap");//去下载
            intent = new Intent(Intent.ACTION_VIEW, uri);
            context.startActivity(intent);
        }
    }

    /**
     * 当前位置到指定位置
     */
    public static void toGaoDeMap(Context context,String endLat, String endLong,String dname){
        Intent intent;
        if (isAvilible(context, "com.autonavi.minimap")) {
            String url = "androidamap://route?sourceApplication=amap"
                    +"&dlat="+endLat+"&dlon="+endLong+"&dname="+ dname +"&dev=0&t=1";
            Uri uri = Uri.parse(url);
            intent = new Intent();
            intent.setAction(Intent.ACTION_VIEW);
            intent.addCategory(Intent.CATEGORY_DEFAULT);
            intent.setData(uri);
            context.startActivity(intent);
        }else{
            Toast.makeText(context, "您尚未安装高德地图", Toast.LENGTH_LONG).show();
            Uri uri = Uri.parse("market://details?id=com.autonavi.minimap");//去下载
            intent = new Intent(Intent.ACTION_VIEW, uri);
            context.startActivity(intent);
        }
    }
}

测试的经纬度:

@Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.bt1:
                MapUtil.toGaoDeMap(this,"39.997361","116.478346","39.936915","116.402796","我是开始位置","我是终点位置");
                break;

            case R.id.bt2:
                MapUtil.toGaoDeMap(this,"39.936915","116.402796","我是终点位置");
                break;

            case R.id.bt5:
                MapUtil.toBaiDuMap(this,"30.195776","120.207283");//当前位置  -  滨江区滨安路467号(春波小区)
                break;

            case R.id.bt6:
                MapUtil.toBaiDuMap(this,"30.195776","120.207283","30.194661","120.221672");
                break;
        }
    }
View Code

效果图:

当没有安装该软件时,效果图(去应用商店下载指定包名的apk)

 

根据两个经纬度获取两点的直线距离

经纬度获取的网址

/**
     * 根据两个经纬度计算两地距离
     * @param longitude1 第一个位置的经度
     * @param latitude1  纬度
     * @param longitude2
     * @param latitude2
     * @return 返回的距离单位是米
     */
    public static double getDistance(double longitude1, double latitude1,
                                     double longitude2, double latitude2) {
        double Lat1 = rad(latitude1);
        double Lat2 = rad(latitude2);
        double a = Lat1 - Lat2;
        double b = rad(longitude1) - rad(longitude2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
                + Math.cos(Lat1) * Math.cos(Lat2)
                * Math.pow(Math.sin(b / 2), 2)));
        s = s * 6378137.0;// 6378137.0为地球半径
        s = Math.round(s * 10000) / 10000;
        return s;
    }
    private static double rad(double d) {
        return d * Math.PI / 180.0;
    }

//测试
LogUtil.e("距离:" + getDistance(120.206995,30.195124,  120.213746,30.195342));

 

posted @ 2016-09-14 21:49  ts-android  阅读(1409)  评论(0编辑  收藏  举报