Android手机平台下开发旅游景点位置查询应用程序
- 格式:pdf
- 大小:662.83 KB
- 文档页数:8
2011.
01
Android 手机平台下开发旅游景点位置查询应用程序
苏亚光
吴亚峰
索依娜
1背景知识
随着Google 及其OHA (Open Handset Alliance ———开放手
机联盟)其他成员的大力推进,Android 平台的智能手机市场占有率与日俱增。
由于Android 的发起者是Google ,因此Android 平台对
Google 很多互联网服务的支持也优于很多其他手机平台,这当
然也包括非常著名的Google 地图服务。
Android 中为Google 地图应用的开发提供了很多方便的辅助
类,如MapActivity 、MapView 等。
通过这些类可以非常方便地开发出丰富多彩的地图应用程序,如位置查询、行车路线查询等。
2案例功能
将结合旅游景点位置查询应用的开发来介绍Android 平台
下Google 地图应用开发所需要用到的各种知识与技术。
在正式介绍开发之前,首先对本Android 应用的功能、界面进行简单的介绍。
2.1主界面
本应用主要包含一个主界面,其中分成两个区域,每个区域有不同的功能,如图1所示。
(1)上面的操纵区域中从左至右依次为景点名称输入文本框、
景点位置查询按钮、
历史记录查询按钮
、地图模式选
择按钮。
(2)
下面的地图显示区域用来以气球来标识要查询的景
点位置。
2.2主要功能
(1)用户可以在文本框中输入要查询的景点名称,如“故
宫”,
然后按下景点位置查询按钮
,则应用程序会从网络上
查询到景点的经纬度并在地图上用气球标识出来。
(2)用户可以通过点击气球来打开信息窗口,信息窗口中会显示气球对应景点的经纬度信息。
再次点击气球,就可以关闭信息窗口。
(3)
点击历史记录查询按钮,系统会弹出历史记录选择
对话框,如图2所示。
用户可以在对话框中选择查询过的景
点,不用再次输入了。
(4)点击地图模式选择按
钮
,系统会弹出地图模式选
择对话框。
用户可以根据需要选择普通地图模式或卫星照片
模式,通过卫星照片模式可以看到更为真实的情况,如图3
摘要:详细介绍在Android 智能手机平台下,用Java 开发基于GoogleMap 地图服务的旅游景点位
置查询应用。
通过实际案例,介绍了如何使用Java 在Android 平台下,进行GoogleMap 地图应用的开发,同时也介绍了一些控件的使用技巧及Android 平台下应用开发技巧。
关键词:Ajax ;GoogleMap ;Flickr ;
MushUp
图1
主界面
图2查询历史选择界面
图3地图模式选择界面
76
所示。
3应用界面的搭建
开发应用的各项业务功能之前,首先要进行界面的搭建。
在Android平台下搭建界面一般都是使用XML文档,这样更方便,效率更高。
编写界面XML文档前,首先需要将界面中要使用的一些文字、颜色资源对应的XML文档组织好。
本应用中主要用到了两个资源XML文档:strings.xml、colors.xml。
(1)strings.xml文档的内容
<?xml version="1.0"encoding="utf-8"?>
<resources>
<string name="app_name">TourGuide</string>
<string name="list">景点历史记录</string>
<string name="mode">地图模式</string>
</resources>
从上述代码中可以看出界面中的一些文字内容都在此xml 文档中组织好了。
(2)colors.xml文档的内容
<?xml version="1.0"encoding="utf-8"?>
<resources>
<color name="red">#fd8d8d</color>
<color name="green">#80050505</color>
<color name="blue">#8d9dfd</color>
<color name="white">#FFFFFF</color>
<color name="black">#000000</color>
</resources>
上述代码中把应用中要用到的一些颜色数值都组织好了,这样在使用时就很方便了。
完成了strings.xml与colors.xml文档后,就可以正式开始开发主界面对应的xml文档main.xml了,其代码如下:
<?xml version="1.0"encoding="utf-8"?>
<LinearLayout xmlns:android="/ apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
><!--主界面的总LinearLayout-->
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
><!--操控区域的LinearLayout-->
<ImageView
android:id="@+id/ImageView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/jdmc"
android:paddingTop="4dip"
android:paddingRight="3dip"
><!--“景点名称”标题图片-->
</ImageView>
<EditText
android:text="故宫"
android:id="@+id/EditText01"
android:layout_width="150dip"
android:textSize="16dip"
android:scrollHorizontally="true"
android:singleLine="true"
android:paddingRight="4dip"
android:layout_height="wrap_content">
</EditText><!--景点名称输入文本框--> <ImageButton
android:id="@+id/ImageButton01"
android:src="@drawable/go"
android:layout_width="45dip"
android:layout_height="45dip">
</ImageButton><!--景点位置查询按钮-->
<ImageButton
android:id="@+id/ImageButton02"
android:src="@drawable/history"
android:layout_width="45dip"
android:layout_height="45dip">
</ImageButton><!—历史记录查询按钮-->
<ImageButton
android:id="@+id/ImageButton03"
android:src="@drawable/mode"
android:layout_width="45dip"
android:layout_height="45dip">
</ImageButton><!—地图模式选择按钮-->
</LinearLayout>
<com.google.android.maps.MapView
android:id="@+id/myMapView"
android:layout_width="fill_parent"
android:layout_height="400px"
android:clickable="true"
android:apiKey="0hLdP9fwX-FpZKIIRFjumCcK-HelH4g7mHNvrFcg"/><!--地图显示用的MapView-->
</LinearLayout>
上述XML代码使用LinearLayout嵌套进行了整体界面的布局,使用了图片(ImageView)、文本框(EditText)、图片按钮(ImageButton)、地图View(MapView)等控件。
要特别交代的是,使用MapView时,需要首先去Google 的网站上申请一个key,将申请的key拷贝到MapView的an-droid:apiKey属性中,如上述代码最后几行所示。
从上述开发过程中读者可能会发现,在Android平台下开发应用程序很多地用到了XML文档,这是因为XML是描述性的,易于开发,易于维护。
将程序中一些基本固定的内容用
77
2011.01
2011.
01
XML 文档来完成也是Android 应用开发的一大特色,这与传统
的JavaME 开发手机应用有很大的不同。
界面搭建完成后,还需要将应用中需要用到的一些图片准备好,如图4所示。
从前面的开发中读者可以感觉到,一个Android 应用程序需要很多的资源,这些资源的组织是有规定的,本应用中用到的资源组织结构如图5所示。
从图5中可以看出,图片资源都在res 目录下的drawable-
mdpi 目录中,主界面布局文件main.xml 位于res 目录下的lay -out 目录中,颜色、文本资源XML 文件位于res 目录下的val -ues 目录中,Java 源代码位于src 目录下。
4自定义气球Overlay 的开发
由于Android 的API 中并没有直接提供气球、信息窗口等
地图二次开发中必备控件的实现,因此在正式开发业务功能前,首先要开发带信息窗口的气球实现类,其代码框架如下:
package wyf.wpf;
import com.google.android.maps.Overlay;//此处省略了一些不重要的import 语句import android.graphics.*;
class MyBallonOverlay extends Overlay{//常量的声明
final static int picWidth=20;//气球图的宽度final static int picHeight=34;//气球图的高度final static int arcR=8;//信息窗口的圆角半径//成员变量的声明
//表示当前选中的气球
static MyBallonOverlay currentBallon=null;
String msg;//此气球对应的文字信息String jdmc;//此气球对应的景点名称
//是否显示文字信息窗口的标志位,true 显示文字信息窗口boolean showWindow=false;
GeoPoint gp;//此气球对应的经纬度
public MyBallonOverlay (GeoPoint gp,String msg,String jdmc)
{//构造器
this.gp=gp;this.msg=msg;this.jdmc=jdmc;}
@Override //重写点击事件处理方法
public boolean onTouchEvent(MotionEvent event,MapView mv){//此处未来开发屏幕触控事件处理代码}@Override//绘制自定义Overlay 的方法
public void draw(Canvas canvas,MapView mapView,boolean shadow){//未来开发代码}
//将经纬度翻译成屏幕上XY 坐标的方法
public Point getPoint(MapView mapView){//未来开发代码}//绘制信息窗口的方法
public void drawWindow(Canvas canvas,Point p,int winWidth){//未来开发代码}}
上述代码给出了自定义气球Overlay 类MyBallonOverlay 的代码框架,还留了很多功能丰富要后面逐步实现。
从上述代码框架中可以看出自定义的Overlay 需要继承系统提供的com.google.android.maps.Overlay 类,其实Overlay 就是可以进行自定义绘制的覆盖在地图上面的一个层。
Android 下Google 地图应用的开发中,经常需要通过开发
自定义的Overlay 来往地图上添加自己应用需要的东西,如:气球、信息窗口、导航指示箭头等等。
下面就逐步实现各个功能,首先实现onTouchEvent ,其代码如下:
public boolean onTouchEvent (MotionEvent event,MapView mv){
if(currentBallon!=null&¤tBallon!=this){//若当前气球不为空且不是自己,什么都不做return false;}
//若在气球上按下则设置当前气球为自己,//且当前状态为在气球上
if(event.getAction()==MotionEvent.ACTION_DOWN){int x=(int)event.getX();//获取点击的x 坐标int y=(int)event.getY();//获取点击的y 坐标//将此气球的经纬度翻译成屏幕上的xy 坐标Point p=getPoint(mv);
int xb=p.x-picWidth/2;//计算气球左上侧点的x 坐标int yb=p.y-picHeight;//计算气球左上侧点的y 坐标if(x>=xb&&x<xb+picWidth&&y>=yb&&y<yb+picHeight){//若在自己这个气球上按下则设置自己为当前气球
currentBallon=this;return
true;}}
图4应用中用到的图片图5资源文件组织结构
78
//移动事件返回当前气球状态若当前在气球上则
//返回true屏蔽其他移动事件
else if(event.getAction()==MotionEvent.ACTION_MOVE) {
return currentBallon!=null;}
else if(event.getAction()==MotionEvent.ACTION_UP){ int x=(int)event.getX();//获取点击的x坐标
int y=(int)event.getY();//获取点击的y坐标
//将此气球的经纬度翻译成屏幕上的xy坐标
Point p=getPoint(mv);
int xb=p.x-picWidth/2;//计算气球左上侧点的x坐标
int yb=p.y-picHeight;//计算气球左上侧点的y坐标
//若当前气球为自己且在当前气球上抬起触控则
//显示当前气球内容
if(currentBallon==this&&x>=xb&&x<xb+picWidth
&&y>=yb&&y<yb+picHeight){
currentBallon=null;//显示完内容后清空当前气球引用
showWindow=!showWindow;//置反信息窗口显示标志
List<Overlay>overlays=mv.getOverlays();
overlays.remove(this);//删除此气球再添加
overlays.add(this);//此气球就位于最上面了
for(Overlay ol:overlays)
{//清除其他气球的showWindow标记
if(ol instanceof MyBallonOverlay){
if(ol!=this){//如果不是自己这个气球,关闭信息窗口
((MyBallonOverlay)ol).showWindow=false;
}}}
return true;
}
//若当前气球为自己但抬起触控不再自己上则
//清空气球状态并返回true
else if(currentBallon==this){
currentBallon=null;
return true;}}
return false;//若不符合上述任一情况则返回false
}
上述代码实现了触控事件的处理逻辑,包括移动地图、点击气球、打开关闭信息窗口等。
完成了此方法的开发后就可以着手开发绘制气球Overlay的draw方法了,其代码如下:public void draw(Canvas canvas,MapView mapView, boolean shadow){
//将此气球经纬度翻译成屏幕上的XY坐标供绘制气球
Point p=getPoint(mapView);
//在坐标指定位置绘制气球图片
canvas.drawBitmap(TourGuideActivity.bitmap,
p.x-picWidth/2,p.y-picHeight,null);
if(showWindow){
//如果showWindow为true则显示信息窗口
drawWindow(canvas,p,180);//绘制信息窗口
}
super.draw(canvas,mapView,shadow);//调用父类绘制}
上述draw方法完成的工作是在指定的位置绘制气球图片,并根据气球的信息窗口显示标志值为true还是为false决定是否调用drawWindow方法来绘制此气球对应的信息窗口。
完成了draw方法的开发后就应该开发绘制信息窗口的drawWindow方法了,其代码如下:
public void drawWindow(Canvas canvas,Point p,int win-Width){
int charSize=15;//字体宽度像素值
int textSize=16;//Android字体大小
int leftRightPadding=2;//信息窗口每行左右侧留白
//将此气球的信息字符串根据信息窗口宽度自动分行
int lineWidth=winWidth-leftRightPadding*2;//每行的宽度int lineCharCount=lineWidth/(charSize);//每行字符数
//记录所有行的ArrayList
ArrayList<String>alRows=new ArrayList<String>();
String currentRow="";//当前行的字符串
for(int i=0;i<msg.length();i++){
char c=msg.charAt(i);//从信息字符串中取出一个字符
if(c!='\n'){//若当前字符不为换行符则加入到当前行中currentRow=currentRow+c;
}else{//若当前字符为换行符则检查当前行长度,若当前行//长度大于零则将当前行加入记录所有行的ArrayList if(currentRow.length()>0){alRows.add(currentRow);} currentRow="";//清空当前行
}
if(currentRow.length()==lineCharCount)
{//若当前行的长度达到一行规定的字符数则将当前行加
//入记录所有行的ArrayList
alRows.add(currentRow);
currentRow="";//清空当前行
}}
if(currentRow.length()>0){//若当前行长度大于零则将当前行
//加入记录所有行的ArrayList
alRows.add(currentRow);}
int lineCount=alRows.size();//获得总行数
//自动计算信息窗体高度
int winHeight=lineCount*(charSize)+2*arcR;
Paint paint=new Paint();//创建paint对象
paint.setAntiAlias(true);//打开抗锯齿
paint.setTextSize(textSize);//设置文字大小
//绘制信息窗体圆角矩形
paint.setARGB(255,255,251,239);//设置画笔颜色
int x1=p.x-winWidth/2;//计算圆角矩形外接矩形左上侧点
int y1=p.y-picHeight-winHeight-1;//的XY坐标
int x2=x1+winWidth;//计算圆角矩形外接矩形右下侧点
int y2=y1+winHeight;//的XY坐标
RectF r=new RectF(x1,y1,x2,y2);//创建圆角矩形对象canvas.drawRoundRect(r,arcR,arcR,paint);//绘制圆角矩形//绘制信息窗体圆角矩形边框
paint.setARGB(255,198,195,198);//设置画笔颜色
79
2011.01
2011.
01
paint.setStyle(Paint.Style.STROKE);//设置绘制线形paint.setStrokeWidth(2);//设置线的宽度
canvas.drawRoundRect(r,arcR,arcR,paint);//绘制圆角矩形//框
//循环绘制每行文字
paint.setStrokeWidth(0);
paint.setARGB(255,10,10,10);//设置画笔颜色int lineY=y1+arcR+charSize;//计算第一行的Y 坐标for(String lineStr:alRows){//对每一行进行循环
for(int j=0;j<lineStr.length();j++){//对一行中的每个字循环//从当前行取出一个字符
String colChar=lineStr.charAt(j)+"";
canvas.drawText(colChar,x1+leftRightPadding +j*charSize,lineY,paint);//绘制此字符}
lineY=lineY+charSize;//y 坐标移向下一行}}
上述drawWindow 方法的功能为根据调用时提供的信息窗体宽度,自动将气球对应的文字信息分行,根据行数自动计算出信息窗口的高度,绘制信息窗口对应的圆角矩形及边框,最后将每行内容绘制到信息窗口中。
上述很多方法都调用了辅助方法getPoint 将气球的经纬度换算为屏幕上的XY 坐标,其代码如下:
public Point getPoint(MapView mapView){//将经纬度翻译成屏幕上的XY 坐标//获取投影对象
Projection projettion =mapView.getProjection();
Point p =new Point();//创建用于存储XY 坐标的point 对象projettion.toPixels(gp,p);//调用toPixels 方法进行换算return p;//返回结果}
完成了上述所有工作后,自定义气球Overlay 的开发就完成了它可以在很多应用程序中重用的,并不只是服务于本文的应用程序,笔者就在很多应用程序中都使用了这个自定义气球
Overlay 。
5业务功能Activity 的开发
自定义气球Overlay 的开发完成后,就应该着手开发实现
本应用业务功能的Activity 了,其代码框架如下:
package wyf.wpf;
import java.io.IOException;
//此处省略了一些不重要的import 语句
import android.widget.AdapterView.OnItemClickListener;public class TourGuideActivity extends MapActivity {
//常量的声明
final int HISTORY_DIALOG=0;//历史对话框的ID final int MODE_DIALOG=1;//模式选择对话框的ID //成员变量的声明
static Bitmap bitmap;//气球图片MapController mc;//地图控制器String jdmcArray[];//景点名称数组
Dialog historyDialog;//历史对话框的引用@Override //activity 的创建、初始化方法
public void onCreate(Bundle savedInstanceState){
//[1]一些初始化工作
//[2]给查询按钮添加监听器//[3]给历史按钮添加监听器//[4]给模式按钮添加监听器}
@Override //对话框的创建方法
public Dialog onCreateDialog(int id){}
@Override //每次弹出对话框时被回调以动态更新对话框内//容的方法
public void onPrepareDialog(int id,Dialog dialog){}@Override //重写父类的方法
protected boolean isRouteDisplayed(){return false;}}
从上述代码框架中可以看出,还有很多功能方法有待实现,首先应该实现onCreate 方法。
其主要有4项工作需要完成,首先是一些初始化的代码:
super.onCreate(savedInstanceState);//调用父类onCreate 方法
setContentView(yout.main);//设置当前view 为main //初始化气球图片
bitmap=BitmapFactory.decodeResource(this.getResources(),R.drawable.ballon);//对地图进行初始化
MapView mv=(MapView)findViewById(R.id.myMapView);mv.setBuiltInZoomControls(true);//设置地图上要缩放控制条mc=mv.getController();//获取地图控制器mc.setZoom(14);//设置地图缩放比例GeoPoint gp =new GeoPoint
(//创建包含地图中心点经纬度的GeoPoint 对象(int)(39.9083*1E6),//纬度(int)(116.3975*1E6)//经度);
mc.animateTo(gp);//设置地图中心点经纬度
接着需要做的工作是为查询按钮添加监听器,此监听器的功能为根据用户输入的景点名称通过网络查询景点的经纬度信息,得到经纬度信息后创建携带经纬度文本信息的气球,并将气球添加到地图上的指定位置,具体代码如下:
ImageButton ib=//获取查询按钮
(ImageButton)this.findViewById(R.id.ImageButton01);ib.setOnClickListener(new OnClickListener(){@Override //重写onClick 方法public void onClick(View v){//获取输入的景点名称
80
EditText et=(EditText)findViewById(R.id.EditText01); String jdmcStr=et.getText().toString();
Geocoder gc=//通过Geocoder查找指定名称景点的经纬度new Geocoder(TourGuideActivity.this,Locale.getDefault());
try{//通过Geocoder查找指定名称景点的经纬度列表
List<Address>addressList=//获取景点经纬度列表
gc.getFromLocationName(jdmcStr,1);
if(addressList.size()>0){
//如果成功获取了经纬度取列表中的第一条记录
Address tempa=addressList.get(0);
int latE6=(int)(tempa.getLatitude()*1000000);//获取纬度
int longE6=(int)(tempa.getLongitude()*1000000);//获取经度GeoPoint gp=new GeoPoint(latE6,longE6);
String latStr=//纬度字符串
Math.round(gp.getLatitudeE6()/1000.00)/1000.0+"";
String longStr=//经度字符串
Math.round(gp.getLongitudeE6()/1000.00)/1000.0+"";
//在地图的对应位置显示气球
MapView mv=(MapView)findViewById(R.id.myMapView); List<Overlay>overlays=mv.getOverlays();
boolean isExisted=false;MyBallonOverlay curr=null;
for(Overlay ol:overlays){//对所有的Overlay循环处理
if(ol instanceof MyBallonOverlay){//如果是气球Overlay MyBallonOverlay tempMbo=(MyBallonOverlay)ol;
//关闭已经存在景点的信息提示窗口
tempMbo.showWindow=false;if(gp.getLatitudeE6()== tempMbo.gp.getLatitudeE6()&&
gp.getLongitudeE6()==tempMbo.gp.getLongitudeE6())
{//景点已经存在
isExisted=true;
//打开要查询景点的信息提示窗口
tempMbo.showWindow=true;
curr=tempMbo;
}}}
if(!isExisted){//如果景点不存在则添加新气球
//在点击位置添加新气球
MyBallonOverlay mbo=new MyBallonOverlay(
gp,//气球的坐标
jdmcStr+"的地理坐标为:\n经度:"+longStr
+"\n纬度:"+latStr,//气球的信息
jdmcStr//景点名称
);
mbo.showWindow=true;//设置新气球的信息窗口打开
overlays.add(mbo);//将新气球添加到地图上
}else{//如果已经存在气球则将此气球移动到最上层
overlays.remove(curr);overlays.add(curr);}
mc.animateTo(gp);//设置地图中央经纬度
}else{//若没有查询到景点经纬度则报错
Toast.makeText(TourGuideActivity.this,//上下文
"对不起,您要找的景点没有找到!",//报错信息
Toast.LENGTH_SHORT//显示时长).show();}}catch(IOException e){e.printStackTrace();} }});
从上述代码中可以看出,提供给GeoPoint类构造器的经纬度都是整数(int型),但实际的经纬度是肯定带小数的,否则精度就太低了。
其实这里的整数并不是说经纬度只是精确到整数度,而是把经纬度扩大100万倍的整数,实际是精确到小数点后6位。
onCreate方法的最后两项工作是给历史按钮、模式按钮添
加监听器,其代码如下:
//给历史按钮添加监听器
ib=(ImageButton)this.findViewById(R.id.ImageButton02);
ib.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v){//重写onClick方法
MapView mv=(MapView)findViewById(R.id.myMapView); List<Overlay>overlays=mv.getOverlays();
if(overlays.size()!=0)
{//若当前有历史记录则显示历史记录对话框
showDialog(HISTORY_DIALOG);
}else{//若当前没有历史记录则提示
Toast.makeText(TourGuideActivity.this,//上下文
"对不起,目前没有历史记录!",//提示信息
Toast.LENGTH_SHORT//显示时长
).show();}}});
//给模式按钮添加监听器
ib=(ImageButton)this.findViewById(R.id.ImageButton03); ib.setOnClickListener(new OnClickListener(){
@Override//重写onClick方法
public void onClick(View v){//显示地图模式选择对话框showDialog(MODE_DIALOG);//显示模式选择对话框
}});
完成了onCreate方法的开发后,就可以开发对话框的创建方法onCreateDialog了,其代码如下:
@Override//重写对话框创建方法onCreateDialog
public Dialog onCreateDialog(int id){
Dialog result=null;
switch(id){
case HISTORY_DIALOG://历史记录对话框的初始化
AlertDialog.Builder b=new AlertDialog.Builder(this);
b.setItems(null,null);historyDialog=b.create();
result=historyDialog;
break;
case MODE_DIALOG://地图模式选择对话框的初始化
AlertDialog.Builder bl=new AlertDialog.Builder(this);
bl.setIcon(R.drawable.mode);//设置图标
bl.setTitle(R.string.mode);//设置标题
bl.setItems(new String[]{"普通模式","卫星模式"},
new DialogInterface.OnClickListener(){
@Override//重写对话框中羡慕被点击的onClick方法
public void onClick(DialogInterface dialog,int which){
81
2011.01
2011.
01
MapView mv=//获取地图View
(MapView)findViewById(R.id.myMapView);switch(which){
case 0://若索引为0则设置为普通地图模式mv.setStreetView(true);mv.setSatellite(false);break;
case 1://若索引为1则设置为卫星地图模式mv.setSatellite(true);mv.setStreetView(false);break;}}});
result=bl.create();break;}
return result;//返回创建的对话框}
上述方法完成了对话框的创建工作,可以发现在开发地图模式选择对话框的创建代码时工作做得比较全面,包括标题、选项、选项监听器在内的对话框的各个方面都完成了。
但对于历史记录对话框,工作却做得比较粗糙。
这是因为历史记录对话框的选项等内容是随着应用的使用不断变化的,因此对话框的创建工作不能全部在onCreateDialog 方法中完成。
而是需要把实时变化的部分留到onPrepareDialog 方法中完成,其代码如下:
@Override
//重写每次弹出对话框时被回调以动态更新对话框内容的方法public void onPrepareDialog(int id,Dialog dialog){//若不是历史对话框则返回
if(id!=this.HISTORY_DIALOG)return;//获取当前景点名称的列表
MapView mv=(MapView)findViewById(R.id.myMapView);List<Overlay>overlays =mv.getOverlays();
jdmcArray=new String[overlays.size()];//存放景点名称的数组int i=0;//数组索引
//从所有景点标识气球中循环获取景点名称for(Overlay ol:overlays){
if(ol instanceof MyBallonOverlay){//若此Overlay 为气球MyBallonOverlay tempMbo=(MyBallonOverlay)ol;
jdmcArray[i++]=tempMbo.jdmc;//从气球中获取景点名称}}
//对话框对应的总垂直方向LinearLayout
LinearLayout ll=new LinearLayout(TourGuideActivity.this);ll.setOrientation(LinearLayout.VERTICAL);//设置朝向ll.setGravity(Gravity.CENTER_HORIZONTAL);//设置对齐ll.setBackgroundResource(R.drawable.dialog);//设置背景图//标题行的水平LinearLayout
LinearLayout lln=new LinearLayout(TourGuideActivity.this);lln.setOrientation(LinearLayout.HORIZONTAL);//设置朝向lln.setGravity(Gravity.LEFT);//设置对齐方式
lln.setLayoutParams(new youtParams(200,LayoutParams.WRAP_CONTENT));//设置长宽尺寸//标题行的图标
ImageView iv=new ImageView(TourGuideActivity.this);
iv.setImageResource(R.drawable.history);//设置图标
iv.setLayoutParams(new youtParams(24,24));lln.addView(iv);//添加到标题行的水平LinearLayout 中//标题行的文字
TextView tvTitle=new TextView(TourGuideActivity.this);tvTitle.setText(R.string.list);//设置标题行的文字内容tvTitle.setTextSize(20);//设置字体大小//设置字体颜色
tvTitle.setTextColor(TourGuideActivity.this.getResources().getColor(R.color.white));lln.addView(tvTitle);//添加到标题行中
ll.addView(lln);//将标题行添加到总LinearLayout //为对话框中的历史记录条目创建ListView
ListView lv=new ListView(this);//初始化ListView //设置列表为单选选择模式
lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);//为ListView 准备内容适配器
BaseAdapter ba=new BaseAdapter(){
@Override //重写返回总共选项个数的方法public int getCount(){return jdmcArray.length;}@Override
public Object getItem(int arg0){return null;}@Override
public long getItemId(int arg0){return 0;}@Override
public View getView(int arg0,View arg1,ViewGroup arg2){//动态生成每条历史记录对应的TextView
TextView tv=new TextView(TourGuideActivity.this);//设置文本对其方式为水平居中
tv.setGravity(Gravity.CENTER_HORIZONTAL);tv.setText(jdmcArray[arg0]);//设置内容tv.setTextSize(20);//设置字体大小
tv.setTextColor(TourGuideActivity.this.getResources().getColor(R.color.white));//设置字体颜色tv.setPadding(0,0,0,0);//设置四周留白return tv;}};
lv.setAdapter(ba);//为ListView 设置内容适配器//设置选项被单击的监听器
lv.setOnItemClickListener(new OnItemClickListener(){@Override
public void onItemClick(AdapterView<?>arg0,View arg1,int arg2,long arg3){//重写选项被单击事件的处理方法//获取历史记录中当前选中的TextView TextView tv=(TextView)arg1;//获取地名输入框
EditText et=(EditText)TourGuideActivity.this.findViewById(R.id.EditText01);
//将历史记录中选中条目内容设置到地名输入框et.setText(tv.getText());
TourGuideActivity.this.historyDialog.cancel();//关闭对话框}});
//将历史记录条的ListView 加入总LinearLayout
82
len1=len;
if(len%2!=0)len1++;
fwrite(&len1,1,4,avifp);
fwrite(buf1,1,len1,avifp);
indexcount++;
totalframes++;
movisize=movisize+len1+8;
newlist=new AVIINDEX;//更新索引链表
newlist->dwChunkId=1667510320L;
if(xvid_enc_stats.type==XVID_TYPE_IVOP)
newlist->dwFlags=0x10;
else
newlist->dwFlags=0x00;
newlist->dwOffset=startindex;
newlist->dwSize=len;
newlist->next=NULL;
startindex=startindex+len1+8;
thelist=aviindexlist;
while(1)
{
if(thelist->next==NULL)break;
thelist=thelist->next;
}
thelist->next=newlist;
}
tick1=tick2;
}
if(recording==0)break;
Sleep(1);
}
free(buf1);
free(buf2);
xvid_encore(enc_handle,XVID_ENC_DESTROY,NULL, NULL);//撤消编码实例
}
FreeLibrary(hHandle);
WriteAviIndex();
UpdateAviHeader();
fclose(avifp);
waveInReset(wavein_handle); waveInUnprepareHeader(wavein_handle,&waveinhdr,sizeof (WAVEHDR));
GlobalFree(GlobalHandle(waveinhdr.lpData)); waveInClose(wavein_handle);//关闭声音输入
delete buf3;
return0;
}
7结语
AVI录像机程序开发完成,对AVI多媒体文件的录制,具有一定的实用价值。
(收稿日期:2010-11-03)
ll.addView(lv);
//将组织好的对话框布局添加到历史记录选择对话框中dialog.setContentView(ll);
}
从上述代码中可以看出,列表(ListView)中选项的内容都是由其适配器(Adapter)提供的,本应用中适配器的实现采用的是继承BaseAdapter的方式。
当ListView需要选项时,首先会调用其对应Adapter的getCount方法获取选项的个数,然后依次调用getView方法获取各个选项对象。
本应用程序中,每个选项都是由TextView实现的。
完成了上述代码的开发后,所有的代码开发工作就都完成了。
6应用程序的打包发布
由于Android平台下的应用程序一般都是使用Eclipse开发的,因此打包与发布的工作非常简单。
只要在开发完成后在Eclipse中运行一下项目,然后就可以在项目文件夹下的bin子文件夹下找到可以用于安装发布的APK包,如图6所示。
将此APK包安装到基于Android平台的手机中即可运行,在联网正确的状态下可以成功获取景点经纬度并显示如图1、图2、图3所示的界面。
7结语
通过开发旅游景点位置查询的应用程序,读者可以基本掌握Android平台下Google地图应用的开发,了解如何向地图中添加自定义的内容。
本应用的功能还不够完善,读者可以自行进一步扩展。
例如结合GPS定位,开发出从当前位置到查询的旅游景点自动路线导航的功能等。
(收稿日期:2010-10-17)
图6bin子目录下的apk包
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!(上接第75页)
83
2011.01。