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);
	}
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.
101 Responses
  1. zhixian says:

    您好,小弟目前正在學如何透過wifi取得經緯度

    是否能跟你索取完成程式碼呢?

  2. hotowen says:

    您好,我依照您提供的方法一步一步建立程式碼
    最後也成功將程式匯出到手機上執(有開啟GPS)
    但是執行後的發現,程式只會偵測到一個固定點的經、緯座標
    並沒有每秒更新的情況,而且我利用Google map查詢了座標的位置
    也不是現在手機的所在地,懇請您的開示,謝謝!

    • Davina says:

      可以先檢查手機的GPS地點沒有改變,這個部份你可以用Google Map確認
      建議把wifi與Google定位開啟,這樣定位會比較準確一些
      程式的部份,就要看"更新地點"那邊的程式有沒有錯誤了

  3. ZH says:

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

    • Davina says:

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

  4. 阿剛 says:

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

    • Davina says:

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

  5. WMHSIAOYI says:

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

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

    請問這有解決方法嗎?

    感恩

    • Davina says:

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

發表迴響

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

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