当前位置:操作系统 > 安卓/Android >>

对populate()方法的理解


在开发地图的应用中,我们很多时候需要在地图上绘制一些文本,图标信息(比如当前位置的图标,比如某个区域内肯德基店的所有兴趣点)
为了能够在地图上绘制我们需要的信息(比如图片),我们需要知道图层的概念。(就像photoshop里的图层)
接下来我们需要利用API接口实现我们的功能(我们这里采用的是高德的API,高德API开发包可自行在官网上下载)
高德API提供了一个基类Overlay,用于在地图上绘图。我们可以继承自该类,重写draw()方法,调用canvas(画布)的一些方法(比如drawText,drawCircle,drawBitmap),可以在地图上画出许多图形来。这些东西在上一章中有过介绍就不在啰嗦了。
API里还有一个抽象类,它叫做ItemizedOverlay<OverlayItem>,它继承自Overlay,所以它也是一个图层类。该类最大的特点是,它可以描绘出一组兴趣点(POI)出来。继承该抽象类,必须复写三个方法,首先是一个构造方法,它含有一个参数Drawable,该参数是一个图形资源,实则上就是负责显示在地图上的一个图标。另外两个方法分别是
[java] 
@Override 
protected OverlayItem createItem(int i) { 
     

 
@Override 
public int size() { 
     

方法createItem中的返回类型是OverlayItem,该类封装有地理点(GeoPoint),片段信息(Snippet)以及标题(Title),我们通常是这样来得到一个OverlayItem对象的:
[java] 
OverlayItem item = new OverlayItem(gp, "title","snippet");//gp的类型是GeoPoint 

在讲第二个方法前,我们首先看看如何继承ItemizedOverlay<OverlayItem>,假设实现类名为DemoItemizedOverlay
在自己的实现类中,对于字段,我们需要添加一个List<OverlayItem>列表:
[java
List<OverlayItem> overlay_list = new ArrayList<OverlayItem>(); 
注意该列表的元素类型是OverlayItem。
接下来是重写构造方法:
[java] 
public DemoItemizedOverlay(Drawable d) { 
    super(boundCenterBottom(d)); 

 
方法boundCenterBottom的作用是为了将(0,0)点置于图标的底边中点。
 而方法boundCenter的作用是将(0,0)置于图标中央。

然后是重写两个必写方法:
[java] 
@Override 
protected OverlayItem createItem(int i) { 
    return over_list.get(i); 

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

如果想在图标附近添加文本,我们需要复写draw方法:
[java] 
@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); 

注意到列表内容是空的,我们需要增加方法来向列表添加内容和删除内容
[java] 
 * 添加一个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()方法,我们可以看看该方法的定义位置:
[java] 
void com.amap.mapapi.map.ItemizedOverlay.populate() 

说明该方法是ItemizedOverlay类里的。
我们看看官方文档是怎么描述该方法的。
[html] 
在一个新的ItemizedOverlay对象上执行所有操作的工具方法。子类通过createItem(int)方法提供item。一旦有了数据,子类在调用其它方法前,首先调用该方法。 

我们在回过头来看看那两个必写方法,createItem()和size()方法。
当我们在向列表里添加或者删除(各种操作)方法后,必须首先调用populate()方法。调用populate()方法后,接下来就会自动调用createItem()方法和size()方法,这样列表里才真正有了数据。为了验证这一点,我自己做了一个测试。
测试大概是这样的, 我首先创建了DemoItemizedOverlay对象,然后创建了4个OverlayItem对象,接着调用方法addOverlay把它们加入到列表中。如果addOverlay方法里含有populate()方法,那么在测试地图上,我们可以看到有4个图标以及文本信息。然后如果我把populate()方法删掉,此时会抛出异常终止信息,查看LogCat日志:

 


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

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

下面是测试的MainActivity代码:

[java] 
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); 
       

补充:移动开发 , Android ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,