步驟一:
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 <Android keystore的存儲位置>
其中<Android keystore的存儲位置>要替換成圖1中Androidkeystore的存儲位置,如:Keytool -list -keystore "D:\Program Files\android-sdks \.android\debug.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文件,在<application>元素中加入子標籤。
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="your_api_key" />
注:其中your_api_key置換成自己申請的API Key。
在該文件中加入一些許可信息,允許必要的權限。
<permission android:name="com.example.mapdemo.permission.MAPS_RECEIVE" android:protectionLevel="signature"/> <uses-permission android:name="com.example.mapdemo.permission.MAPS_RECEIVE"/>
注:其中com.example.mapdemo換成自己的包名。
步驟三:
AndroidManifest.xml文件中的其他的選項設置。
1)許可設置
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICE S"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
2)OpenGL ES V2特性支持(作爲<manifest> 的子元素)
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
步驟四:
在佈局文件中加上地圖。
<fragment xmlns:android=http://schemas.android.com/apk/res/android android:id="@+id/map" android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.MapFragment"/>
遇到的問題和解決的方法。
程序編譯錯誤,顯示找不到一些類,如圖11所示。
圖11 錯誤提示信息
解決這個問題,首先需要把Google Play services的類庫加載進來:
在Eclipse裏面選擇:File > Import >Android > Existing Android Code Into Workspace然後點擊Next。
之後Browse..., 找到路徑下的<android-sdk-folder>/extras/google/google_play_services/ libproject/google-play-services_lib,然後選擇Finish。
添加對這個庫的引用:在自己的項目上右鍵,選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,主要代碼如下。
<?xml version="1.0" encoding="utf-8"?> <fragment xmlns:android="http://schemas.android.com/apk/res/android" xmlns:map="http://schemas.android.com/apk/res-auto" android:id="@+id/mapView" android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.MapFragment" map:cameraBearing="45" map:cameraTargetLat="25.033611" map:cameraTargetLng="121.565000" map:cameraTilt="0" map:cameraZoom="13" map:uiCompass="true" map:mapType="normal" map:uiRotateGestures="true" map:uiScrollGestures="true" map:uiTiltGestures="true" map:uiZoomControls="false" map:uiZoomGestures="true" />
注:此文件中,class屬性以下的幾行代碼,是用於設置地圖的一些屬性,這部分內容不是必須的,可以根據自己的需要進行設置,也可以都不設置,而在Activity中使用代碼進行設置。
當在XML文件中加入這些map屬性的設置時,必須要添加命名空間:「xmlns:map="http://schemas.android.com/apk/res-auto"」,並且該XML文件中不能再加入其它的組件,例如編輯框,甚至不能爲其添加容器,例如LinearLayout。如果設置了這些屬性,並且還想添加其它組件,就需要將該XML文件作爲主XML佈局文件的一部分,通過<include>標籤包含在主佈局文件中。具體方法稍後具體說明。
如果不在XML文件中設置這些map屬性的話,該XML文件可以不添加命名空間,並且可以在此文件中添加其它的組件。
步驟七:
編寫主佈局文件:activity_main.xml,採用線性佈局並將上面的地圖組件對應的XML文件(googlemap.xml)包含進來。
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10dp" android:text="定位" android:textSize="15sp" /> <LinearLayout android:id="@+id/location" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:orientation="horizontal" > <!-- 定義輸入經度值的文本框 --> <EditText android:id="@+id/edt_lng" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ems="6" android:hint="經度" android:textSize="20sp" /> <!-- 定義輸入緯度值的文本框 --> <EditText android:id="@+id/edt_lat" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:ems="6" android:hint="緯度" android:textSize="20sp" /> <Button android:id="@+id/btn_loc" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:text="定位" android:textSize="15sp" /> </LinearLayout> <LinearLayout android:id="@+id/mapsChoice" android:layout_width="wrap_content" android:layout_height="wrap_content" > <!-- 定義選擇地圖類型的單選按鈕 --> <RadioGroup android:id="@+id/rg_mapType" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="horizontal" > <RadioButton android:id="@+id/rb_nomal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" android:text="普通視圖" /> <RadioButton android:id="@+id/rb_satellite" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="衛星視圖" /> </RadioGroup> </LinearLayout> </LinearLayout> <include android:id="@+id/googleMap" layout="@layout/googlemap" />
步驟八:
編寫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: List<String> providers = 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。
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" … > <uses-sdk … /> <!—下面的權限中,com.example.googlemaptest 要換成你的工程文件的包名--> <permission android:name="com.example.googlemaptest.permission.MAPS_RECEIVE" android:protectionLevel="signature"/> <uses-permission android:name="com.example.googlemaptest.permission.MAPS_RECEIVE"/> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/> <!—下面的兩條權限在API V2中是不要求的,但是在開發過程中建議添加 --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-feature android:glEsVersion="0x00020000" android:required="true"/> <application … > <activity android:name="com.example.googlemaptest.MainActivity" … </activity> <meta-data android:name="com.google.android.maps.v2.API_KEY" <!—下面的屬性值要求添加你申請的API Key值--> android:value="你申請的API Key值 " /> <uses-library android:required="true" android:name="com.google.android.maps" /> </application> </manifest>
步驟十:
運行改項目,測試定位功能。
注:由於本項目提取歷史定位數據,所以首次使用,在沒有歷史數據的情況下會閃退,這是因爲第一次獲取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」按鈕。
到此結束,希望對大家有幫助。
以上純屬個人觀點,供新手交流學習。歡迎高手及大神批評指正。