国内关注网站:
1、http://www.im2m.com.cn
2、http://www.chniot.cn
国外关注网站:
1、http://www.webofthings.org/
2、http://www.rfidjournal.com/
Google Maps 是Google公司提供的电子地图服务,它能够提供三种视图:一是交通、街道视图;二是卫星视图;三是后来加上的地形视图。可以去http://maps.google.com看一下。(还有一个更炫的:Google Earth,它是Google Maps的姊妹产品,是一个在三维模型上提供街景和更多的卫星视图及GPS定位的功能的桌面应用程序。)
二、开发的准备工作
1.下载安装Google APIs的组件
在编译器里打开Android SDK Manager,看一下Google APIs by Google Ins”选项是否显示安装了,如果没有则勾选相应版本的“Google APIs by Google Ins”选项,然后进行安装。
2.创建新的模拟器
打开Android Virtual Device Manager(怎么新建模拟器不用说了吧……)注意在Target这一栏选的是Google APIs!
3.新建一个支持Google Maps API的工程
在新建工程时也同样注意,勾选的不再是Android 2.2(或者2.3等等),而是Google APIs!
4.在AndroidManifest.xml文件中添加库文件
<uses-library android:name="com.google.android.maps" />
5.在AndroidManifest.xml文件中添加访问网络的许可
<uses-permission android:name="android.permission.INTERNET" />
三、申请Android Map API Key(密钥)
这一步很重要,这是取得地图服务的关键。
首先我们在安装Android的开发环境时都会有一个系统默认的证书(相当于签名,用于标记程序的开发者),这个证书里包含一个唯一的key,这个key就是我们要获取的MD5值(认证指纹),然后我们再通过MD5值到Google的Android Map API Key申请我们所需要的密钥。
具体步骤如下:
步骤1:找到你的debug.keystore文件。证书的一般路径为:C:\Documents and Settings\当前用户\Local Settings\Application Data\ Android\debug.keystore。
步骤2:取得debug.keystore的MD5值。首先在命令提示符下进入debug.keystore文件所在的路径,执行命令:keytool -list -alias androiddebugkey -keystore debug.keystore这时可能会提示你输入密码,这里输入默认的密码“android”,即可取得MD5值(认证指纹)
步骤3:申请Android Map的API Key。打开浏览器,输入网址:http://code.google.com/intl/zh-CN/android/maps-api-signup.html,登录Google账号,在Google的Android Map API Key申请页面上输入步骤2得到的MD5认证指纹。
然后你就会获得"0Vsky-WLijmLQ17R7GHyJMCkedPCx-HOkkq0azQ",这个就是密钥。
四、在布局文件中创建MapView的控件
<com.google.android.maps.MapView android:id="@+id/MapView01" android:layout_width="fill_parent" android:layout_height="fill_parent" android:clickable="true" android:enabled="true" android:apiKey="0Vsky-WLijmLQ17R7GHyJMCkedPCx-HOkkq0azQ" />
注意密钥不要打错了,否则你会在测试的是时候得到一个空白的页面(感受颇深,犯这个错很不值)!
五、开始写主程序
1.写之前先了解一下相关类
MapAcitivity:管理Activity的生命周期,为mapview建立及取消对map service的连接。
注意:一个进程只能支持一个MapActivity,否则会有意想不到的异常和错误。
MapView:Mapview是用来显示地图的类,当MapView获得焦点,可以控制地图的移动和缩放。地图可以以不同的形式来显示出来,如街景模式,卫星模式等,通过setSatellite(boolean),setTraffic(boolean), setStreetView(boolean) 方法。
MapView只能被MapActivity来创建,这是因为mapview需要通过后台的线程来连接网络或者文件系统,而这些线程要由mapActivity来管理。
MapController:控制地图移动,伸缩,以某个GPS坐标为中心,控制MapView中的view组件,管理Overlay,提供View的基本功能。
Overlay:覆盖层的类,我们在一些导航软件上看到的地图标记,路线等都是画在这个上面的。我们可以扩展它的onDraw接口,自定义在MapView中显示一些自己的东西。
Projection:投影类,作用是在MapView中将实际的GPS坐标与屏幕上的坐标进行转换(GeoPoint和Point)。
2.创建一个Google APIS项目之后会自动生成一个继承Activity的类,我们需要把它改成继承MapActivity的类
public class MapDemoActivity extends MapActivity { @Override public void onCreate(Bundle saveInstanceState) { super.onCreate(saveInstanceState); } /*是否显示路径信息*/ @Override protected boolean isRouteDisplayed() { return false; } }
3.初始化MapView,显示地图的载体,并调用它的成员方法:
getController()//获取地图控制器
setStreetView() //设置地图显示模式为街道模式
setTraffic() //设置地图显示模式为交通模式*/
setSatellite() //设置地图显示模式为卫星模式
setZoom() //设置地图缩放率(1~21)
getMapCenter() //获取地图中心
getLatitudeSpan()//获取纬度跨度
getLongitudeSpan()//获取经度跨度
setBuiltInZoomControls()//设置是否内置缩放控制器
具体代码如下:
mMapController = mMapView01.getController(); //设置地图显示模式为卫星模式 mMapView.setSatellite(false); //设置地图显示模式为街道模式 mMapView.setStreetView(false); //设置地图显示模式为交通模式 mMapView.setTraffic(true); //设置放大倍数 mMapController.setZoom(12);
4.使用Overlay在地图上添加标记
Overlay是地图覆盖层,这是个抽象类,要为地图添加覆盖层的话需要实现这个类的draw方法,如果需要添加事件响应需要实现onTap方法。
public class MyOverlay extends Overlay { //绘制地图标记显示的内容 @Override public void draw(Canvas canvas, MapView mapView, boolean shadow) { super.draw(canvas, mapView, shadow); } //单击标记需要执行的事件 @Override public boolean onTap(GeoPoint p, MapView mapView) { return super.onTap(p, mapView); } }
5、使用LocationManager进行定位(个人认为这是最有意思和最核心的部分)
(1)要有定位功能,首先需要获得LocationManager对象。在Android中,获得LocationManager的唯一方法是通过getSystemService()方法的调用。
LocationManager locationManager=(LocationManager)getSystemService(context);
(2)在获取到LocationManager后,还需要指定LocationManager的定位方法,然后才能够调用LocationManager。
LocationManager支持的定位方法有两种
一是GPS定位:可以提供更加精确的位置信息,但定位速度和质量受到卫星数量和环境情况的影响;
二是网络定位:提供的位置信息精度差,但速度比GPS定位更快;
使用GPS定位,利用卫星提供精确的位置信息,需要添加android.permissions.ACCESS_FINE_LOCATION用户权限
使用网络定位,利用基站或Wi-Fi提供近似的位置信息,需要添加权限:
android.permission.ACCESS_COARSE_LOCATION或android.permission.ACCESS_FINE_LOCATION.
在指定LocationManager的定位方法后,则可以调用getLastKnowLocation()方法获取当前的位置信息
(3)通过调用Location中的getLatitude()和getLonggitude()方法可以分别获取位置信息中的纬度和经度
double lat = location.getLatitude(); double lng = location.getLongitude();
(4)LocationManager中的requestLocationUpdates()是监视位置移动的方法
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,1000, 0, locationListener);
其中第一个参数是设置服务提供者,第二个参数是周期,最后一个参数locationListener,它用来监听定位信息的改变。
/** * 监听定位信息的改变 */ private final LocationListener locationListener=new LocationListener(){ //当坐标改变时触发此函数 public void onLocationChanged(Location location) { updataNewLocation(location); } //GPS关闭时触发此函数 public void onProviderDisabled(String provider) { updataNewLocation(null); } //GPS打开时触发此函数 public void onProviderEnabled(String provider) { // TODO Auto-generated method stub } @Override public void onStatusChanged(String provider, int status, Bundle extras) { // TODO Auto-generated method stub } };
(5)测试
由于我们在模拟器上测试,所以需要人为设置一个坐标,我用的方法是通过DDMS。(有两种方法,另一种是通过命令行,我觉得很复杂,不好用),我们可以在Eclipse的ADT插件中使用这种方法,只要启动Eclipse,选择“Window”->“Show View”,打开“Emulator Control”界面即可看到如下的设置窗口,我们可以手动或者通过KML和GPX文件来设置一个坐标。
最后做测试的时候可以把程序下载到自己手机上,进行实地测试。
测试结果:(以下地点显示的是长沙)
卫星视图 交通视图
-----------------------------------------
-----------------------------------------
实现定位的功能:(用模拟器模拟位置的改变)
初始位置中国长沙-------------------------》改变坐标,我瞬间到了韩国首尔…
六、说明
这只是一个很简单的个人移动地图,只能进行一些地图的查看和位置的定位。据说真正的导航软件(可以自动生成驾车或者乘车路线)的算法要用到几何,概率等高级的数据处理方式,需要很多人力物力财力。
七、个人总结
搞这个东西花了两个星期左右。由于刚刚才开始Android方面的学习没多久,所以搞起来还有点吃力。期间在网上查找了大量关于Google Maps 的文档资料以及视频,虽然最后出来的效果跟预计有点差距而且程序中间还有有点bug,但是自己是用心并且花了时间去做的,所以并不觉得可惜。希望以后有时间会想办法再去完善它。还有一点,研究自己感兴趣的东西,它的动力是无穷的……
八、主要代码:
package cn.hpw.map.activity; import java.io.IOException; import java.util.List; import java.util.Locale; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Point; import android.location.Address; import android.location.Criteria; import android.location.Geocoder; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.widget.TextView; import com.google.android.maps.GeoPoint; import com.google.android.maps.MapActivity; import com.google.android.maps.MapController; import com.google.android.maps.MapView; import com.google.android.maps.Overlay; public class Map02Activity extends MapActivity { /** Called when the activity is first created. */ public MapView mapview;//地图控件 public MapController mapcontrol;//控制器 public MyLocationOverlay myPosition;//显示标记的图层 private GeoPoint mapgeopoint;//地图起点 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //取得LocationManager实例 LocationManager locationManager; String context=Context.LOCATION_SERVICE; locationManager=(LocationManager)getSystemService(context); mapview = (MapView)findViewById(R.id.MapView01); //取得MapController实例,控制地图 mapcontrol=mapview.getController(); // //设置地图起点 // mapgeopoint=new GeoPoint((int)(28.19*1E6),(int)(112.98*1000000)); // //定位到起点位置 // mapcontrol.animateTo(mapgeopoint); //设置显示模式 mapview.setTraffic(true); // mapview.setSatellite(true); // mapview.setStreetView(true); //设置地图支持缩放 mapview.setBuiltInZoomControls(true); //设置使用MyLocationOverlay来绘图 mapcontrol.setZoom(12); myPosition = new MyLocationOverlay(); List<Overlay> overlays=mapview.getOverlays(); overlays.add(myPosition); //设置Criteria服务商的信息 Criteria criteria = new Criteria(); //经度要求 criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setAltitudeRequired(false); criteria.setBearingRequired(false); criteria.setCostAllowed(false); criteria.setPowerRequirement(Criteria.POWER_LOW); //取得效果最好的criteria String provider=locationManager.getBestProvider(criteria, true); //得到坐标的相关信息 Location location=locationManager.getLastKnownLocation(provider); //更新坐标 updataNewLocation(location); //注册一个周期性的更新,3000ms更新一次 //用locationListener来监听定位信息的改变 locationManager.requestLocationUpdates(provider, 3000, 0, locationListener); } //更新坐标的方法 private void updataNewLocation(Location location) { String latLongString; TextView myLocationText = (TextView)findViewById(R.id.text01); String addressString = "没有找到地址!"; if(location!=null){ //为绘制标志的类设置坐标 myPosition.setLocation(location); //取得经度和纬度 Double geoLat=location.getLatitude()*1E6; Double geoLong=location.getLongitude()*1E6; //将其转化为INT型 GeoPoint point = new GeoPoint(geoLat.intValue(),geoLong.intValue()); //定位到指定的坐标 mapcontrol.animateTo(point); double lat=location.getLatitude(); double lng=location.getLongitude(); latLongString="经度:"+lat+"\n纬度:"+lng; double latitude=location.getLatitude(); double longtitude=location.getLongitude(); //根据地理环境来确定编码 Geocoder gc=new Geocoder(this,Locale.getDefault()); //取得与地址相关的一些信息、经度、纬度 try { List<Address> addresses=gc.getFromLocation(latitude, longtitude, 1); StringBuilder sb=new StringBuilder(); if(addresses.size()>0){ Address address = addresses.get(0); for(int i=0;i<address.getMaxAddressLineIndex();i++){ sb.append(address.getAddressLine(i)).append("\n"); sb.append(address.getLocality()).append("\n"); sb.append(address.getPostalCode()).append("\n"); sb.append(address.getCountryName()).append("\n"); addressString=sb.toString(); } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else{ latLongString="没有找到坐标,请检查网络设置!"; } //显示信息 myLocationText.setText("您当前的位置如下:\n"+latLongString+"\n"+addressString); System.out.println("您当前的位置如下:\n"+latLongString+"\n"+addressString); } /** * 监听定位信息的改变 */ private final LocationListener locationListener=new LocationListener(){ //当坐标改变时触发此函数 public void onLocationChanged(Location location) { updataNewLocation(location); } //GPS关闭时触发此函数 public void onProviderDisabled(String provider) { updataNewLocation(null); } //GPS打开时触发此函数 public void onProviderEnabled(String provider) { // TODO Auto-generated method stub } @Override public void onStatusChanged(String provider, int status, Bundle extras) { // TODO Auto-generated method stub } }; //是否显示路径信息 protected boolean isRouteDisplayed() { // TODO Auto-generated method stub return false; } /** * * 用来标记的Overlay图层 * */ class MyLocationOverlay extends Overlay{ Location mylocation; /** * 在更新坐标时,设置该坐标,以便画图 * @param location */ public void setLocation(Location location){ mylocation = location; } //绘制地图标记显示的内容 public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) { // TODO Auto-generated method stub super.draw(canvas, mapView, shadow, when); Paint paint = new Paint(); Point myScreen = new Point(); //将经纬度转换成实际的屏幕坐标 GeoPoint tmp = new GeoPoint((int)(mylocation.getLatitude()*1E6),(int)(mylocation.getLongitude()*1E6)); mapView.getProjection().toPixels(tmp, myScreen); paint.setStrokeWidth(1); //设置标记点的颜色 paint.setARGB(255, 255, 0, 0); paint.setStyle(Paint.Style.STROKE); //把我的照片加上去,嘿嘿…… Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.me); canvas.drawBitmap(bmp, myScreen.x, myScreen.y,paint); canvas.drawText("我的位置", myScreen.x, myScreen.y,paint); return true; } } }
再慢慢研究
有时候,我们希望表单中的文本框是只读的,让用户不能修改其中的信息,如使<input type="text" name="input1" value="中国"> 的内容,"中国"两个字不可以修改。实现的方式归纳一下,有如下几种。
方法1: onfocus=this.blur()
<input type="text" name="input1" value="中国" onfocus=this.blur()>
方法2:readonly
<input type="text" name="input1" value="中国" readOnly>
<input type="text" name="input1" value="中国" readOnly="true">
方法3: disabled
<input type="text" name="input1" value="中国" disabled="true">