步骤一:
GoogleMap环境准备。
Android系统默认并不支持调用Google Map,为正常调用Google Map服务,需要先进行如下准备工作。
1)获取Map API Key
单击Eclipse主菜单:Window —>Preferences —> 单击左侧“Android”—> Build —> 弹出如图1所示。
图1查看Android模拟器的Keystore
2)上图中显示的便是模拟器的keystore的存储位置,接下来应用程序需要根据该keystore来生成Google API的Key。
3)用JDK提供的keytool工具为Android keystore生成认证指纹,启动命令行窗口输入如下命令:
keytool –list –keystore
其中
图2指纹
注:默认密钥库口令是:android
就会得到MD5的指纹,记录下此记录:二十段用冒号割开的数字段,每段是两个十六进制的数(图2中红色删除线下的部分)。
4)在Google APIs Console上创建项目,并且注册Maps API。
首先,去这个网址:https://code.google.com/apis/console/
注:本文对申请API Key V2的说明是基于google developer console(上面的网址)网站旧版本的说明,现在已更新了,如果要返回旧版本可在打开网址后,选择旧版本。
用Gmail的账户登录,如果是第一次的话,需要创建项目,默认情况会创建一个叫做APIProject的项目。
登陆之后出现页面(如图3所示):
图3创建APIProject工程
单击“Createproject...”后到达页面(如图4所示):
图4 服务页面
点击左边的Services,会在中间看到很多的APIs和Services,找到GoogleMaps Android API v2,然后把它设置成on,需要接受一些服务条款,如图5所示。
图5 开启的服务页面
之后跳转到页面,如图6所示:
图6 同意条款
勾选同意条款,单击接受按钮。
5)获得API Key
在左边的导航条中选择API Access(如图7)。
图7 导航栏
在出来的页面中选择Create New Android Key...就可以生成key了(如图8所示)。
图8 生成Key
然后在对话框中填入:SHA-1 指纹,分号隔开,然后是应用的 package name.然后就会生成一个Key,如图9所示。图9 生成自己的Key操作图
最后生成的API Key如图10所示:
图10 生成的API Key
步骤二:
把API Key加入应用程序。
1)首先,新建Android应用程序。创建应用程序时,注意包名应该和申请key时候的包名一致。
2)之后修改AndroidManifest.xml文件,在
注:其中your_api_key置换成自己申请的API Key。
在该文件中加入一些许可信息,允许必要的权限。
注:其中com.example.mapdemo换成自己的包名。
步骤三:
AndroidManifest.xml文件中的其他的选项设置。
1)许可设置
2)OpenGL ES V2特性支持(作为
步骤四:
在布局文件中加上地图。
遇到的问题和解决的方法。
程序编译错误,显示找不到一些类,如图11所示。
图11 错误提示信息
解决这个问题,首先需要把Google Play services的类库加载进来:
在Eclipse里面选择:File > Import >Android > Existing Android Code Into Workspace然后点击Next。
之后Browse..., 找到路径下的
添加对这个库的引用:在自己的项目上右键,选Properties,左边选Android,然后在下面的Library里面Add刚才的google-play-services_lib,如图12所示。
图12 引用类库步骤图
之后运行程序就应该出来地图了。运行过程中,有可能会碰到下面的问题:程序运行成功,但是显示This app won't run unlessyou update Google Play services,如图13所示。需要点击Update,按照提示操作。
图13 提示界面
图14 运行结果图
注:
因为MapFragment只在API 12及之后的版本才有,所以对于之前的版本需要使用Support Library来进行辅助。
如果minSdkVersion设置为12以前的,就需要使用Support Library。
需要更改的地方是:布局文件中,把MapFragment改为SupportMapFragment。
MainActivity继承自FragmentActivity而不是Activity。(需要import android.support.v4. app.FragmentActivity;)。
步骤五:
新建工程GoogleMapTest,包名为com.example.googlemaptest,将一张名为pos.png的图片导入到drawable目录下,用于标注当前的位置。项目中Activity的名字为MainActivity.java,对应的布局文件名字为activity_main.xml,布局文件中包括2个输入框,用于接收用户输入的经纬度信息,有1个按钮,用于根据用户输入的经纬度定位具体位置;有两个单选按钮,分别显示普通地图和卫星地图;有1个地图组件。该工程目录结构及布局文件界面如图15所示:
图15 工程目录结构图
步骤六:
编辑地图组件对应的布局文件googlemap.xml,主要代码如下。
注:此文件中,class属性以下的几行代码,是用于设置地图的一些属性,这部分内容不是必须的,可以根据自己的需要进行设置,也可以都不设置,而在Activity中使用代码进行设置。
当在XML文件中加入这些map属性的设置时,必须要添加命名空间:“xmlns:map="http://schemas.android.com/apk/res-auto"”,并且该XML文件中不能再加入其它的组件,例如编辑框,甚至不能为其添加容器,例如LinearLayout。如果设置了这些属性,并且还想添加其它组件,就需要将该XML文件作为主XML布局文件的一部分,通过
如果不在XML文件中设置这些map属性的话,该XML文件可以不添加命名空间,并且可以在此文件中添加其它的组件。
步骤七:
编写主布局文件:activity_main.xml,采用线性布局并将上面的地图组件对应的XML文件(googlemap.xml)包含进来。
步骤八:
编写Activity文件,MainActivity.java。
声明各组件及必要的类。
//定义界面上的可视化组件 private Button btn_loc; private EditText edt_lng, edt_lat; private RadioGroup rg_mapType; GoogleMap mMap; private CameraPosition cameraPosition; private MarkerOptions markerOpt; //定义LocationManager对象 private LocationManager locManager; private Location location; private String bestProvider;
在onCreate()方法中获取各组件,并给按钮注册事件监听器,实现地理位置的实时定位。
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //获取用户界面的组件 findViews(); //创建LocationManager对象,并获取Provider initProvider(); //取得地图组件 mMap = ((MapFragment)getFragmentManager() .findFragmentById(R.id.mapView)).getMap(); mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL); //更新位置信息 updateToNewLocation(location); //给按钮添加监听器 btn_loc.setOnClickListener(new MapClickedListener()); //为RadioGroup的选中状态改变添加监听器 rg_mapType.setOnCheckedChangeListener(new ChangeMapTypeListener()); // 设置监听器,自动更新的最小时间为间隔N秒(1秒为1*1000,这样写主要为了方便)或最小位移变化超过N locManager.requestLocationUpdates(bestProvider, 3 * 1000, 8 , new LocationListener() { //当Provider的状态改变时 @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { // 当GPS LocationProvider可用时,更新位置 location = locManager.getLastKnownLocation(provider); } @Override public void onProviderDisabled(String provider) { updateToNewLocation(null); } @Override public void onLocationChanged(Location location) { // 当GPS定位信息发生改变时,更新位置 updateToNewLocation(location); } }); } private void initProvider() { //创建LocationManager对象 locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); // List all providers: Listproviders = locManager.getAllProviders(); Criteria criteria = new Criteria(); bestProvider = locManager.getBestProvider(criteria, false); location = locManager.getLastKnownLocation(bestProvider); System.out.println("经度:"+location.getLatitude()+"纬度:" + location.getLongitude()); } //获取用户界面组件 private void findViews() { //获取界面上的两个按钮 btn_loc = (Button) findViewById(R.id.btn_loc); //获取界面上的两个文本框 edt_lng = (EditText) findViewById(R.id.edt_lng); edt_lat = (EditText) findViewById(R.id.edt_lat); //获得RadioGroup rg_mapType = (RadioGroup) findViewById(R.id.rg_mapType); }
实现各个事件监听器类。
//定位按钮的点击事件监听器 private class MapClickedListener implements OnClickListener{ //根据用户输入经纬度定位 @Override public void onClick(View v) { //获取用户输入的经纬度 String lng = edt_lng.getText().toString().trim(); String lat = edt_lat.getEditableText().toString().trim(); if(lng.equals("") || lat.equals("")){ Toast.makeText(getApplicationContext(), "请输入有效的经纬度信息! ", Toast.LENGTH_LONG).show(); location = locManager.getLastKnownLocation(bestProvider); updateToNewLocation(location); }else{ location.setLongitude(Double.parseDouble(lng)); location.setLatitude(Double.parseDouble(lat)); //调用方法更新地图定位信息 updateToNewLocation(location); } } } private class ChangeMapTypeListener implements OnCheckedChangeListener{ @Override public void onCheckedChanged(RadioGroup group, int checkedId) { switch(checkedId){ case R.id.rb_nomal://如果勾选的是"正常视图"的单选按钮 mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL); break; case R.id.rb_satellite://如果勾选的是"卫星视图"的单选按钮 mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID); break; } } }
实现更新位置信息的方法。
private void updateToNewLocation(Location location){ mMap.clear(); //Marker1 markerOpt = new MarkerOptions(); double dLong = 114.51500; double dLat = 38.042000; if(location != null){ //获取经度 dLong = location.getLongitude(); //获取纬度 dLat = location.getLatitude(); } markerOpt.position(new LatLng(dLat, dLong)); markerOpt.draggable(false); markerOpt.visible(true); markerOpt.anchor(0.5f, 0.5f);//设为图片中心 markerOpt.icon(BitmapDescriptorFactory.fromResource(R.drawable.pos)); mMap.addMarker(markerOpt); //将摄影机移动到指定的地理位置 cameraPosition = new CameraPosition.Builder() .target(new LatLng(dLat, dLong)) .zoom(15) // 缩放比例 .bearing(0) // Sets the orientation of the camera to east .tilt(30) // Sets the tilt of the camera to 30 degrees .build();// Creates a CameraPosition from the builder mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); }
步骤九:
编辑AndroidManifest.xml,需要添加必要的权限及所申请的API Key。
android:value="你申请的API Key值 " />
步骤十:
运行改项目,测试定位功能。
注:由于本项目提取历史定位数据,所以首次使用,在没有历史数据的情况下会闪退,这是因为第一次获取GPS的时候没有历史数据,location = locManager.getLastKnownLocation(provider)这条语句获取不到历史数据造成的,常见的解决办法有如下几种:
1. 循环获取定位数据,直到获取到经纬度为止。该方法的缺点是获取不到数据时会进入死循环。
while(location == null){ lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 30000, 1, new LocListener()); }
2. 优先采用NETWORK_PROVIDER,该Provider比GPS_PROVIDER的稳定性好。
3. 读取定位数据之前,先让程序获取定位数据,给程序预留一定的时间,因为定位数据不一定一次性获取成功,这和位置、手机软硬件有关。
4. 偷懒的方法是使用其他的软件如百度地图,首先获取到定位数据,有历史数据了以后再运行该程序。
5. 在程序中给定初始化的经纬度数据。
附录:
新版本中对于已申请的API Key可以服务于多个包,直接添加就可以了。
新版本的谷歌开发网左侧的列表中,点击APIs & auth下的APIs,会显示所开启的服务。
左侧的列表如下图所示
点击Credentials列表可申请新的API Key,如下图示。
点击“CREATE NEW KEY”可申请新的Key,点击“Edit allowed Android applications”可编辑已有的API Key,也可使用已有Key,支持更多的服务,如下图所示。
直接在框中添加Key所支持的包名即可,需要注意的是,Key与包名之间要命“;”隔开。之后点击“Update”按钮。
到此结束,希望对大家有帮助。
以上纯属个人观点,供新手交流学习。欢迎高手及大神批评指正。