对populate()方法的理解


在开发地图的应用中,我们很多时候需要在地图上绘制一些文本,图标信息(比如当前位置的图标,比如某个区域内肯德基店的所有兴趣点)

为了能够在地图上绘制我们需要的信息(比如图片),我们需要知道图层的概念。(就像photoshop里的图层)

接下来我们需要利用API接口实现我们的功能(我们这里采用的是高德的API,高德API开发包可自行在官网上下载)

高德API提供了一个基类Overlay,用于在地图上绘图。我们可以继承自该类,重写draw()方法,调用canvas(画布)的一些方法(比如drawText,drawCircle,drawBitmap),可以在地图上画出许多图形来。这些东西在上一章中有过介绍就不在啰嗦了。

API里还有一个抽象类,它叫做ItemizedOverlay,它继承自Overlay,所以它也是一个图层类。该类最大的特点是,它可以描绘出一组兴趣点(POI)出来。继承该抽象类,必须复写三个方法,首先是一个构造方法,它含有一个参数Drawable,该参数是一个图形资源,实则上就是负责显示在地图上的一个图标。另外两个方法分别是

		@Override
		protected OverlayItem createItem(int i) {
			
		}

		@Override
		public int size() {
			
		}

方法createItem中的返回类型是OverlayItem,该类封装有地理点(GeoPoint),片段信息(Snippet)以及标题(Title),我们通常是这样来得到一个OverlayItem对象的:

OverlayItem item = new OverlayItem(gp, "title","snippet");//gp的类型是GeoPoint

在讲第二个方法前,我们首先看看如何继承ItemizedOverlay,假设实现类名为DemoItemizedOverlay

在自己的实现类中,对于字段,我们需要添加一个List列表:

List overlay_list = new ArrayList();

注意该列表的元素类型是OverlayItem。

接下来是重写构造方法:

		public DemoItemizedOverlay(Drawable d) {
			super(boundCenterBottom(d));
		}
方法boundCenterBottom的作用是为了将(0,0)点置于图标的底边中点。

 而方法boundCenter的作用是将(0,0)置于图标中央。


然后是重写两个必写方法:

		@Override
		protected OverlayItem createItem(int i) {
			return over_list.get(i);
		}

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

如果想在图标附近添加文本,我们需要复写draw方法:

		@Override
		public void draw(Canvas canvas, MapView mapView, boolean shadow) {
			for(int i=0; i< size(); i++) {
				OverlayItem item = createItem(i);
				GeoPoint gp = item.getPoint();
				Point mPoint = new Point();
				Projection proj = mapView.getProjection();
				proj.toPixels(gp, mPoint);
				Paint mPaint = new Paint();
				mPaint.setColor(Color.BLUE);
				mPaint.setAntiAlias(true);	//抗锯齿
				canvas.drawText("图标" + (i+1), mPoint.x, mPoint.y-30, mPaint);
				
			}
			super.draw(canvas, mapView, shadow);
		}

注意到列表内容是空的,我们需要增加方法来向列表添加内容和删除内容

		/**
		 * 添加一个Overlay
		 */
		public void addOverlay(OverlayItem overlay) {
			over_list.add(overlay);
			populate();
		}
		/**
		 * 删除一个Overlay
		 */
		public void dropOverlay(OverlayItem item) {
			if(over_list.contains(item)) {
				over_list.remove(item);
				populate();
			}
		}


关键点来了,有没有注意到populate()方法,我们可以看看该方法的定义位置: 

         void com.amap.mapapi.map.ItemizedOverlay.populate()

说明该方法是ItemizedOverlay类里的。

我们看看官方文档是怎么描述该方法的。

在一个新的ItemizedOverlay对象上执行所有操作的工具方法。子类通过createItem(int)方法提供item。一旦有了数据,子类在调用其它方法前,首先调用该方法。

我们在回过头来看看那两个必写方法,createItem()和size()方法。

当我们在向列表里添加或者删除(各种操作)方法后,必须首先调用populate()方法。调用populate()方法后,接下来就会自动调用createItem()方法和size()方法,这样列表里才真正有了数据。为了验证这一点,我自己做了一个测试。

测试大概是这样的, 我首先创建了DemoItemizedOverlay对象,然后创建了4个OverlayItem对象,接着调用方法addOverlay把它们加入到列表中。如果addOverlay方法里含有populate()方法,那么在测试地图上,我们可以看到有4个图标以及文本信息。然后如果我把populate()方法删掉,此时会抛出异常终止信息,查看LogCat日志:


对populate()方法的理解_第1张图片


所以会抛出空指针异常,是因为没有调用populate()方法,所以也不会调用createItem()方法,因此虽然调用了addOverlay方法,但是实际上并没有往列表里添加Overlay,因此会抛出NullPointerException。


我们看下createItem方法的描述:

createItem

