Android实现百度离线地图+gps定位

本文详细介绍了如何在Android应用中实现百度离线地图的下载与展示,以及结合GPS进行定位。首先,通过添加百度地图SDK并引用,然后下载所需城市的离线地图。接着,展示了如何使用GPS进行定位并在地图上显示。最后,提供了相应的代码示例和步骤,包括地图初始化、下载管理、定位监听等关键操作。
摘要由CSDN通过智能技术生成

关于

  这段时间,因为公司项目需求,要在内网下实现地图展示及个人定位上报功能,一开始接到这个需求比较懵逼也以为实现起来很简单,结果…我以为的离线地图和实际的百度提供的离线地图功能相差甚远。一开始是想着将离线地图通过后台copy至接口或者资源复制,但是因为种种原因离线地图没显示出来,现在想来应该是地图加载页面写的有问题或者就是缓存问题,这个等有时间研究下吧,项目太着急,只能先这样了。然后离线地图的下载则是直接copy的demo里面的离线地图下载,定位则是通过gps,至于基站没有考虑的原因之一是公司的测试手机么得手机卡。

效果图

图1 离线地图展示
图2 GPS定位

第一步,添加百度地图jar包及引用

  考虑到篇幅原因,我就直接把我之前百度地图使用基本配置的教程放上去,这里只需要参考其中配置地图引用的部分就好了,因为是离线地图估计百度地图的key可能不大需要,毕竟是离线地图使用鉴权也没必要Android关于百度地图的开发心得(笔记一(配置与基本使用))

第二步,下载离线地图功能

  这一部分是直接拿demo上的下载功能,他的下载功能及查看效果如下:
在这里插入图片描述
  直接贴代码了,新建一个activity页面,这里我是起的TestActivity:

public class TestActivity extends AppCompatActivity implements MKOfflineMapListener{

