讀古今文學網 > Android程序設計:第2版 > 沒有地圖的地理位置 >

沒有地圖的地理位置

如果你的活動想要訪問地理位置信息,但是沒有包含MapView,那會發生什麼情況呢?當使用MapView時,在MyLocationOverlay的實現中,一切都很簡單,但是如果你不使用地圖,獲取地理位置信息也不難。本節所提供的代碼不是MJAndroid的一部分,但是它說明了如何不通過MapView獲取地理位置信息。

我們一起來看一個簡單的、單活動應用,它在TextView中顯示了當前的地理位置。

Manifest文件和Layout文件

以下是常見的AndroidManifest.xml文件。我們使用Android SDK及Android Manifest Editor創建了這個文件。唯一需要使用編輯器進行修改的是為android.permission.ACCESS_FINE_LOCATION增加uses-permission標籤(在文件的倒數第二行)。我們一直需要這個權限,從而能夠從GPS地理位置提供者中獲取地理位置信息:


<?xml version=\"1.0\" encoding=\"utf-8\"?>
<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"
          package=\"com.microjobsinc.dloc\"
          android:versionCode=\"1\"
          android:versionName=\"1.0.0\">
<application android:icon=\"@drawable/icon\" android:label=\"@string/app_name\">
<activity android:name=\".Main\"
                    android:label=\"@string/app_name\">
<intent-filter>
<action android:name=\"android.intent.action.MAIN\" />
<category android:name=\"android.intent.category.LAUNCHER\" />
</intent-filter>
</activity>
</application>
<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\">
</uses-permission>
</manifest>
  

這裡將使用簡單的layout文件,它包含4個TextView:每個維度和經度包含一個標籤和一個文本框:


<?xml version=\"1.0\" encoding=\"utf-8\"?>
            <LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"
        android:orientation=\"vertical\"
        android:layout_
        android:layout_
            >
      <TextView
        android:id=\"@+id/lblLatitude\"
        android:layout_
        android:layout_
        android:text=\"Latitude:\"
                />
      <TextView
        android:id=\"@+id/tvLatitude\"
        android:layout_
        android:layout_
                />
      <TextView
        android:id=\"@+id/lblLongitude\"
        android:layout_
        android:layout_
        android:text=\"Longitude:\"
                />
      <TextView
        android:id=\"@+id/tvLongitude\"
        android:layout_
        android:layout_
        />
      </LinearLayout>
  

連接到LocationProvider,更新地理位置信息

我們一起實現一個活動,它連接到GPS LocationProvider,獲取並顯示當前地理位置(沒有更新):


package com.oreilly.demo.pa.microJobs;
import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.TextView;
public class Main extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        // find the TextViews
        TextView tvLatitude = (TextView)findViewById(R.id.tvLatitude);
        TextView tvLongitude = (TextView)findViewById(R.id.tvLongitude);
        // get handle for LocationManager
        LocationManager lm = (LocationManager)
        getSystemService(Context.LOCATION_SERVICE);
1
        // connect to the GPS location service
        Location loc = lm.getLastKnownLocation(\"gps\");
2
        // fill in the TextViews
        tvLatitude.setText(Double.toString(loc.getLatitude));
3
        tvLongitude.setText(Double.toString(loc.getLongitude));
    }
}
  

這個過程相當簡單。以下是對上述關鍵代碼的分析:

1 通過getSystemService(Context.LOCATION_SERVICE)方法連接到LocationManager。

