Android開發筆記-GPS與網路定位

內容說明:GPS定位、網路定位
資料來源:Android南部工作坊、Google!Android 2手機應用程式設計入門第三版

Android提供兩種定位方式,一種是GPS,另一種是網路定位。前者用於室外;後者用於室內。
首先要建立一個專案,如果未來想結合Google服務,可勾選Google APIs,詳細說明請參考Google地圖

設定使用權限
開啟AndroidManifest.xml,並且在</application>後面加入<uses-permission...>的權限。INTERNET是網路權限,ACCESS_FINE_LOCATION是GPS權限,ACCESS_COARSE_LOCATION是網路定位。

17
18
19
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>

加入顯示欄位
為了使定位的結果清楚可見,可以先在設定介面中加入變數與欄位,方便顯示定位的結果。本範例的string.xml程式碼如下:

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">GPS/網路定位</string>
    <string name="longitude_label">經度:</string>
    <string name="latitude_label">緯度:</string>
</resources>

main.xml程式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/longitude_label"
    />
<TextView  android:id="@+id/longitude"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text=""
    />
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/latitude_label"
    />
<TextView  android:id="@+id/latitude"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text=""
    />
</LinearLayout>

實作LocationListener介面
當定位座標改變時,我們希望系統也會自動抓取新的位置,所以必需使用LocationListener來傾聽位置的變化。開啟Java檔案,在class後面加入"implements LocationListener"實作介面,並且根據指示增加實作方法,產生的完整程式碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package moke.test;
 
import android.app.Activity;
import android.location.Location;
import android.location.LocationListener;
import android.os.Bundle;
 
public class main extends Activity implements LocationListener {
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
	}
 
	@Override
	public void onLocationChanged(Location arg0) {	//當地點改變時
		// TODO Auto-generated method stub
 
	}
 
	@Override
	public void onProviderDisabled(String arg0) {	//當GPS或網路定位功能關閉時
		// TODO Auto-generated method stub
 
	}
 
	@Override
	public void onProviderEnabled(String arg0) {	//當GPS或網路定位功能開啟
		// TODO Auto-generated method stub
 
	}
 
	@Override
	public void onStatusChanged(String arg0, int arg1, Bundle arg2) {	//定位狀態改變
		// TODO Auto-generated method stub
 
	}
}

使用LocationManager取得位置
無論是GPS或網路定位,我們都可以利用LocationManager輕易地幫使用者定位。首先我們要先確定使用者有開啟定位服務,因此請在onCreate()加入21~29行程式碼:

17
18
19
20
21
22
23
24
25
26
27
28
29
30
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
 
		//取得系統定位服務
		LocationManager status = (LocationManager) (this.getSystemService(Context.LOCATION_SERVICE));
		if (status.isProviderEnabled(LocationManager.GPS_PROVIDER) || status.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
			//如果GPS或網路定位開啟,呼叫locationServiceInitial()更新位置
			locationServiceInitial();
		} else {
			Toast.makeText(this, "請開啟定位服務", Toast.LENGTH_LONG).show();
			startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));	//開啟設定頁面
		}
	}

如果未來需要開啟系統其它的設定頁面,可以參考官方網站。接著,我們就要來實作locationServiceInitial()方法:

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
	private LocationManager lms;
	private void locationServiceInitial() {
		lms = (LocationManager) getSystemService(LOCATION_SERVICE);	//取得系統定位服務
		Location location = lms.getLastKnownLocation(LocationManager.GPS_PROVIDER);	//使用GPS定位座標
		getLocation(location);
	}
	private void getLocation(Location location) {	//將定位資訊顯示在畫面中
		if(location != null) {
			TextView longitude_txt = (TextView) findViewById(R.id.longitude);
			TextView latitude_txt = (TextView) findViewById(R.id.latitude);
 
			Double longitude = location.getLongitude();	//取得經度
			Double latitude = location.getLatitude();	//取得緯度
 
			longitude_txt.setText(String.valueOf(longitude));
			latitude_txt.setText(String.valueOf(latitude));
		}
		else {
			Toast.makeText(this, "無法定位座標", Toast.LENGTH_LONG).show();
		}
	}

取得最佳資訊提供者
Criteria物件是用來讓我們設定資訊提供者選取的標準。我們可以透過它設定精準度、電力、高度、速度、方位和金錢成本等因素作為選擇提供者的考量。locationServiceInitial()的修改如下。當我們在第36行建立一個新的Criteria物件時,因為沒有指定任何條件,所以選取提供者的準則就是沒有標準,誰都可以。到第37行時,使用getBestProvider來取得最佳提供者。如果候選人有很多位,它就會選擇精準度最高的;如果沒有符合標準的候選人,它就會依序根據電力、精準度、方位、速度或高度來選擇提供者。getBestProvider第二個參數一般都是「true」,表示如果系統只有啟用一個提供者,要不要使用它。

32
33
34
35
36
37
38
39
40
	private LocationManager lms;
	private String bestProvider = LocationManager.GPS_PROVIDER;	//最佳資訊提供者
	private void locationServiceInitial() {
		lms = (LocationManager) getSystemService(LOCATION_SERVICE);	//取得系統定位服務
		Criteria criteria = new Criteria();	//資訊提供者選取標準
		bestProvider = lms.getBestProvider(criteria, true);	//選擇精準度最高的提供者
		Location location = lms.getLastKnownLocation(bestProvider);
		getLocation(location);
	}

更新地點
在更新地點之前,我們必需先設定一個boolean getService參數,判斷定位服務是否已經開啟,這樣當使用者沒有開啟任何定位服務的時候,系統才不會出現錯誤。首先在onCreate()上方宣告一個boolean變數,並且在確定服務開啟時設定為true。

17
	private boolean getService = false;		//是否已開啟定位服務