    private MKOfflineMap mOffline = null;
    private TextView cidView;
    private TextView stateView;
    private EditText cityNameView;
    // 已下载的离线地图信息列表
    private ArrayList<MKOLUpdateElement> localMapList = null;
    private LocalMapAdapter lAdapter = null;
    private LinearLayout mCityList;
    private LinearLayout mLocalMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);

        mOffline = new MKOfflineMap();
        mOffline.init(this);
        initView();
    }

    private void initView() {
        cidView = (TextView) findViewById(R.id.cityid);
        cityNameView = (EditText) findViewById(R.id.city);
        stateView = (TextView) findViewById(R.id.state);
        mCityList = (LinearLayout) findViewById(R.id.citylist_layout);
        mLocalMap = (LinearLayout) findViewById(R.id.localmap_layout);

        ListView hotCityList = (ListView) findViewById(R.id.hotcitylist);
        ArrayList<String> hotCities = new ArrayList<String>();
        final ArrayList<String> hotCityNames = new ArrayList<String>();
        // 获取热闹城市列表
        ArrayList<MKOLSearchRecord> records1 = mOffline.getHotCityList();
        if (records1 != null) {
            for (MKOLSearchRecord r : records1) {
                //V4.5.0起,保证数据不溢出,使用long型保存数据包大小结果
                hotCities.add(r.cityName + "(" + r.cityID + ")" + "   --" + this.formatDataSize(r.dataSize));
                hotCityNames.add(r.cityName);
            }
        }
        ListAdapter hAdapter = (ListAdapter) new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, hotCities);
        hotCityList.setAdapter(hAdapter);
        hotCityList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                cityNameView.setText(hotCityNames.get(i));
            }
        });

        ListView allCityList = (ListView) findViewById(R.id.allcitylist);
        // 获取所有支持离线地图的城市
        ArrayList<String> allCities = new ArrayList<String>();
        final ArrayList<String> allCityNames = new ArrayList<String>();
        ArrayList<MKOLSearchRecord> records2 = mOffline.getOfflineCityList();
        if (records2 != null) {
            for (MKOLSearchRecord r : records2) {
                //V4.5.0起,保证数据不溢出,使用long型保存数据包大小结果
                allCities.add(r.cityName + "(" + r.cityID + ")" + "  --" + this.formatDataSize(r.dataSize));
                allCityNames.add(r.cityName);
            }
        }
        ListAdapter aAdapter = (ListAdapter) new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, allCities);
        allCityList.setAdapter(aAdapter);
        allCityList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                cityNameView.setText(allCityNames.get(i));
            }
        });
        mLocalMap.setVisibility(View.GONE);
        mCityList.setVisibility(View.VISIBLE);

        // 获取已下过的离线地图信息
        localMapList = mOffline.getAllUpdateInfo();
        if (localMapList == null) {
            localMapList = new ArrayList<MKOLUpdateElement>();
        }

        ListView localMapListView = (ListView) findViewById(R.id.localmaplist);
        lAdapter = new LocalMapAdapter();
        localMapListView.setAdapter(lAdapter);
    }

    /**
     * 切换至城市列表
     *
     * @param view
     */
    public void clickCityListButton(View view) {
        mLocalMap.setVisibility(View.GONE);
        mCityList.setVisibility(View.VISIBLE);
    }

    /**
     * 切换至下载管理列表
     *
     * @param view
     */
    public void clickLocalMapListButton(View view) {
        mLocalMap.setVisibility(View.VISIBLE);
        mCityList.setVisibility(View.GONE);
    }

    /**
     * 搜索离线城市
     *
     * @param view
     */
    public void search(View view) {
        ArrayList<MKOLSearchRecord> records = mOffline.searchCity(cityNameView.getText().toString());

        if (records == null || records.size() != 1) {
            Toast.makeText(this, "不支持该城市离线地图", Toast.LENGTH_SHORT).show();
            return;
        }
        cidView.setText(String.valueOf(records.get(0).cityID));
    }

    /**
     * 开始下载
     *
     * @param view
     */
    public void start(View view) {
        int cityid = Integer.parseInt(cidView.getText().toString());
        mOffline.start(cityid);
        clickLocalMapListButton(null);

        Toast.makeText(this, "开始下载离线地图. cityid: " + cityid, Toast.LENGTH_SHORT).show();
        updateView();
    }

    /**
     * 暂停下载
     *
     * @param view
     */
    public void stop(View view) {
        int cityid = Integer.parseInt(cidView.getText().toString());
        mOffline.pause(cityid);
        Toast.makeText(this, "暂停下载离线地图. cityid: " + cityid, Toast.LENGTH_SHORT).show();
        updateView();
    }

    /**
     * 删除离线地图
     *
     * @param view
     */
    public void remove(View view) {
        int cityid = Integer.parseInt(cidView.getText().toString());
        mOffline.remove(cityid);
        Toast.makeText(this, "删除离线地图. cityid: " + cityid, Toast.LENGTH_SHORT).show();
        updateView();
    }

    /**
     * 更新状态显示
     */
    public void updateView() {
        localMapList = mOffline.getAllUpdateInfo();
        if (localMapList == null) {
            localMapList = new ArrayList<MKOLUpdateElement>();
        }
        lAdapter.notifyDataSetChanged();
    }

    @Override
    protected void onPause() {
        super.onPause();
        int cityid = Integer.parseInt(cidView.getText().toString());
        MKOLUpdateElement temp = mOffline.getUpdateInfo(cityid);
        if (temp != null && temp.status == MKOLUpdateElement.DOWNLOADING) {
            mOffline.pause(cityid);
        }
    }

    /**
     * V4.5.0起,保证数据不溢出,使用long型保存数据包大小结果
     */
    public String formatDataSize(long size) {
        String ret = "";
        if (size < (1024 * 1024)) {
            ret = String.format("%dK", size / 1024);
        } else {
            ret = String.format("%.1fM", size / (1024 * 1024.0));
        }
        return ret;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 退出时,销毁离线地图模块
        mOffline.destroy();
    }

    @Override
    public void onGetOfflineMapState(int type, int state) {
        switch (type) {
            case MKOfflineMap.TYPE_DOWNLOAD_UPDATE:
                MKOLUpdateElement update = mOffline.getUpdateInfo(state);
                // 处理下载进度更新提示
                if (update != null) {
                    stateView.setText(String.format("%s : %d%%", update.cityName, update.ratio));
                    updateView();
                }
                break;

            case MKOfflineMap.TYPE_NEW_OFFLINE:
                // 有新离线地图安装
                Log.d("OfflineDemo", String.format("add offlinemap num:%d", state));
                break;

            case MKOfflineMap.TYPE_VER_UPDATE:
                // 版本更新提示
                // MKOLUpdateElement e = mOffline.getUpdateInfo(state);
                break;

            default:
                break;
        }
    }

    /**
     * 离线地图管理列表适配器
     */
    public class LocalMapAdapter extends BaseAdapter {

        @Override
        public int getCount() {
            return localMapList.size();
        }

        @Override
        public Object getItem(int index) {
            return localMapList.get(index);
        }

        @Override
        public long getItemId(int index) {
            return index;
        }

        @Override
        public View getView(int index, View view, ViewGroup arg2) {
            MKOLUpdateElement e = (MKOLUpdateElement) getItem(index);
            view = View.inflate(TestActivity.this, R.layout.offline_localmap_list, null);
            initViewItem(view, e);
            return view;
        }

        void initViewItem(View view, final MKOLUpdateElement e) {
            Button display = (Button) view.findViewById(R.id.display);
            Button remove = (Button) view.findViewById(R.id.remove);
            TextView title = (TextView) view.findViewById(R.id.title);
            TextView update = (TextView) view.findViewById(R.id.update);
            TextView ratio = (TextView) view.findViewById(R.id.ratio);
            ratio.setText(e.ratio + "%");
            title.setText(e.cityName);

            if (e.update) {
                update.setText("可更新");
            } else {
                update.setText("最新");
            }

            if (e.ratio != 100) {
                display.setEnabled(false);
            } else {
                display.setEnabled(true);
            }

            remove.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View arg0) {
                    mOffline.remove(e.cityID);
                    updateView();
                }
            });

            display.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent();
                    intent.putExtra("customStyle", true);
                    intent.putExtra("x", e.geoPt.longitude);
                    intent.putExtra("y", e.geoPt.latitude);
                    intent.putExtra("level", 13.0f);
                    intent.setClass(TestActivity.this, MapTypeDemo.class);
                    startActivity(intent);
                }
            });
        }
    }


}

  对应的item布局 offline_localmap_list.xml:

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

    <TextView
        android:id="@+id/title"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="已下载城市 " />

    <TextView
        android:id="@+id/update"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text=""
        android:textColor="#FF0000" />

    <TextView
        android:id="@+id/ratio"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="" />

    <Button
        android:id="@+id/display"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="查看" />

    <Button
        android:id="@+id/remove"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="删除" />