2 通過getLastKnownLocation(\"provider\")方法,向LocationManager查詢當前的地理位置。

3 從返回的Location中獲取維度和經度,並依據需要使用這些信息。

我們還要從LocationManager中週期性地更新位置信息,這樣在移動時可以追蹤自己的位置。為此,需要增加一個listener,當有更新時,要求LocationManager調用該listener。

應用可以通過DispLocListener類訪問LocationManager更新過來的地理位置信息,因此,在主活動中,可以在onCreate方法中創建該類的實例。需要在DispLocListener中重寫很多方法來滿足LocationListener接口定義,但是在這個應用中不需要實現這些方法,因此保留空定義。完整的實現如下所示:


package com.oreilly.demo.pa.MicroJobs;
import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.TextView;
public class Main extends Activity {
    private LocationManager lm;
    private LocationListener locListenD;
    public TextView tvLatitude;
    public TextView tvLongitude;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        // find the TextViews
        tvLatitude = (TextView)findViewById(R.id.tvLatitude);
        tvLongitude = (TextView)findViewById(R.id.tvLongitude);
        // get handle for LocationManager
        LocationManager lm =
          (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        // connect to the GPS location service
        Location loc = lm.getLastKnownLocation(\"gps\");
        // fill in the TextViews
        tvLatitude.setText(Double.toString(loc.getLatitude));
        tvLongitude.setText(Double.toString(loc.getLongitude));
        // ask the Location Manager to send us location updates
        locListenD = new DispLocListener;
        lm.requestLocationUpdates(\"gps\", 30000L, 10.0f, locListenD);
    }
    private class DispLocListener implements LocationListener {
        @Override
        public void onLocationChanged(Location location) {
            // update TextViews
            tvLatitude.setText(Double.toString(location.getLatitude));
            tvLongitude.setText(Double.toString(location.getLongitude));
        }
        @Override
        public void onProviderDisabled(String provider) {
        }
        @Override
        public void onProviderEnabled(String provider) {
        }
        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }
    }
}
 

onCreate方法會創建一個DispLocListener實例,請求LocationManager通過requestLocationUpdates方法更新它。該方法包含4個參數:

String provider

指定要使用的地理位置提供者。在這個例子中,假定是GPS。

long minTime

指定最小更新時間,單位是ms。LocationManager在兩次更新之間會至少等待minTime。這是為了省電。更新越頻繁,電池消耗越多。

float minDistance

觸發更新的最小距離,單位是m。只有當用戶至少移動了這麼遠的距離,LocationManager才會執行更新。

LocationListener listener

當存在更新時會調用的listener名稱,在這個例子中,即剛創建的DispLocListener實例。

最後,增加了onPause方法和onResume方法,當啟用不在用戶屏幕上顯示時,可以關閉地理位置更新,並且當再次顯示時,重新啟用地理位置更新:


/**
 * Turn off location updates if we\'re paused
 */
@Override
public void onPause {
    super.onPause;
    lm.removeUpdates(locListenD);
}
/**
 * Resume location updates when we\'re resumed
 */
@Override
public void onResume {
    super.onResume;
    lm.requestLocationUpdates(\"gps\", 30000L, 10.0f, locListenD);
}
  

更新模擬的地理位置

在開發和調試前文所示的應用時,一般都是在模擬器上運行。在模擬器上運行代碼時,如果能夠更新當前位置將是比較理想的(甚至是比較基礎的)。這種模擬地理位置提供者可能功能很完善,但是Android提供了一些內建方式來更新模擬的地理位置:

·Android shell中提供的geo程序

·通過DDMS的一次性更新

·通過DDMS序列化更新的追蹤信息

下面將逐個解釋這些方式。

使用geo工具更新地理位置信息

geo工具構建在Android圖像中,它運行在模擬器上。geo工具包含很多功能,其中有兩個功能很有用:

geo fix

可以在模擬的Android的console上執行telnet,使用geo fix命令為Android發送地理位置信息。LocationProvider會使用該信息作為當前的地理位置:


      telnet localhost 5554
      Android Console: type \'help\' for a list of commands
      OK
      geo fix -122.842232 38.411908 0
      OK
  

geo fix接受3個參數:

longitude

以十進制形式表示。

latitude

也是以十進制形式表示。

altitude

單位是米。

通過DDMS更新地理位置

第1章介紹了Dalvik Debug Monitor Server(DDMS)。這裡將探討該工具提供的和地理位置更新相關的兩個功能。DDMS屏幕的Emulator Control窗口提供了控制運行的模擬器的一些方式。當切換為DDMS方式時(單擊Eclipse窗口右上角的DDMS),在DDMS窗口的左側中間,可以看到Emulator Control窗口(如圖15-1所示)。可能需要在該窗口中使用滾動條往下拉,查看和Location Controls相關的控件。

要給該模擬器發送一次地理位置更新,只需要在相應的窗口中輸入經維度,並單擊Send按鈕。

圖15-1:DDMS Emulator Control窗口

如果單擊GPX或KML選項卡,還可以加載描述路徑的GPX文件或KML文件,如圖15-2所示。這裡,加載了文件OR.kml,在本書的網站中提供了該文件。它跟蹤位於加利福尼亞州塞巴斯玻市的O』Reilly總部附近的一條路徑。

圖15-2:包含KML地理位置更新的DDMS模擬器

可以使用GPS導航軟件工具生成GPX追蹤信息,使用Google Earth或其他導航程序生成KML追蹤信息。OR.kml文件是使用Google Earth繪製了一系列地標並把它們連接起來後生成的一個文件。以下是OR.kml文件的一個片段: