前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在viewPager里使用高德地图

在viewPager里使用高德地图

作者头像
用户1665735
发布2019-02-19 12:41:20
2.3K0
发布2019-02-19 12:41:20
举报
文章被收录于专栏:kevindroidkevindroid

懒加载

因为viewpager的预加载机制,使得联网应用会多出内存以及网络的使用量,同时,在viewpager下使用高德地图,也会因此出现各种莫名其妙的问题,因此,需要使用懒加载的手段。 实现懒加载,只需继承fragment类然后重写与界面显示相关的方法即可。

代码语言:javascript
复制
public abstract class LazyFragment extends Fragment{
    protected boolean isVisible;

    @Override
    public 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()

代码语言:javascript
复制
@Override
    public 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()

代码语言:javascript
复制
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()

代码语言:javascript
复制
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);
        //设置是否只定位一次,默认为false
        aMapLocationClientOption.setOnceLocation(false);
        //设置是否强制刷新WIFI,默认为强制刷新
        aMapLocationClientOption.setWifiActiveScan(true);
        //设置是否允许模拟位置,默认为false,不允许模拟位置
        aMapLocationClientOption.setMockEnable(false);
        //设置定位间隔,单位毫秒,默认为2000ms
        aMapLocationClientOption.setInterval(10000);
        //给定位客户端对象设置定位参数
        aMapLocationClient.setLocationOption(aMapLocationClientOption);
        //启动定位
        aMapLocationClient.startLocation();
    }

配置定位参数并开始定位。

onLocationChanged()

代码语言:javascript
复制
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()

代码语言:javascript
复制
//添加标志到地图上
    private void addMarkerToMap(Double lat, Double lon) {
        NetWorks.getAroundPosts(lat, lon, new Observer<PostLab>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
                Log.e("MapFragment",e.getMessage());
            }

            @Override
            public 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()

代码语言:javascript
复制
protected void lazyLoad() {
        if (null != aMap) {
            //每次重新加载地图前,清除数据
            aMap.clear();
            markerLocal = null;
            markerOptionsListall.clear();
            markerOptionsListInView.clear();
        }
        setUpMapIfNeeded();
    }

整体代码

MapFragment

代码语言:javascript
复制
public class MapFragment extends LazyFragment implements
        AMapLocationListener, 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)
    //视野内的marker
    private ArrayList<MarkerOptions> markerOptionsListInView = new ArrayList<>();
    //所有的marker
    private 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
    }


    @Override
    public 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;
    }

    @Override
    public void onResume() {
        super.onResume();
        mapView.onResume();
    }

    @Override
    public void onPause() {
        super.onPause();
        mapView.onPause();
        deactivate();
    }


    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mapView.onSaveInstanceState(outState);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        //mapView.onDestroy();
    }

    @Override
    public 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);
        //设置是否只定位一次,默认为false
        aMapLocationClientOption.setOnceLocation(false);
        //设置是否强制刷新WIFI,默认为强制刷新
        aMapLocationClientOption.setWifiActiveScan(true);
        //设置是否允许模拟位置,默认为false,不允许模拟位置
        aMapLocationClientOption.setMockEnable(false);
        //设置定位间隔,单位毫秒,默认为2000ms
        aMapLocationClientOption.setInterval(10000);
        //给定位客户端对象设置定位参数
        aMapLocationClient.setLocationOption(aMapLocationClientOption);
        //启动定位
        aMapLocationClient.startLocation();
    }


    @Override
    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());
            }
        }
    }

    //添加标志到地图上
    private void addMarkerToMap(Double lat, Double lon) {
        NetWorks.getAroundPosts(lat, lon, new Observer<PostLab>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
                Log.e("MapFragment",e.getMessage());
            }

            @Override
            public 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);
            }
        }
        // 自定义的聚合类MyMarkerCluster
        ArrayList<MarkerImageView> clustersMarker = new ArrayList<>();
        for (MarkerOptions mp : markerOptionsListInView) {
            if (clustersMarker.size() == 0) {
                // 添加一个新的自定义marker
                clustersMarker.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=相距多少才聚合
                }
            }
        }
        // 设置聚合点的位置和icon
        for (MarkerImageView mmc : clustersMarker) {
            mmc.setpositionAndIcon();
        }
        aMap.clear();
        // 重新添加 marker
        for (MarkerImageView cluster : clustersMarker) {
            aMap.addMarker(cluster.getOptions());
        }
    }

    @Override
    protected void lazyLoad() {
        if (null != aMap) {
            //每次重新加载地图前,清除数据
            aMap.clear();
            markerLocal = null;
            markerOptionsListall.clear();
            markerOptionsListInView.clear();
        }
        setUpMapIfNeeded();
    }


    @Override
    public void activate(OnLocationChangedListener onLocationChangedListener) {
        mOnLocationChangedListener = onLocationChangedListener;
    }

    @Override
    public void deactivate() {
        mOnLocationChangedListener = null;
    }

    //marker点击事件
    @Override
    public boolean onMarkerClick(Marker marker) {
        marker.hideInfoWindow();
        LatLng latLng = marker.getPosition();
        return false;
    }


    @Override
    public void onCameraChange(CameraPosition cameraPosition) {
    }

    @Override
    public void onCameraChangeFinish(CameraPosition cameraPosition) {
        if (markerOptionsListall.size() != 0) {
            resetMarks();
        }
    }

}

MarkerImageView

聚合标志工具类

代码语言:javascript
复制
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对象,导致一些莫名其妙的错误。 多点聚合主要参考这位大神的博客:这儿

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017年01月17日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 懒加载
  • 高德地图的具体实现
    • onCreateView()
      • setUpMapIfNeeded()
        • location()
          • onLocationChanged()
            • addMarkerToMap()
              • LazyLoad()
              • 整体代码
                • MapFragment
                  • MarkerImageView
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档