</LinearLayout>

  这里下载地图,我是将北京市的和我自己现在在的地方-南京市下载下来,因为一般如果定位失败都会默认展示北京的地图…所以一般下载两个地图就够了。

第三步,GPS定位+地图展示

  新增布局文件activity_letter_report.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <!--这个是复用的标题栏,你可以直接去掉-->
    <include layout="@layout/title_bar"/>
      
      <com.baidu.mapapi.map.MapView
            android:id="@+id/mapView"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

        </com.baidu.mapapi.map.MapView>

</LinearLayout>

  修改LetterReportActivity.java,第一步,定义控件以及变量

private MapView mapView;
private BaiduMap mBaiduMap;
//自带定位管理,用于获取系统定位服务
private LocationManager lm;
//百度地图控件,用于覆盖点
private BitmapDescriptor bitmap;
//用于获取gps提供
private String privoderLc= "";

  在oncreate中实例化:

 lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
 mapView = (MapView) findViewById(R.id.mapView);
 //初始化地图
 initMaps();
 Criteria criteria = new Criteria();
 criteria.setAccuracy(Criteria.ACCURACY_COARSE);
 criteria.setAccuracy(Criteria.ACCURACY_FINE);
 privoderLc = lm.getBestProvider(criteria, true);
 //初始化权限以及获取信息
 initMapGps();

  编写initMaps()方法:

 private void initMaps() {
        if (mBaiduMap == null)
            mBaiduMap = mapView.getMap();//获取地图实例
        View child = mapView.getChildAt(1);
        if (child != null && (child instanceof ImageView || child instanceof ZoomControls)) {
            child.setVisibility(View.GONE);
        }
        // 构建地图状态
        MapStatus.Builder builder = new MapStatus.Builder();
        // 默认 天安门
        LatLng center = new LatLng(39.915071, 116.403907);
        // 默认 11级
        float zoom = 11.0f;
        builder.target(center).zoom(zoom);
        MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newMapStatus(builder.build());

        // 设置地图状态
        mBaiduMap.setMapStatus(mapStatusUpdate);
    }

先初始化加载北京的离线地图,这样如果gps定位失败了也有默认地图展示。
  initMapGps()方法中

 private void initMapGps() {
        //初始化检测权限
        checkLocation();
        //更新定位信息
        updataLocation();
    }

  编写权限申请checkLocation()

private void checkLocation() {
//这里用的是郭老师的权限请求框架
        PermissionX.init(this)        
        .permissions(Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION)
                /*  .onExplainRequestReason((scope, deniedList) -> {
                      scope.showRequestReasonDialog(deniedList,"以下权限是必须权限","确定","取消");
                  })*/
                //   .onForwardToSettings((scope, deniedList) -> scope.showForwardToSettingsDialog(deniedList,"您需要去应用程序设置当中手动开启权限","去设置","暂不开启"))
                .request(new RequestCallback() {
                    @SuppressLint("MissingPermission")
                    @Override
                    public void onResult(boolean allGranted, List<String> grantedList, List<String> deniedList) {
                        if (allGranted){
                            if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
                                lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 20*1000, 0, listener);
                            }
                        }else {
                           ToastUtils.show("请开启定位权限!");
                        }
                    }
                });
    }

  编写对应的定位监听器:

private LocationListener listener = new LocationListener(){
        @Override
        public void onLocationChanged(Location location) {
        //    Log.e("GPS定位",location.getLatitude()+"|||"+location.getLongitude()+"||");
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }

        @Override
        public void onProviderEnabled(String provider) {
        
        }

        @Override
        public void onProviderDisabled(String provider) {
           ToastUtils.show("定位不可用");
        }
    };

  编写updataLocation()方法更新地图定位:

@SuppressLint("MissingPermission")
    private void updataLocation() {
       if (privoderLc !=null){ //防止手机关闭定位服务导致奔溃
           Location location=lm.getLastKnownLocation(privoderLc);
           if (location != null){
               Log.e("GPS定位",location.getLatitude()+"|||"+location.getLongitude()+"||");
               //将GPS坐标转换成百度坐标,不然显示在地图上会有偏差
               CoordinateConverter converter  = new CoordinateConverter()
                       .from(CoordinateConverter.CoordType.GPS)
                       .coord(new LatLng(location.getLatitude(),location.getLongitude()));         
               Log.e("坐标转换",desLatLng.latitude+"|||"+desLatLng.longitude+"||");
               if (mBaiduMap == null)
                   mBaiduMap = mapView.getMap();//获取地图实例     
               LatLng center = converter.convert();
               if (bitmap == null) {
                   //定位的红色mark点,在百度地图开发平台有
                   bitmap = BitmapDescriptorFactory.fromResource(R.mipmap.icon_openmap_mark);
               }
               //准备 marker option 添加 marker 使用
               OverlayOptions markerOptions = new MarkerOptions().icon(bitmap).position(center);
               //清空之前的marker
               mBaiduMap.clear();
               //获取添加的 marker 这样便于后续的操作
               mBaiduMap.addOverlay(markerOptions);
               //定义地图状态
               MapStatus mMapStatus = new MapStatus.Builder()
                       .target(center)
                       .zoom(18)
                       .build();
               //定义MapStatusUpdate对象,以便描述地图状态将要发生的变化
               MapStatusUpdate mMapStatusUpdate = MapStatusUpdateFactory.newMapStatus(mMapStatus);
               //改变地图状态
               mBaiduMap.setMapStatus(mMapStatusUpdate);
           }else {
               lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 4000, 0, listener);
               ToastUtils.show("定位信息获取异常");
           }
       }else {
           ToastUtils.show("请打开手机定位");
       }
    }

下一篇将会写一篇关于将gps经纬度转换成实际地址的文章,有时间的话,本篇文章到此就结束了,有问题欢迎批评指正,喜欢的也请点个赞噢

评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪の星空朝酱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值