Android 百度地图 SDK v3.0.0 (四) 引入离线地图功能

一直觉得地图应用支持离线地图很重要啊,我等移动2G屌丝,流量不易,且用且珍惜。

 

对于官方开发指南对于离线地图的教程,提供了两种方案:

第一,手动导入,先将从官网下载的离线包解压,把vmp文件夹拷入SD卡根目录下的BaiduMapSDK文件夹内。好吧,我表示不能接受,无视了。

第二,接口下载方法如下:mOffline.start(cityid);还比较靠谱,就是没详细介绍。

今天,我们主要对第二种方式进行详细介绍,然后集成到我们的已经集成了定位方向传感器的地图中,如果你还不了解:Android百度地图 SDK v3.0.0 (三) 添加覆盖物Marker与InfoWindow的使用

效果图:
为了方便,我又添加了个菜单按钮~可以看到能够对下载位置的保存,支持多个等待下载,已经取消下载等。最主要当然是,下载过后,只需要定位的流量(甚至不用)就能很好的使用咱们的地图拉~
顺便提一下:本来想搞个线程池,支持多个同时下载,这块可能很多不注意会有一些问题,但是百度地图公开出来的start(cityCode)不管我怎么尝试(尝试了多个离线地图实例都不行),每次同时都只能下载一个。
1、百度地图离线相关API介绍
a 、类 MKOfflineMap 提供地图的下载,离线地图列表的获取,已下载地图的查询等
java.util.ArrayList<MKOLUpdateElement> getAllUpdateInfo() 返回各城市离线地图更新信息
java.util.ArrayList<MKOLSearchRecord> getHotCityList() 返回热门城市列表
java.util.ArrayList<MKOLSearchRecord> getOfflineCityList() 返回支持离线地图城市列表
MKOLUpdateElement getUpdateInfo(int cityID) 返回指定城市ID离线地图更新信息
java.util.ArrayList<MKOLSearchRecord> searchCity(java.lang.String cityName) 根据城市名搜索该城市离线地图记录
boolean init(MKOfflineMapListener listener) 初使化
boolean pause(int cityID) 暂停下载指定城市ID的离线地图
boolean remove(int cityID) 删除指定城市ID的离线地图
boolean start(int cityID) 启动下载指定城市ID的离线地图
void destroy()  销毁离线地图管理模块,不用时调用

接口 MKOfflineMapListener 离线地图事件通知接口。
void onGetOfflineMapState(int type, int state)
 
类 MKOLUpdateElement 和 类 MKOLSearchRecord
基本就是包含一些cityName , cityId, size 等等
API在百度的帮助文档中也很详细,下面会在代码中使用这些API。
2、离线地图城市信息的实体Bean
  1. package com.zhy.zhy_baidu_ditu_demo00;
  2. public class OfflineMapCityBean
  3. {
  4.     private String cityName;
  5.     private int cityCode;
  6.     /**
  7.      * 下载的进度
  8.      */
  9.     private int progress;
  10.     private Flag flag = Flag.NO_STATUS;
  11.     /**
  12.      * 下载的状态:无状态,暂停,正在下载
  13. [email protected]
  14.      *
  15.      */
  16.     public enum Flag
  17.     {
  18.         NO_STATUS,PAUSE,DOWNLOADING
  19.     }
  20.     public Flag getFlag()
  21.     {
  22.         return flag;
  23.     }
  24.     public void setFlag(Flag flag)
  25.     {
  26.         this.flag = flag;
  27.     }
  28.     public OfflineMapCityBean()
  29.     {
  30.     }
  31.     public OfflineMapCityBean(String cityName, int cityCode, int progress)
  32.     {
  33.         this.cityName = cityName;
  34.         this.cityCode = cityCode;
  35.         this.progress = progress;
  36.     }
  37.     public String getCityName()
  38.     {
  39.         return cityName;
  40.     }
  41.     public void setCityName(String cityName)
  42.     {
  43.         this.cityName = cityName;
  44.     }
  45.     public int getCityCode()
  46.     {
  47.         return cityCode;
  48.     }
  49.     public void setCityCode(int cityCode)
  50.     {
  51.         this.cityCode = cityCode;
  52.     }
  53.     public int getProgress()
  54.     {
  55.         return progress;
  56.     }
  57.     public void setProgress(int progress)
  58.     {
  59.         this.progress = progress;
  60.     }
  61. }

