在viewPager里使用高德地图

懒加载

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

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()

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

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);
        //设置是否只定位一次,默认为false
        aMapLocationClientOption.setOnceLocation(false);
        //设置是否强制刷新WIFI,默认为强制刷新
        aMapLocationClientOption.setWifiActiveScan(true);
        //设置是否允许模拟位置,默认为false,不允许模拟位置
        aMapLocationClientOption.setMockEnable(false);
        //设置定位间隔,单位毫秒,默认为2000ms
        aMapLocationClientOption.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>() {
            @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()

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

整体代码

MapFragment

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

聚合标志工具类

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

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kevinjqy/article/details/54587893
文章标签: 高德地图 viewpager
个人分类: 安卓
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