25
26
27
28
29
		if (status.isProviderEnabled(LocationManager.GPS_PROVIDER) || status.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
			//如果GPS或網路定位開啟,呼叫locationServiceInitial()更新位置
			getService = true;	//確認開啟定位服務
			locationServiceInitial();
		...

接著,我們在onResume()開啟更新,並設定更新的頻率(為了讓我們在測式時快速有反應,所以設定成每秒更新1次,但快速的更新是很耗電的,實際使用時可以根據需求來設定)。當系統進入onPause()時,則停止更新(onResume與onPause請參考Android生命周期)。

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
	@Override
	protected void onResume() {
		// TODO Auto-generated method stub
		super.onResume();
		if(getService) {
			lms.requestLocationUpdates(bestProvider, 1000, 1, this);
			//服務提供者、更新頻率60000毫秒=1分鐘、最短距離、地點改變時呼叫物件
		}
	}
 
	@Override
	protected void onPause() {
		// TODO Auto-generated method stub
		super.onPause();
		if(getService) {
			lms.removeUpdates(this);	//離開頁面時停止更新
		}
	}

最後,我們希望畫面顯示的內容會隨著經緯度變化,所以請直接在onLocationChanged加入getLocation()。

79
80
81
82
83
	@Override
	public void onLocationChanged(Location location) {	//當地點改變時
		// TODO Auto-generated method stub
		getLocation(location);
	}

專案程式碼下載 (2014.05.14 新增)
由於來信索取程式碼的人很多,還是決定直接放上來提供下載。必須要提醒當初撰寫的版本是Android 2.3,現在已經有更新更好的寫法,並不建議使用。

下載連結請 按此

Share on Google+
You can follow any responses to this entry through the RSS 2.0 feed.You can leave a response, or trackback from your own site.
89 Responses
  1. ZH says:

    我做了以上的程式碼後,手機要一直反轉(重新更新)座標才會變,
    為什麼不能一直走座標就一直更變呢?
    可否跟你要完成的程式?tks
    49855902@stust.edu.tw

    • Davina says:

      如果onLocationChanged()確定有加入的話,可能是手機設定上的問題(省電之類的)
      程式碼的部份請來信索取。

  2. 阿剛 says:

    版主 你好 小弟是剛學Java的初學者 最近學校要我們做一個gps定位的程式 上來搜尋 並發現版主發的文 我想問的是 有完整的程式碼可以參考嗎? 慢慢看然後慢慢學 然後還有 我把程式碼打在記事本可以編譯跟執行嗎??

    • Davina says:

      GPS的部份可以來信索取。
      我是使用eclipse軟體,但最近看見App Inventor可以做出不錯的效果,如果是程式新手可以考慮由此入門。

  3. WMHSIAOYI says:

    你好 我想請問 那網頁本身可以嗎
    我知道(手機)網頁可以存取位置資訊

    可是 他不會自己開gps偵測 一定要有app開了 讓gps工作
    他才會一直收到資料

    請問這有解決方法嗎?

    感恩

    • Davina says:

      你的網頁是讓使用者用自已的瀏覽器開啟,還是在APP中嵌入一個網頁呢?
      如果是後者就比較好處理,直接在APP裡判斷GPS,確認後再開啟網頁的框架即可。
      前者的話要研究網頁端的程式,我們瀏覽某些網頁都會詢問我們是否要傳送位置資訊,但我不確定在手機上的效果如何。

  4. WATGS says:

    版大你好 我近期在學習GPS
    我可以跟您要完整的程式碼run看看嗎?
    另外,我想請問GPS是自己定位找座標(經緯度)顯示還是給座標(經緯度)讓它找定位?

  5. Ben says:

    如果關了GPS 只會提示無法定位座標
    不會以網絡定位..........

    有解決方法嗎

    就算馬上 開啟GPS 也 是 無法定位座標,無法自動以網絡定位...............

    • Davina says:

      抱歉現在才看到你的問題。
      網路定位的權限開啟後系統應該會自動存取才對(可以的話換機子試試)。
      如果想關閉GPS的提示,可以修改23行 if(status.isProviderEnabled(LocationManager.GPS_PROVIDER)...

  6. Yi says:

    你好,請問為何定位會差了一個縣市呢?
    而且不管怎麼移動定位都是在錯誤的地點。
    麻煩你了

    • Davina says:

      你可以開Google地圖檢查目前定位的位置,因為這支程式也是抓系統定位,所以系統定位不正確的話,顯示結果也不會正確。

  7. 遊客 says:

    請問
    下面有提到有新的做法
    那新的做法是什麼呢?
    最近剛學ECLIPSE
    看到很多文章都很受用
    感謝

    • Davina says:

      這支程式在新版的Android執行可能會有問題,新的GPS寫法似乎是把LocationManager直接寫成class(我沒有實作過所以不確定)。
      另外,現在已經有App Inventor或是PhoneGap等更方便的工具可以使用,寫Android程式其實不一定要用Eclipse了。

  8. 遊客 says:

    不過我以為 直接用程式寫會比較容易修改或明白
    我之前有看過app inventor 的工具
    等於把語法做成圖形了

    現在剛接觸 真的最困難就是
    一堆東西不知道從哪裡跑出來引用的

    像是什麼更新位子的語法等等等
    我現在下載程式碼之後可以安裝 執行部分我也在嘗試

    請問初學真的不適合用eclipse嗎

    • Davina says:

      我認為學Android程式之前,應該要具備Java的基礎,所以這系列的文章有些地方寫得不是很清楚。
      初學者要直接學當然沒問題,只是難度比較高,容易把信心磨掉…
      即使要寫Eclipse,還是建議看書/網路找新版本的寫法會比較好,要學就直接學最新的,我認為是這樣。
      (我目前沒有餘力更新這些文章,只好先繼續擺著了)

  9. 遊客 says:

    難怪 我完全沒有java基礎
    但是基於專題.... 必須直接上
    因為老師認為app非常簡單
    前幾天改了藍芽範例增加自己一些功能
    老師一眼也不想看
    花了超級無敵多時間的....

    感謝您 我會再去找相關書籍

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *

你可以使用這些 HTML 標籤與屬性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>