包含了,城市名称:用于listview上的显示,城市id:用于查询下载情况,进度:更新listview下载时的显示,标志:用户开启或者取消下载时的标志。

3、离线地图的使用
在Actvity启动时,首先初始化离线地图
  1. /**
  2.      * 初始化离线地图
  3.      */
  4.     private void initOfflineMap()
  5.     {
  6.         mOfflineMap = new MKOfflineMap();
  7.         // 设置监听
  8.         mOfflineMap.init(new MKOfflineMapListener()
  9.         {
  10. [email protected]
  11.             public void onGetOfflineMapState(int type, int state)
  12.             {
  13.                 switch (type)
  14.                 {
  15.                 case MKOfflineMap.TYPE_DOWNLOAD_UPDATE:
  16.                     // 离线地图下载更新事件类型
  17.                     MKOLUpdateElement update = mOfflineMap.getUpdateInfo(state);
  18.                     Log.e(TAG, update.cityName + ” ,” + update.ratio);
  19.                     for (OfflineMapCityBean bean : mDatas)
  20.                     {
  21.                         if (bean.getCityCode() == state)
  22.                         {
  23.                             bean.setProgress(update.ratio);
  24.                             bean.setFlag(Flag.DOWNLOADING);
  25.                             break;
  26.                         }
  27.                     }
  28.                     mAdapter.notifyDataSetChanged();
  29.                     Log.e(TAG, “TYPE_DOWNLOAD_UPDATE”);
  30.                     break;
  31.                 case MKOfflineMap.TYPE_NEW_OFFLINE:
  32.                     // 有新离线地图安装
  33.                     Log.e(TAG, “TYPE_NEW_OFFLINE”);
  34.                     break;
  35.                 case MKOfflineMap.TYPE_VER_UPDATE:
  36.                     // 版本更新提示
  37.                     break;
  38.                 }
  39.             }
  40.         });
  41.     }

设置离线地图的下载监听接口,目前我们只关注type为MKOfflineMap.TYPE_DOWNLOAD_UPDATE , 此时传入的state为cityId, 然后我们通过mOfflineMap.getUpdateInfo(state);可以获得该城市的下载数据,接下来更新我们listview的数据集,最后刷新界面。

初始化数据:
  1. private void initData()
  2. {
  3.     // 获得所有热门城市
  4.     ArrayList<MKOLSearchRecord> offlineCityList = mOfflineMap
  5.             .getHotCityList();
  6.     // 手动添加了西安
  7.     MKOLSearchRecord xian = new MKOLSearchRecord();
  8.     xian.cityID = 233;
  9.     xian.cityName = “西安市”;
  10.     offlineCityList.add(xian);
  11.     // 获得所有已经下载的城市列表
  12.     ArrayList<MKOLUpdateElement> allUpdateInfo = mOfflineMap
  13.             .getAllUpdateInfo();
  14.     // 设置所有数据的状态
  15.     for (MKOLSearchRecord record : offlineCityList)
  16.     {
  17.         OfflineMapCityBean cityBean = new OfflineMapCityBean();
  18.         cityBean.setCityName(record.cityName);
  19.         cityBean.setCityCode(record.cityID);
  20.         if (allUpdateInfo != null)//没有任何下载记录,返回null,为啥不返回空列表~~
  21.         {
  22.             for (MKOLUpdateElement ele : allUpdateInfo)
  23.             {
  24.                 if (ele.cityID == record.cityID)
  25.                 {
  26.                     cityBean.setProgress(ele.ratio);
  27.                 }
  28.             }
  29.         }
  30.         mDatas.add(cityBean);
  31.     }
  32. }

进入Activity先通过mOfflineMap.getHotCityList();获得热门城市列表,不过热门里面竟然没有西安,我手动增加了一个西安。(这里我是为了方便,有兴趣的可以列出全国支持的城市);接下来mOfflineMap.getAllUpdateInfo();获得已经下载城市的数据信息;然后就行交叉对比,设置数据源数据。