protected abstract Item createItem(int i)
子类通过该方法创建实体item。该item只能从populate()开始调用,并且缓存起来待以后使用。
参数:
i - 实体item对象。
返回:
创建的实体item。

下面是测试的MainActivity代码:


package com.example.itemizedoverlaytest;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.widget.Toast;

import com.amap.mapapi.core.GeoPoint;
import com.amap.mapapi.core.OverlayItem;
import com.amap.mapapi.map.ItemizedOverlay;
import com.amap.mapapi.map.MapActivity;
import com.amap.mapapi.map.MapController;
import com.amap.mapapi.map.MapView;
import com.amap.mapapi.map.Overlay;
import com.amap.mapapi.map.Projection;

public class MainActivity extends MapActivity {

	private MapView mapView;
	
	private Drawable d;
	
	private MapController controller;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		//this.setMapMode(MAP_MODE_VECTOR);	//设置为矢量图s
		
		setContentView(R.layout.activity_main);
		
		mapView = (MapView)findViewById(R.id.mapView);
		
		mapView.setBuiltInZoomControls(true);	//开启缩放控件
		
		controller = mapView.getController();	//得到控制对象
		
//		mapView.setSatellite(true);				//设置卫星模式
		
		GeoPoint gp = new GeoPoint((int) (30.227123 * 1E6),
				(int) (120.040687 * 1E6));	//工大
		
		controller.setCenter(gp);
		
		controller.setZoom(10);
		
		d = getResources().getDrawable(R.drawable.marker_gpsvalid);
		
	//	d.setBounds(0, 0, right, bottom)
		
		List map_list = mapView.getOverlays();
		
		DemoItemizedOverlay demo = new DemoItemizedOverlay(d, this);
		GeoPoint gp1 = new GeoPoint((int) (30.227123 * 1E6),
				(int) (120.040687 * 1E6));
		OverlayItem item1 = new OverlayItem(gp1, "title1","snippet1");
		demo.addOverlay(item1);
		
		GeoPoint gp2 = new GeoPoint((int) (30.237123 * 1E6),
				(int) (120.050687 * 1E6));
		OverlayItem item2 = new OverlayItem(gp2, "title2","snippet2");
		demo.addOverlay(item2);	
		
		GeoPoint gp3 = new GeoPoint((int) (30.247123 * 1E6),
				(int) (120.060687 * 1E6));
		OverlayItem item3 = new OverlayItem(gp3, "title3","snippet3");
		demo.addOverlay(item3);	
		
		map_list.add(demo);
	
		GeoPoint gp4 = new GeoPoint((int) (30.257123 * 1E6),
				(int) (120.070687 * 1E6));
		OverlayItem item4 = new OverlayItem(gp4, "title4","snippet4");
		demo.addOverlay(item4);	
		
		demo.dropOverlay(item2);
	}
	
	public class DemoItemizedOverlay extends ItemizedOverlay {

		private List over_list = new ArrayList();

		private Context mContext; 			//上下文
		
		public DemoItemizedOverlay(Drawable d) {
			super(boundCenterBottom(d));
		}

		public DemoItemizedOverlay(Drawable d,Context c) {
			this(d);
			mContext = c;
		}
		
		@Override
		public void draw(Canvas canvas, MapView mapView, boolean shadow) {
			for(int i=0; i< size(); i++) {
				OverlayItem item = createItem(i);
				GeoPoint gp = item.getPoint();
				Point mPoint = new Point();
				Projection proj = mapView.getProjection();
				proj.toPixels(gp, mPoint);
				Paint mPaint = new Paint();
				mPaint.setColor(Color.BLUE);
				mPaint.setAntiAlias(true);	//抗锯齿
				canvas.drawText("图标" + (i+1), mPoint.x, mPoint.y-30, mPaint);
				
			}
			super.draw(canvas, mapView, shadow);
		}

		@Override
		protected boolean onTap(int i) {
			OverlayItem item = over_list.get(i);
			Toast.makeText(mContext,"片段信息:" + item.getSnippet() + "\n标题:" + item.getTitle(),Toast.LENGTH_SHORT).show();
			return super.onTap(i);
		}

		@Override
		protected OverlayItem createItem(int i) {
			return over_list.get(i);
		}

		@Override
		public int size() {
			return over_list.size();
		}
		
		/**
		 * 添加一个Overlay
		 */
		public void addOverlay(OverlayItem overlay) {
			over_list.add(overlay);
			populate();
		}
		/**
		 * 删除一个Overlay
		 */
		public void dropOverlay(OverlayItem item) {
			if(over_list.contains(item)) {
				over_list.remove(item);
				populate();
			}
		}
	}
}

最后别忘了加相应的 权限,以及在安卓清单文件中 注册该Activity。

需要项目资源的可点击:http://download.csdn.net/detail/czjuttsw/4726692


お疲れ様でした!^_^

Over...

你可能感兴趣的:(android)