本系列教程將分為兩部分,第一部分是指導用戶使用Mapview控件進行編程,其中包括了如何獲得Google Map API,如何使用該API進行簡單的開發,如何獲得用戶當前所在的位置。第二部分則包括如何在地圖上,用第三方的組件庫,實現氣球式顯示若干指定位置的功能。
步驟1 創建新的Android 工程
首先打開eclipse新建立一個Android 工程,其中相關參數設置如下:
Project name:MallFinder
Build Target: Google APIs Platform – 2.1 API Level 7
Application Name: Mall Finder
Package Name: com.shawnbe.mallfinder
Create Activity: MallFinderActivity
MinimumSDK: 7
如下圖所示:
步驟2 注冊Google Map API key
由於在使用google map的時候,需要使用google map api的key,因此需要先注冊一個開發者key,可以到如下地址進行注冊:http://code.google.com/android/add-ons/google-apis/mapkey.html ,其中需要我們先產生開發期間的md5 密紋才能完成注冊,因此我們先學習如何生成一個MD5密紋。
我們需要使用keytool工具,不使用傳統的命令行方式下那枯燥的證書簽名生成辦法,而是直接在eclipse下通過插件進行完成,詳細見步驟3
步驟3 安裝keytool插件
在eclipse的Help菜單中,如下圖,選擇安裝新軟件:
在安裝地址中輸入如下地址:http://www.keytool.sourceforge.net/update ,如下圖
接下來會加載相關的安裝程序,並顯示用戶協議,選擇接受所有用戶協議后進行安裝,安裝成功后重新啟動eclipse即可生效。
步驟4 產生開發期間的MD5密鑰
在重新啟動eclipse后,會發現工具欄多了如下圖的keytool菜單
現在,我們打開debug.keystore,注意其位置回因操作系統不同而有不同
Windows Vista : C:\Users\\.android\debug.keystore
Windows XP : C:\Documents and Settings\\.android\debug.keystore
OS X 和 Linux : ~/.android/debug.keystore
點keytool菜單中,選擇open keystore,根據提示,選擇當前系統所在的debug.keystore位置並打開,如下圖,
其中,輸入密碼默認為android即可,並點Load加載。之后會在eclipse中出現新的keytool的視圖,如下圖所示:
雙擊打開androiddebugkey,復制其md5密紋,然后訪問頁面
http://code.google.com/android/maps-api-signup.html ,接受其協議,將md5密紋復制進去,再點Generate API Key,即產生google map的api key,記得保存好這個KEY,在接下來的步驟中要使用。
步驟5 增加MapView控件
接下來,我們可以往布局文件中增加MapView控件。我們在main.xml中添加如下代碼:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.google.android.maps.MapView
android:id="@+id/mapView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true"
android:apiKey="你的GOOGLE MAP API KEY "/>
</FrameLayout>
</LinearLayout>
在這個控件中,請注意要在android:apiKey的位置填入剛申請的google map api key。
步驟6 設置相關的權限
由於我們的應用需要調用Google Map的數據,以及通過手機的GPS獲得相關的其他地理位置數據,因此我們必須在Android的Manifest文件中進行權限的設置。
我們打開AndroidManifest.xml文件,然后增加如下代碼所示的權限設置,注意添加在標簽后,但要在標簽前。
<uses-feature android:name="android.hardware.location.gps"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.INTERNET"/>
在這里,我們分別調用了gps位置服務權限,使用互聯網的權限以及使用最佳位置查找的權限(FINE_LOCATION)。在本文中,其實沒用到FINE_LOCATION,但只是告訴開發者可以調整使用不同的地理位置提供者(providers)以提供准確的位置服務,如果要有比較精確的地理位置服務,那么可以設置android.permisson.ACCESS_FINE_LOCATION服務。要注意的是在開發中,不要過多引用一些不需要使用的權限設置,否則會給用戶帶來擔憂安全等問題。要是只想調用一般的位置服務,可以使用普通的android.permission.ACCESS_COARSE_LOCATION權限。
為了在應用中使用Google Map,需要在Manifest文件中包含相關的類庫文件,所以加入如下代碼:
<uses-library android:required="true" android:name="com.google.android.maps" />
為了視覺的美觀,我們把標題欄也去掉,以便留給地圖更大的空間,所以設置為
android:theme="@android:style/Theme.NoTitleBar"
下面是完整的Manifest文件代碼:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.shawnbe.mallfinder"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="7" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar">
<activity
android:label="@string/app_name"
android:name=".MallFinderActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<uses-library android:required="true" android:name="com.google.android.maps" />
</application>
<uses-feature android:name="android.hardware.location.gps"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
步驟7 設置MapView
下面對主activity程序(MallFinderActivity.java)進行修改,首先讓其繼承MapActivity類,如下:
public class MallFinderActivity extends MapActivity {
由於繼承了MapActivity類,因此必須實現isRouteDisplayed方法,這個方法是用來做路線導航用的,這里我們不需要,因此只需要簡單返回false即可:
@Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}
接下來我們就可以聲明MapController控件,並對其進行相關屬性的設置了,首先是聲明控件
private MapController mapController;
private MapView mapView;
並在oncreate方法中進行屬性設置如下:
mapView = (MapView)findViewById(R.id.mapView);
mapView.setBuiltInZoomControls(true);
mapView.setSatellite(false);
mapView.setStreetView(true);
mapController = mapView.getController();
mapController.setZoom(13);
在上面的代碼中,設置了地圖顯示的方式為街道模式(通過設置mapview的setStreetView屬性值為true),並且通過mapView.setBuiltInZoomControls(true); 使用了系統內置的放大縮小功能,並設置了地圖的放大縮小倍數為13。
這個時候我們就可以選擇運行應用,看下是否符合我們的初步預期效果,運行后效果如下圖:
步驟8 獲得當前所在位置
在LBS應用中,十分重要的工作是要獲得當前設備所在的位置,這個可以使用locationManager類實現,在獲得當前位置的時候是需要花費一些時間的。我們繼續聲明兩個參數變量如下:
private LocationManager locationManager;
private GeoPoint currentLocation;
分別聲明了LocationManager類的實例和GeoPoint類的實例(用於下文中的經緯度的計算)。
再增加如下幾個方法:
public void getLastLocation(){
String provider = getBestProvider();
currentLocation = locationManager.getLastKnownLocation(provider);
if(currentLocation != null){
setCurrentLocation(currentLocation);
}
else
{
Toast.makeText(this, "Location not yet acquired", Toast.LENGTH_LONG).show();
}
}
public void animateToCurrentLocation(){
if(currentPoint!=null){
mapController.animateTo(currentPoint);
}
}
public String getBestProvider(){
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
criteria.setPowerRequirement(Criteria.NO_REQUIREMENT);
criteria.setAccuracy(Criteria.NO_REQUIREMENT);
String bestProvider = locationManager.getBestProvider(criteria, true);
return bestProvider;
}
public void setCurrentLocation(Location location){
int currLatitude = (int) (location.getLatitude()*1E6);
int currLongitude = (int) (location.getLongitude()*1E6);
currentLocation = new GeoPoint(currLatitude,currLongitude);
currentLocation = new Location("");
currentLocation.setLatitude(currentPoint.getLatitudeE6() / 1e6);
currentLocation.setLongitude(currentPoint.getLongitudeE6() / 1e6);
}
並且在oncreate方法中,添加對以上方法的調用代碼如下:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mapView = (MapView)findViewById(R.id.mapView);
mapView.setBuiltInZoomControls(true);
mapView.setSatellite(false);
mapView.setStreetView(true);
mapController = mapView.getController();
mapController.setZoom(13);
getLastLocation();
animateToCurrentLocation();
}
首先,在getLastLocation這個方法中,創建了locationManager類的實例並且根據設置的條件返回一個合適的地理位置提供方法。在這里,我們並沒有指定對地理位置提供者的查詢條件,在實際應用中,開發者可以通過設置criteria.setAccuracy()和criteria.setPowerRequirement()方法進行查找。如果要使用最精確的provider的話,可以設置使用ACCURACY_FINE方法進行搜索,如下代碼所示:
criteria.setAccuracy(Criteria.ACCURACY_FINE);
在本文中之所以不選擇使用最准確的位置provider主要是因為是沒在室外進行測試,都是在室內調試程序,建議開發完后換成GPS模式provider到室外進行調試那樣將看到很好的效果。
接下來代碼中使用 currentLocation = locationManager.getLastKnownLocation(provider); 一句,獲得最新的位置信息,並且在setCurrentLocation方法中,對通過prodiver獲得的地理位置信息Location對象進行經緯度的轉換為GeoPoint對象。然后調用animateToCurrentLocation方法,將地圖的中心點定位到我們當前的位置上去。
此外,由於我們的位置是會發生變化的,所以需要使用location 監聽器去檢測我們的位置變化,這時需要實現locationListener接口,如下所示:
public class MallFinderActivity extends MapActivity implements LocationListener{
同時我們需要實現LocationListener類的以下幾個方法:
@Override
public void onLocationChanged(Location arg0) {
// TODO Auto-generated method stub
}
@Override
public void onProviderDisabled(String arg0) {
// TODO Auto-generated method stub
}
@Override
public void onProviderEnabled(String arg0) {
// TODO Auto-generated method stub
}
@Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
// TODO Auto-generated method stub
}
其中這里我們關心的是需要實現onLocationChanged方法,這里我們調用之前編寫好的setlocation方法,獲得當前的最新位置,如下:
@Override
public void onLocationChanged(Location newLocation) {
// TODO Auto-generated method stub
setCurrentLocation(newLocation);
}
為了完善程序,在程序處在onResume及onPause狀態下都能及時更新地理位置信息以及取消更新,加上如下代碼:
@Override
protected void onResume() {
super.onResume();
locationManager.requestLocationUpdates(getBestProvider(), 1000, 1, this);
}
@Override
protected void onPause() {
super.onPause();
locationManager.removeUpdates(this);
}
小結
在本系列的第一講中,分步講解了如何注冊Google API KEY以及Mapview控件基本方法的使用,還有讓讀者了解到使用google map的初步步驟,在下一講中,將指導讀者如何對地圖上的位置進行標注。
本系列教程將分為兩部分,第一部分是指導用戶使用Mapview控件進行編程,其中包括了如何獲得Google Map API,如何使用該API進行簡單的開發,如何獲得用戶當前所在的位置。第二部分則包括如何在地圖上,用第三方的組件庫,實現氣球式顯示若干指定位置的功能。
步驟1 創建新的Android 工程
首先打開eclipse新建立一個Android 工程,其中相關參數設置如下:
Project name:MallFinder
Build Target: Google APIs Platform – 2.1 API Level 7
Application Name: Mall Finder
Package Name: com.shawnbe.mallfinder
Create Activity: MallFinderActivity
MinimumSDK: 7
如下圖所示:
步驟2 注冊Google Map API key
由於在使用google map的時候,需要使用google map api的key,因此需要先注冊一個開發者key,可以到如下地址進行注冊:http://code.google.com/android/add-ons/google-apis/mapkey.html ,其中需要我們先產生開發期間的md5 密紋才能完成注冊,因此我們先學習如何生成一個MD5密紋。
我們需要使用keytool工具,不使用傳統的命令行方式下那枯燥的證書簽名生成辦法,而是直接在eclipse下通過插件進行完成,詳細見步驟3
步驟3 安裝keytool插件
在eclipse的Help菜單中,如下圖,選擇安裝新軟件:
在安裝地址中輸入如下地址:http://www.keytool.sourceforge.net/update ,如下圖
接下來會加載相關的安裝程序,並顯示用戶協議,選擇接受所有用戶協議后進行安裝,安裝成功后重新啟動eclipse即可生效。
步驟4 產生開發期間的MD5密鑰
在重新啟動eclipse后,會發現工具欄多了如下圖的keytool菜單
現在,我們打開debug.keystore,注意其位置回因操作系統不同而有不同
Windows Vista : C:\Users\\.android\debug.keystore
Windows XP : C:\Documents and Settings\\.android\debug.keystore
OS X 和 Linux : ~/.android/debug.keystore
點keytool菜單中,選擇open keystore,根據提示,選擇當前系統所在的debug.keystore位置並打開,如下圖,
其中,輸入密碼默認為android即可,並點Load加載。之后會在eclipse中出現新的keytool的視圖,如下圖所示:
雙擊打開androiddebugkey,復制其md5密紋,然后訪問頁面
http://code.google.com/android/maps-api-signup.html ,接受其協議,將md5密紋復制進去,再點Generate API Key,即產生google map的api key,記得保存好這個KEY,在接下來的步驟中要使用。
步驟5 增加MapView控件
接下來,我們可以往布局文件中增加MapView控件。我們在main.xml中添加如下代碼:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.google.android.maps.MapView
android:id="@+id/mapView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true"
android:apiKey="你的GOOGLE MAP API KEY "/>
</FrameLayout>
</LinearLayout>
在這個控件中,請注意要在android:apiKey的位置填入剛申請的google map api key。
步驟6 設置相關的權限
由於我們的應用需要調用Google Map的數據,以及通過手機的GPS獲得相關的其他地理位置數據,因此我們必須在Android的Manifest文件中進行權限的設置。
我們打開AndroidManifest.xml文件,然后增加如下代碼所示的權限設置,注意添加在標簽后,但要在標簽前。
<uses-feature android:name="android.hardware.location.gps"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.INTERNET"/>
在這里,我們分別調用了gps位置服務權限,使用互聯網的權限以及使用最佳位置查找的權限(FINE_LOCATION)。在本文中,其實沒用到FINE_LOCATION,但只是告訴開發者可以調整使用不同的地理位置提供者(providers)以提供准確的位置服務,如果要有比較精確的地理位置服務,那么可以設置android.permisson.ACCESS_FINE_LOCATION服務。要注意的是在開發中,不要過多引用一些不需要使用的權限設置,否則會給用戶帶來擔憂安全等問題。要是只想調用一般的位置服務,可以使用普通的android.permission.ACCESS_COARSE_LOCATION權限。
為了在應用中使用Google Map,需要在Manifest文件中包含相關的類庫文件,所以加入如下代碼:
<uses-library android:required="true" android:name="com.google.android.maps" />
為了視覺的美觀,我們把標題欄也去掉,以便留給地圖更大的空間,所以設置為
android:theme="@android:style/Theme.NoTitleBar"
下面是完整的Manifest文件代碼:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.shawnbe.mallfinder"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="7" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar">
<activity
android:label="@string/app_name"
android:name=".MallFinderActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<uses-library android:required="true" android:name="com.google.android.maps" />
</application>
<uses-feature android:name="android.hardware.location.gps"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
步驟7 設置MapView
下面對主activity程序(MallFinderActivity.java)進行修改,首先讓其繼承MapActivity類,如下:
public class MallFinderActivity extends MapActivity {
由於繼承了MapActivity類,因此必須實現isRouteDisplayed方法,這個方法是用來做路線導航用的,這里我們不需要,因此只需要簡單返回false即可:
@Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}
接下來我們就可以聲明MapController控件,並對其進行相關屬性的設置了,首先是聲明控件
private MapController mapController;
private MapView mapView;
並在oncreate方法中進行屬性設置如下:
mapView = (MapView)findViewById(R.id.mapView);
mapView.setBuiltInZoomControls(true);
mapView.setSatellite(false);
mapView.setStreetView(true);
mapController = mapView.getController();
mapController.setZoom(13);
在上面的代碼中,設置了地圖顯示的方式為街道模式(通過設置mapview的setStreetView屬性值為true),並且通過mapView.setBuiltInZoomControls(true); 使用了系統內置的放大縮小功能,並設置了地圖的放大縮小倍數為13。
這個時候我們就可以選擇運行應用,看下是否符合我們的初步預期效果,運行后效果如下圖:
步驟8 獲得當前所在位置
在LBS應用中,十分重要的工作是要獲得當前設備所在的位置,這個可以使用locationManager類實現,在獲得當前位置的時候是需要花費一些時間的。我們繼續聲明兩個參數變量如下:
private LocationManager locationManager;
private GeoPoint currentLocation;
分別聲明了LocationManager類的實例和GeoPoint類的實例(用於下文中的經緯度的計算)。
再增加如下幾個方法:
public void getLastLocation(){
String provider = getBestProvider();
currentLocation = locationManager.getLastKnownLocation(provider);
if(currentLocation != null){
setCurrentLocation(currentLocation);
}
else
{
Toast.makeText(this, "Location not yet acquired", Toast.LENGTH_LONG).show();
}
}
public void animateToCurrentLocation(){
if(currentPoint!=null){
mapController.animateTo(currentPoint);
}
}
public String getBestProvider(){
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
criteria.setPowerRequirement(Criteria.NO_REQUIREMENT);
criteria.setAccuracy(Criteria.NO_REQUIREMENT);
String bestProvider = locationManager.getBestProvider(criteria, true);
return bestProvider;
}
public void setCurrentLocation(Location location){
int currLatitude = (int) (location.getLatitude()*1E6);
int currLongitude = (int) (location.getLongitude()*1E6);
currentLocation = new GeoPoint(currLatitude,currLongitude);
currentLocation = new Location("");
currentLocation.setLatitude(currentPoint.getLatitudeE6() / 1e6);
currentLocation.setLongitude(currentPoint.getLongitudeE6() / 1e6);
}
並且在oncreate方法中,添加對以上方法的調用代碼如下:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mapView = (MapView)findViewById(R.id.mapView);
mapView.setBuiltInZoomControls(true);
mapView.setSatellite(false);
mapView.setStreetView(true);
mapController = mapView.getController();
mapController.setZoom(13);
getLastLocation();
animateToCurrentLocation();
}
首先,在getLastLocation這個方法中,創建了locationManager類的實例並且根據設置的條件返回一個合適的地理位置提供方法。在這里,我們並沒有指定對地理位置提供者的查詢條件,在實際應用中,開發者可以通過設置criteria.setAccuracy()和criteria.setPowerRequirement()方法進行查找。如果要使用最精確的provider的話,可以設置使用ACCURACY_FINE方法進行搜索,如下代碼所示:
criteria.setAccuracy(Criteria.ACCURACY_FINE);
在本文中之所以不選擇使用最准確的位置provider主要是因為是沒在室外進行測試,都是在室內調試程序,建議開發完后換成GPS模式provider到室外進行調試那樣將看到很好的效果。
接下來代碼中使用 currentLocation = locationManager.getLastKnownLocation(provider); 一句,獲得最新的位置信息,並且在setCurrentLocation方法中,對通過prodiver獲得的地理位置信息Location對象進行經緯度的轉換為GeoPoint對象。然后調用animateToCurrentLocation方法,將地圖的中心點定位到我們當前的位置上去。
此外,由於我們的位置是會發生變化的,所以需要使用location 監聽器去檢測我們的位置變化,這時需要實現locationListener接口,如下所示:
public class MallFinderActivity extends MapActivity implements LocationListener{
同時我們需要實現LocationListener類的以下幾個方法:
@Override
public void onLocationChanged(Location arg0) {
// TODO Auto-generated method stub
}
@Override
public void onProviderDisabled(String arg0) {
// TODO Auto-generated method stub
}
@Override
public void onProviderEnabled(String arg0) {
// TODO Auto-generated method stub
}
@Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
// TODO Auto-generated method stub
}
其中這里我們關心的是需要實現onLocationChanged方法,這里我們調用之前編寫好的setlocation方法,獲得當前的最新位置,如下:
@Override
public void onLocationChanged(Location newLocation) {
// TODO Auto-generated method stub
setCurrentLocation(newLocation);
}
為了完善程序,在程序處在onResume及onPause狀態下都能及時更新地理位置信息以及取消更新,加上如下代碼:
@Override
protected void onResume() {
super.onResume();
locationManager.requestLocationUpdates(getBestProvider(), 1000, 1, this);
}
@Override
protected void onPause() {
super.onPause();
locationManager.removeUpdates(this);
}
小結
在本系列的第一講中,分步講解了如何注冊Google API KEY以及Mapview控件基本方法的使用,還有讓讀者了解到使用google map的初步步驟,在下一講中,將指導讀者如何對地圖上的位置進行標注。