初始化listview
  1. private void initListView()
  2.     {
  3.         mListView = (ListView) findViewById(R.id.id_offline_map_lv);
  4.         mAdapter = new MyOfflineCityBeanAdapter();
  5.         mListView.setAdapter(mAdapter);
  6.         mListView.setOnItemClickListener(new OnItemClickListener()
  7.         {
  8. [email protected]
  9.             public void onItemClick(AdapterView<?> parent, View view,
  10.                     int position, long id)
  11.             {
  12.                 int cityId = mDatas.get(position).getCityCode();
  13.                 if (mCityCodes.contains(cityId))
  14.                 {
  15.                     removeTaskFromQueue(position, cityId);
  16.                 } else
  17.                 {
  18.                     addToDownloadQueue(position, cityId);
  19.                 }
  20.             }
  21.         });
  22.     }

为listview的item设置点击事件,第一次点击时加入下载队列,第二次点击时取消下载。

listview的适配器
  1. /**
  2.      * 热门城市地图列表的Adapter
  3.      *
  4. [email protected]
  5.      *
  6.      */
  7.     class MyOfflineCityBeanAdapter extends BaseAdapter
  8.     {
  9. [email protected]
  10.         public boolean isEnabled(int position)
  11.         {
  12.             if (mDatas.get(position).getProgress() == 100)
  13.             {
  14.                 return false;
  15.             }
  16.             return super.isEnabled(position);
  17.         }
  18. [email protected]
  19.         public int getCount()
  20.         {
  21.             return mDatas.size();
  22.         }
  23. [email protected]
  24.         public Object getItem(int position)
  25.         {
  26.             return mDatas.get(position);
  27.         }
  28. [email protected]
  29.         public long getItemId(int position)
  30.         {
  31.             return position;
  32.         }
  33. [email protected]
  34.         public View getView(int position, View convertView, ViewGroup parent)
  35.         {
  36.             OfflineMapCityBean bean = mDatas.get(position);
  37.             ViewHolder holder = null;
  38.             if (convertView == null)
  39.             {
  40.                 holder = new ViewHolder();
  41.                 convertView = mInflater.inflate(R.layout.offlinemap_item,
  42.                         parent, false);
  43.                 holder.cityName = (TextView) convertView
  44.                         .findViewById(R.id.id_cityname);
  45.                 holder.progress = (TextView) convertView
  46.                         .findViewById(R.id.id_progress);
  47.                 convertView.setTag(holder);
  48.             } else
  49.             {
  50.                 holder = (ViewHolder) convertView.getTag();
  51.             }
  52.             holder.cityName.setText(bean.getCityName());
  53.             int progress = bean.getProgress();
  54.             String progressMsg = “”;
  55.             // 根据进度情况,设置显示
  56.             if (progress == 0)
  57.             {
  58.                 progressMsg = “未下载”;
  59.             } else if (progress == 100)
  60.             {
  61.                 bean.setFlag(Flag.NO_STATUS);
  62.                 progressMsg = “已下载”;
  63.             } else
  64.             {
  65.                 progressMsg = progress + “%”;
  66.             }
  67.             // 根据当前状态,设置显示
  68.             switch (bean.getFlag())
  69.             {
  70.             case PAUSE:
  71.                 progressMsg += “【等待下载】”;
  72.                 break;
  73.             case DOWNLOADING:
  74.                 progressMsg += “【正在下载】”;
  75.                 break;
  76.             default:
  77.                 break;
  78.             }
  79.             holder.progress.setText(progressMsg);
  80.             return convertView;
  81.         }
  82.         private class ViewHolder
  83.         {
  84.             TextView cityName;
  85.             TextView progress;
  86.         }
  87.     }

适配器的代码比较简单,主要就是getView中根本bean的数据设置显示。

最后在我们主Activity增加一个菜单项,打开此Activity就完工了:
  1. @Override
  2. public boolean onOptionsItemSelected(MenuItem item)
  3. {
  4.     switch (item.getItemId())
  5.     {
  6.     case R.id.id_menu_map_offline:
  7.         Intent intent = new Intent(MainActivity.this,
  8.                     OfflineMapActivity.class);
  9.         startActivity(intent);
  10.         break;
  11.     …
  12.     }
  13. }

好了,关于百度地图,目前就用到这么多~~如果后期有别的需求,还会继续更新~

Tagged:

Comments are closed.