在viewPager里使用高德地图
懒加载
因为viewpager的预加载机制,使得联网应用会多出内存以及网络的使用量,同时,在viewpager下使用高德地图,也会因此出现各种莫名其妙的问题,因此,需要使用懒加载的手段。
实现懒加载,只需继承fragment类然后重写与界面显示相关的方法即可。
public abstract class LazyFragment extends Fragment{protected boolean isVisible;@Overridepublic void setUserVisibleHint(boolean isVisibleToUser) {//frahment从不可见到完全可见的时候,会调用该方法super.setUserVisibleHint(isVisibleToUser);if (getUserVisibleHint() && isInit){isVisible = true;onVisible();}else {isVisible = false;isInit=false;onInvisible();}}protected abstract void lazyLoad();//懒加载的方法,在这个方法里面我们为Fragment的各个组件去添加数据protected void onVisible(){lazyLoad();}protected void onInvisible(){}
}
isInit是一个在MapFragment里定义的bool型变量,用来判断高德地图所在的fragment是否已经初始化,如果不添加,那么点击viewpager里的tab跳转可能会出现空指针错误。
高德地图的具体实现
onCreateView()
@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {View v = inflater.inflate(R.layout.fragment_map, container, false);isFirstLoc = 1;isInit = true;mapView = (MapView) v.findViewById(R.id.map);mapView.onCreate(savedInstanceState);// 此方法必须重写screenWidth = ScreenUtils.getScreenWidth(getActivity());screenHeight = ScreenUtils.getScreenHeight(getActivity());setUpMapIfNeeded();return v;}
完成地图空间的初始化以及定位标识符的初始化,防止多次重复定位。高度与宽度用来后面的地图多标志聚合。
setUpMapIfNeeded()
private void setUpMapIfNeeded() {((MainActivity) getActivity()).setFabVisible(0);//业务要求,读者可忽视aMap = mapView.getMap();uiSettings = aMap.getUiSettings();aMap.setLocationSource(this);//设置定位监听,实现LocationSource的接口aMap.setOnMarkerClickListener(this);// 设置点击marker事件监听器aMap.setOnCameraChangeListener(this);// 对amap添加移动地图事件监听器//是否显示定位按钮uiSettings.setMyLocationButtonEnabled(true);//设置缩放控件uiSettings.setZoomGesturesEnabled(true);//显示比例尺控件uiSettings.setScaleControlsEnabled(true);uiSettings.setZoomControlsEnabled(true);//显示定位层并可以触发定位事件aMap.setMyLocationEnabled(true);//开始定位location();}
完成地图一些基本的参数配置。
location()
private void location() {Log.d("定位测试", "location方法已经执行");//初始化定位aMapLocationClient = new AMapLocationClient(getActivity());//设置定位回调监听aMapLocationClient.setLocationListener(this);//初始化定位参数aMapLocationClientOption = new AMapLocationClientOption();//设置定位模式为Hight_Accuracy高精度模式,Battery_Saving为低功耗模式,Device_Sensors是仅设备模式aMapLocationClientOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);//设置是否返回地址信息(默认返回地址信息)aMapLocationClientOption.setNeedAddress(true);//设置是否只定位一次,默认为falseaMapLocationClientOption.setOnceLocation(false);//设置是否强制刷新WIFI,默认为强制刷新aMapLocationClientOption.setWifiActiveScan(true);//设置是否允许模拟位置,默认为false,不允许模拟位置aMapLocationClientOption.setMockEnable(false);//设置定位间隔,单位毫秒,默认为2000msaMapLocationClientOption.setInterval(10000);//给定位客户端对象设置定位参数aMapLocationClient.setLocationOption(aMapLocationClientOption);//启动定位aMapLocationClient.startLocation();}
配置定位参数并开始定位。
onLocationChanged()
public void onLocationChanged(AMapLocation aMapLocation) {//Log.d("定位回掉方法测试",aMapLocation.toString());if (aMapLocation != null) {if (aMapLocation.getErrorCode() == 0) {//可在其中解析amapLocation获取相应内容。lat = aMapLocation.getLatitude();//获取纬度lon = aMapLocation.getLongitude();//获取经度//获取定位时间SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date date = new Date(aMapLocation.getTime());df.format(date);Log.d("缩放标志位", "定位次数" + isFirstLoc);// 如果不设置标志位,此时再拖动地图时,它会不断将地图移动到当前的位置if (isFirstLoc == 1) {//设置缩放级别(缩放级别为4-20级)isFirstLoc = 0;aMap.moveCamera(CameraUpdateFactory.zoomTo(15));//将地图移动到定位点aMap.moveCamera(CameraUpdateFactory.changeLatLng(new LatLng(lat, lon)));//点击定位按钮 能够将地图的中心移动到定位点mOnLocationChangedListener.onLocationChanged(aMapLocation);}if (null == markerLocal) {//只有为空时才重绘,防止内存泄漏addMarkerToMap(lat, lon);}} else {//定位失败时,可通过ErrCode(错误码)信息来确定失败的原因,errInfo是错误信息,详见错误码表。Log.e("地图错误", "定位失败, 错误码:" + aMapLocation.getErrorCode() + ", 错误信息:"+ aMapLocation.getErrorInfo());}}}
此方法是完成定位的回调方法,同时也是移动地图的回调方法。再次方法里获取定位的结果并显示在地图上。
addMarkerToMap()
//添加标志到地图上private void addMarkerToMap(Double lat, Double lon) {NetWorks.getAroundPosts(lat, lon, new Observer<PostLab>() {@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable e) {Log.e("MapFragment",e.getMessage());}@Overridepublic void onNext(PostLab postLab) {Log.e("地图","成功获取数据");if (markerOptionsListall != null) {//每次重绘前清除数据markerOptionsListall.clear();}posts = postLab.getmPosts();for (Post post :posts) {double tempLat = post.getmLat();double tempLon = post.getmLon();final LatLng mLatLng = new LatLng(tempLat, tempLon);final String mTitle = post.getmTitle();MarkerOptions markerOptions = new MarkerOptions();markerOptions.draggable(true);markerOptions.icon(BitmapDescriptorFactory.defaultMarker());View v = getActivity().getLayoutInflater().inflate(R.layout.custom_infowindow_content, null);ImageView imageView = (ImageView) v.findViewById(R.id.custom_content_image);TextView textView = (TextView) v.findViewById(R.id.custom_content_title);imageLoader.displayImage(post.getmImageUrl(),imageView, ImageLoaderOptionUtil.getOptions());textView.setText(mTitle);markerOptions.position(mLatLng);//将这个view转为bitmap格式markerOptions.icon(BitmapDescriptorFactory.fromView(v));//markerOptions.title(mTitle);markerOptionsListall.add(markerOptions);markerLocal = aMap.addMarker(markerOptions);}}});}
本方法的目的是根据经纬度信息将标记添加到地图上,我是业务需要,从网络获取多个经纬度信息然后添加到地图上。
LazyLoad()
protected void lazyLoad() {if (null != aMap) {//每次重新加载地图前,清除数据aMap.clear();markerLocal = null;markerOptionsListall.clear();markerOptionsListInView.clear();}setUpMapIfNeeded();}
整体代码
MapFragment
public class MapFragment extends LazyFragment implementsAMapLocationListener, LocationSource, AMap.OnMarkerClickListener,AMap.OnCameraChangeListener {private AMap aMap;private MapView mapView;private UiSettings uiSettings;private AMapLocationClient aMapLocationClient;private OnLocationChangedListener mOnLocationChangedListener = null;private AMapLocationClientOption aMapLocationClientOption;private Double lat; //经度private Double lon; //纬度private int isFirstLoc;//定位标志位public static boolean isInit = false;//控件初始化标志位private Marker markerLocal;private int screenHeight;// 屏幕高度(px)private int screenWidth;// 屏幕宽度(px)//视野内的markerprivate ArrayList<MarkerOptions> markerOptionsListInView = new ArrayList<>();//所有的markerprivate ArrayList<MarkerOptions> markerOptionsListall = new ArrayList<>();//markerOptionsListall初始化标志位private int isListallInit = 0;//接收到的post集合private List<Post> posts;//获取imageloader实例private final ImageLoader imageLoader = ImageLoader.getInstance();public MapFragment() {// Required empty public constructor}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {View v = inflater.inflate(R.layout.fragment_map, container, false);isFirstLoc = 1;isInit = true;mapView = (MapView) v.findViewById(R.id.map);mapView.onCreate(savedInstanceState);// 此方法必须重写screenWidth = ScreenUtils.getScreenWidth(getActivity());screenHeight = ScreenUtils.getScreenHeight(getActivity());setUpMapIfNeeded();return v;}@Overridepublic void onResume() {super.onResume();mapView.onResume();}@Overridepublic void onPause() {super.onPause();mapView.onPause();deactivate();}@Overridepublic void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);mapView.onSaveInstanceState(outState);}@Overridepublic void onDestroy() {super.onDestroy();//mapView.onDestroy();}@Overridepublic void onDestroyView() {super.onDestroyView();mapView.onDestroy();}private void setUpMapIfNeeded() {((MainActivity) getActivity()).setFabVisible(0);aMap = mapView.getMap();uiSettings = aMap.getUiSettings();aMap.setLocationSource(this);//设置定位监听,实现LocationSource的接口aMap.setOnMarkerClickListener(this);// 设置点击marker事件监听器aMap.setOnCameraChangeListener(this);// 对amap添加移动地图事件监听器//是否显示定位按钮uiSettings.setMyLocationButtonEnabled(true);//设置缩放控件uiSettings.setZoomGesturesEnabled(true);//显示比例尺控件uiSettings.setScaleControlsEnabled(true);uiSettings.setZoomControlsEnabled(true);//显示定位层并可以触发定位事件aMap.setMyLocationEnabled(true);//开始定位location();}private void location() {Log.d("定位测试", "location方法已经执行");//初始化定位aMapLocationClient = new AMapLocationClient(getActivity());//设置定位回调监听aMapLocationClient.setLocationListener(this);//初始化定位参数aMapLocationClientOption = new AMapLocationClientOption();//设置定位模式为Hight_Accuracy高精度模式,Battery_Saving为低功耗模式,Device_Sensors是仅设备模式aMapLocationClientOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);//设置是否返回地址信息(默认返回地址信息)aMapLocationClientOption.setNeedAddress(true);//设置是否只定位一次,默认为falseaMapLocationClientOption.setOnceLocation(false);//设置是否强制刷新WIFI,默认为强制刷新aMapLocationClientOption.setWifiActiveScan(true);//设置是否允许模拟位置,默认为false,不允许模拟位置aMapLocationClientOption.setMockEnable(false);//设置定位间隔,单位毫秒,默认为2000msaMapLocationClientOption.setInterval(10000);//给定位客户端对象设置定位参数aMapLocationClient.setLocationOption(aMapLocationClientOption);//启动定位aMapLocationClient.startLocation();}@Overridepublic void onLocationChanged(AMapLocation aMapLocation) {//Log.d("定位回掉方法测试",aMapLocation.toString());if (aMapLocation != null) {if (aMapLocation.getErrorCode() == 0) {//可在其中解析amapLocation获取相应内容。lat = aMapLocation.getLatitude();//获取纬度lon = aMapLocation.getLongitude();//获取经度//获取定位时间SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date date = new Date(aMapLocation.getTime());df.format(date);Log.d("缩放标志位", "定位次数" + isFirstLoc);// 如果不设置标志位,此时再拖动地图时,它会不断将地图移动到当前的位置if (isFirstLoc == 1) {//设置缩放级别(缩放级别为4-20级)isFirstLoc = 0;aMap.moveCamera(CameraUpdateFactory.zoomTo(15));//将地图移动到定位点aMap.moveCamera(CameraUpdateFactory.changeLatLng(new LatLng(lat, lon)));//点击定位按钮 能够将地图的中心移动到定位点mOnLocationChangedListener.onLocationChanged(aMapLocation);}if (null == markerLocal) {//只有为空时才重绘,防止内存泄漏addMarkerToMap(lat, lon);}} else {//定位失败时,可通过ErrCode(错误码)信息来确定失败的原因,errInfo是错误信息,详见错误码表。Log.e("地图错误", "定位失败, 错误码:" + aMapLocation.getErrorCode() + ", 错误信息:"+ aMapLocation.getErrorInfo());}}}//添加标志到地图上private void addMarkerToMap(Double lat, Double lon) {NetWorks.getAroundPosts(lat, lon, new Observer<PostLab>() {@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable e) {Log.e("MapFragment",e.getMessage());}@Overridepublic void onNext(PostLab postLab) {Log.e("地图","成功获取数据");if (markerOptionsListall != null) {//每次重绘前清除数据markerOptionsListall.clear();}posts = postLab.getmPosts();for (Post post :posts) {double tempLat = post.getmLat();double tempLon = post.getmLon();final LatLng mLatLng = new LatLng(tempLat, tempLon);final String mTitle = post.getmTitle();MarkerOptions markerOptions = new MarkerOptions();markerOptions.draggable(true);markerOptions.icon(BitmapDescriptorFactory.defaultMarker());View v = getActivity().getLayoutInflater().inflate(R.layout.custom_infowindow_content, null);ImageView imageView = (ImageView) v.findViewById(R.id.custom_content_image);TextView textView = (TextView) v.findViewById(R.id.custom_content_title);imageLoader.displayImage(post.getmImageUrl(),imageView, ImageLoaderOptionUtil.getOptions());textView.setText(mTitle);markerOptions.position(mLatLng);markerOptions.icon(BitmapDescriptorFactory.fromView(v));//markerOptions.title(mTitle);markerOptionsListall.add(markerOptions);markerLocal = aMap.addMarker(markerOptions);}}});}/*** 获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker*/private void resetMarks() {// 开始刷新Projection projection = aMap.getProjection();Point p = null;markerOptionsListInView.clear();// 获取在当前视野内的marker;提高效率for (MarkerOptions mp : markerOptionsListall) {p = projection.toScreenLocation(mp.getPosition());if (p.x < 0 || p.y < 0 || p.x > screenWidth || p.y > screenHeight) {// 不添加到计算的列表中} else {markerOptionsListInView.add(mp);}}// 自定义的聚合类MyMarkerClusterArrayList<MarkerImageView> clustersMarker = new ArrayList<>();for (MarkerOptions mp : markerOptionsListInView) {if (clustersMarker.size() == 0) {// 添加一个新的自定义markerclustersMarker.add(new MarkerImageView(getActivity(), mp, projection, 80));// 80=相距多少才聚合} else {boolean isIn = false;for (MarkerImageView cluster : clustersMarker) {// 判断当前的marker是否在前面marker的聚合范围内 并且每个marker只会聚合一次。if (cluster.getBounds().contains(mp.getPosition())) {cluster.addMarker(mp);isIn = true;break;}}// 如果没在任何范围内,自己单独形成一个自定义marker。在和后面的marker进行比较if (!isIn) {clustersMarker.add(new MarkerImageView(getActivity(), mp, projection, 80));// 80=相距多少才聚合}}}// 设置聚合点的位置和iconfor (MarkerImageView mmc : clustersMarker) {mmc.setpositionAndIcon();}aMap.clear();// 重新添加 markerfor (MarkerImageView cluster : clustersMarker) {aMap.addMarker(cluster.getOptions());}}@Overrideprotected void lazyLoad() {if (null != aMap) {//每次重新加载地图前,清除数据aMap.clear();markerLocal = null;markerOptionsListall.clear();markerOptionsListInView.clear();}setUpMapIfNeeded();}@Overridepublic void activate(OnLocationChangedListener onLocationChangedListener) {mOnLocationChangedListener = onLocationChangedListener;}@Overridepublic void deactivate() {mOnLocationChangedListener = null;}//marker点击事件@Overridepublic boolean onMarkerClick(Marker marker) {marker.hideInfoWindow();LatLng latLng = marker.getPosition();return false;}@Overridepublic void onCameraChange(CameraPosition cameraPosition) {}@Overridepublic void onCameraChangeFinish(CameraPosition cameraPosition) {if (markerOptionsListall.size() != 0) {resetMarks();}}}
MarkerImageView
聚合标志工具类
public class MarkerImageView {//上下文private Context context;//marker类private MarkerOptions options;//当前可观区域里的 聚合过之后的集合private ArrayList<MarkerOptions> includeMarkers = new ArrayList<>();// 创建区域private LatLngBounds bounds;private int count = 0;/*** 头像加载完监听*/public MarkerImageView(Context context, MarkerOptions firstMarkers,Projection projection, int gridSize) {this.context = context;options = new MarkerOptions();Point point = projection.toScreenLocation(firstMarkers.getPosition());//范围类Point southwestPoint = new Point(point.x - gridSize, point.y + gridSize);//范围类Point northeastPoint = new Point(point.x + gridSize, point.y - gridSize);bounds = new LatLngBounds(projection.fromScreenLocation(southwestPoint),projection.fromScreenLocation(northeastPoint));//设置初始化marker属性options.anchor(0.5f, 0.5f).title(firstMarkers.getTitle()).position(firstMarkers.getPosition()).icon(firstMarkers.getIcon()).snippet(firstMarkers.getSnippet());includeMarkers.add(firstMarkers);Log.d("计数",""+count++);}public MarkerImageView(Context context) {this.context = context;}public LatLngBounds getBounds() {return bounds;}public MarkerOptions getOptions() {return options;}public void setOptions(MarkerOptions options) {this.options = options;}/*** 添加marker*/public void addMarker(MarkerOptions markerOptions) {includeMarkers.add(markerOptions);// 添加到列表中}/*** 设置聚合点的中心位置以及图标*/public void setpositionAndIcon() {int size = includeMarkers.size();double lat = 0.0;double lng = 0.0;// 一个的时候if (size == 1) {//设置marker单个属性// 设置marker位置Log.d("单个marker", "被使用");options.position(new LatLng(includeMarkers.get(0).getPosition().latitude,includeMarkers.get(0).getPosition().longitude));options.title("聚合点");options.icon(BitmapDescriptorFactory.fromBitmap(getViewBitmap(getView(size))));} else {// 聚合的时候//设置marker聚合属性Log.d("多个marker", includeMarkers.size()+"个被使用");for (MarkerOptions op : includeMarkers) {lat += op.getPosition().latitude;lng += op.getPosition().longitude;}// 设置marker的位置为中心位置为聚集点的平均位置options.position(new LatLng(lat / size, lng / size));options.title("聚合点");options.icon(BitmapDescriptorFactory.fromBitmap(getViewBitmap(getView(size))));}}/*** marker视图*/public View getView(int num) {View view = LayoutInflater.from(context).inflate(R.layout.view_gaode_img, null);/** 数量 */TextView txt_num = (TextView) view.findViewById(R.id.view_gaode_txt_num);/** 头像 */ImageView img_portrait = (ImageView) view.findViewById(R.id.view_gaode_img_portrait);img_portrait.setPadding(8, 8, 8, 12);if (num > 1) {txt_num.setText(num + "");} else if (num == 1) {//在此处修改未聚合时候的显示方式txt_num.setText(num + "");img_portrait.setBackgroundResource(R.drawable.green_pin);//overDraw();}return view;}/*** 把一个view转化成bitmap对象*/public static Bitmap getViewBitmap(View view) {Bitmap bitmap = null;try {if (view != null) {view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));view.layout(0, 0, view.getMeasuredWidth(),view.getMeasuredHeight());view.buildDrawingCache();bitmap = view.getDrawingCache();}} catch (Exception e) {}return bitmap;}
}
值得注意的一点是,在for循环中向markerOptionsListall中添加markerOptions时,一定要每次循环都要声明并定义markOptions,因为类当参数传递时是直接使用的引用,如果不这样做,每次循环都会重用markOptions对象,导致一些莫名其妙的错误。
多点聚合主要参考这位大神的博客:这儿。
在viewPager里使用高德地图相关推荐
- android 内嵌地图,Android Fragment里嵌入高德地图【原创】
最近在做的项目里要用到地图,看了一下高德地图的API,最后决定就用高德地图,和平时不同,这次地图是要嵌在Fragment了,研究了一下网上的代码,最后实现了.下面说一下实现2D地图的方法. 1.先去高 ...
- Vue对高德地图2.0的封装使用
在Vue项目里使用高德地图,网上有几个比较好用的,例如 AMap-Vue ,文档很好,但不开源 vue-amap ,文档让人流泪 懒人和需求不复杂的,可以直接使用上面的.上面两开源的已经不太活跃了,用 ...
- h5手机端或PC端利用高德地图获取当前定位位置
踩的坑写在前面: 想直接利用h5的特性来获取,但是一直报错,需要https服务,结果还去了阿里云搞ssl的域名卡住了,然后一直报未检测到DNS配置记录,如果你们服务是https就可以直接用这个了. 后 ...
- web端引入高德地图
一.用原始方法引入,对所有web端都可用 先引入一下文件 <link rel="stylesheet" href="https://a.amap.com/jsapi ...
- 高德地图Amap离线地图的使用
一.问题现象 高德地图离线地图的官方使用教程点这里传送门 我们把在正常有网的手机上通过离线地图下载的城市数据拷贝出来备用,如下图 把上面两个文件夹放到一台插有物联网卡的终端机器上,存放目录为SD卡根目 ...
- right 微信小程序_微信小程序高德地图API
本文章介绍微信小程序调用高德地图API的过程,使用高德定位功能做演示. 微信小程序目前支持百度地图.高德地图.腾讯地图.用法可以说是基本完全一样,本文章以高德为例,简单说一下他们的区别,高德地图精度应 ...
- 微信小程序---高德地图API
本文章介绍微信小程序调用高德地图API的过程,使用高德定位功能做演示. 微信小程序目前支持百度地图.高德地图.腾讯地图.用法可以说是基本完全一样,本文章以高德为例,简单说一下他们的区别,高德地图精度应 ...
- uniapp 之 使用高德地图的方法将经纬度转为地址
目录 前言 第一步 第二步 第三步 前言 因项目上的需要,需定位显示自己的位置 我之前一直坚持只使用 uniapp 内置的map属性去完成,却没成想,还是要依赖于高德地图才能将经纬度转为地址,之前也看 ...
- 高德地图-2D地图下区域遮掩(只显示固定区域里的内容)
最近遇到一个新的需求需用用到高德地图 公司需要只显示固定区域范围的地图,其余地方的地图都用透明遮罩覆盖 完成后如下图所示: 地图体验网址 刚开始的时候研究了半天高德地图的的JS API中只有一个区域遮 ...
最新文章
- 天津盈克斯机器人科技_柔性视觉选料 机器人摆盘 柔性振动盘
- 用Android NDK打造自己的toolchain(使用C/C++默认的Makefile)
- oauth2.0授权码_OAUTH 2.0授权码授予
- mysql 小写null 大写null_mysql中的null字段值的处理及大小写问题
- win10计算器rsh_Win10计算器在哪里?
- 华为手机像素密度排行_最新手机性能排行榜出炉:高通骁龙865霸榜,前十不见华为!...
- 再读华为代码规范文档
- unix网络编程之基本套接口编程
- 杰奇1.7--关关采集器使用教程
- windows 禁用ipv6服务_win10系统电脑中禁用ipv6协议的修复方案
- 过去一年对我帮助最大的三本书
- 数独解法Java实现
- 购物系统 java代码_java购物系统源代码
- 做好演讲者的必备条件
- 网页图片循环滚动播放效果
- C语言的文件打开(多种方式),读写,关闭,文件指针偏移等操作,理解读写原理
- SpringCloudAlibaba看的某马视频笔记
- Traceback (most recent call last):异常
- 成大事,你一定需要经历的二次跃升
- sqlsever主库从库如何切换_超硬核的Java工程师分享,什么是Java?为什么我要做Java,我是如何学习Java的?...