此文為開發視界翻譯轉載者請注明出處(開發視界 www.sf.org.cn)否則追究法律責任
3 使用API定位
定位API被定義在Javax.microedition.location數據報中,察看microedition.location.version的屬性可以看到API的更詳細的情況。系統屬性的值就是運行的API的版本號,比如“1.0”。本節所講到的API開發中的代碼可以從以下地址獲得 http://www.forum.nokia.com/info/sw.nokia.com/
id/f7e8ad78-7898-4053-ab83
所有的定位API都在一個相同的類中,這節將這些API結合在一起講解,API中第一個使用的應該是選擇定位供應商,看下面的第一個表:
類
解釋
Criteria
用於選擇服務供應商
LocationProvider
顯示位置信息(比如GPS模式)
通常,API定位應用程序首先更新設備位置,定位API使用Lister檢測位置更新。以下列表介紹了幾個Lister。
類
解釋
LocationListene
接受與其連接的LocationProvider的信號
PorximityListener
連接附近的探測器注冊新的坐標。
下面的表格主要說明位置是如何測量的
類
解釋
AddressInfor
將位置信息以文本的形式存儲
Coordinates
以經度-緯度-海拔的形式表達坐標
Location
顯示標准格式的位置信息(及時坐標,速度,精確度等等)
LocationException
定位API產生錯誤的時候執行
QualifIEdCoordinates
更精確的以緯度-經度-海拔的格式表示坐標
位置信息可以存儲用於陸標。下面的表格所介紹的類就是這個目的。
類
解釋
Landmark
用於顯示一個已知定位的名稱
LandmarkException
處理陸標出現問題的時候運行
LandmarkSrore
管理陸標的方法(存儲,刪除,恢復陸標)
如果設備探測器支持獲取方向信息,也可以使用定位API的OrIEntation類來獲取信息(如下表)。
表3.5:定位API中的方位信息獲取類
類
解釋
OrIEntation
顯示設備物理方位i
3.1 設備定位
設備中內置的定位提供方法並不是必須的。比如,設備運行一個定位API,需要一個附件來運行定位方法。這樣一個附件可以是帶藍牙的GPS接收設備或者是一個在有效范圍內的GPS接收設備。位置的精確度有定位的方法所決定。有很多設備運行API定位程序從手機的基站獲得位置信息,局部小范圍的定位基站也可以用來獲取位置信息。除此之外,很多設備支持混合方法叫做A-GPS,這種方法同時使用了APS和網絡獲取位置信息。下面的圖說明了使用移動電話網或者衛星定位的原理。
圖5:通過使用移動電話網和衛星定位。
通常,通過衛星接收到的位置信息更加精確。由於衛星的周期性,在商業區衛星的GPS可能出現“峽谷效應”,造成API定位中斷。使用的費用根據不同的定位方法決定。API中可以定義定位所使用的方法。
API使用的第一個類是LocationProvider類,其顯示了定位信息提供的模式。通過使用默認的LocationProvider.getInstance(Criteria criteria)
可以創建LocationProvider的一個實例。標准參數用於判斷使用了什麼定位方式。API運行的時候選擇最符合參數的定位提供方式。TouristRoute中定義了一系列的參數,用於查找判斷選擇哪一種參數。
代碼實例1:Creating criteria (TouristRoute's ConfigurationProvider.Java class)
Criteria crit1 = new Criteria();
crit1.setHorizontalAccuracy(25); //
crit1.setVerticalAccuracy(25); //
crit1.setPreferredResponseTime(Criteria.NO_REQUIREMENT);
crit1.setPreferredPowerConsumption(Criteria.NO_REQUIREMENT);
crit1.setCostAllowed(false);
crit1.setSpeedAndCourseRequired(true);
crit1.setAltitudeRequired(true);
crit1.setAddressInfoRequired(true);
代碼實例2Choosing the location provider (TouristRoute's ConfigurationProvider.Java class)
代碼實例2中可以看到選擇定位方式的過程的代碼片斷,如果想參考完成的代碼,請看TouristRoute MIDlet
try
provider = LocationProvider.getInstance(criteria);
if (provider != null)
{
// provider found!
// .. see the complete source code for the real action.
}
catch(LocationException le)
// LocationProviders are currently out of service
如果設備中沒有任何內置的定位方法可以使用,外部也沒有任何可以連接的定位方法,LocationProvider.getInstance()則轉向運行LocationException而且TouristRoute MIDlet將會發出警告沒有發現任何定位方法。如果有任何定位方法可以執行,LocationProvider.getInstance()的返回值就不為空。如果沒有發現定位方法,TouristRoute MIDlet將持續掃描,直到發現定位方法。
當LocationProvider成功創建以後,就可以被用來注冊MIDLET監聽位置信息的更新以及坐標的變動。當前位置更新和定位方法狀態的改變的事件可以用LocationListener的借口來監聽(代碼實例3)。通過這樣一個接口,JSR179就可以對一個設備進行跟蹤。
代碼實例3:LocationListener interface's skeleton (TouristRoute's TouristData.Java class)
public void locationUpdated(LocationProvider provider, final Location location)
public void providerStateChanged(LocationProvider provider, final int newState)
注意:標准的LocationListener接口並沒有設置location和newstate參數,在例子中,final關鍵字只是在匿名的線程訪問參數的時候才會被用到。在例子TouristRoute中,運行的兩個方法都啟動了新的線程,因為LocationListener方法需要馬上返回,而不執行任何其他的過程。
通過ProximityListener,當發現新的坐標的時候,MIDLet就發出信號。當設備到達一個新的區域的時候,比如酒店或者賓館,Promximity event listening就會對設備進行監測。
代碼實例4:Proximity listener's skeleton (TouristRoute's TouristData class)
public void proximityEvent(Coordinates coordinates, Location location)
public void monitoringStateChanged(boolean isMonitoringActive)
使用setLocationProvider方法可以使LocationListener注冊一種定位方法,這樣就可以確定下面的參數:interval(以妙為單位),該參數用來接收事件;timeout(以秒為單位),代表與定義的更新間隔相比較,最大的升級間隔時間。Maxage定義了位置信息更新的值。代碼實例5說明了TouristRoute MIDlet日注冊LocationListener。
代碼實例5:Registering the location listener (TouristRoute's TouristData class)
if (provider != null)
int interval = -1; // default interval of this provider
int timeout = 0; // parameter has no effect.
int maxage = 0; // parameter has no effect.
provider.setLocationListener(this,interval,timeout,maxage);
代碼實例6通過使用LocationProvider的靜態方法addProximityListener說明ProximityListener的注冊方法。通過這種方法,每一個監聽的坐標都設置一個圓心,這個值是事件啟動的阈值!如果因為缺少資源注冊失敗,程序將跳轉執行LocationException。在TouristRoute MIDlet中,ProximityListener與從LandmarkStore中找到的每一個路標都進行注冊。與TouristRoute實例一樣,Proximity Listener注冊方法需要Coordinates參數,比如可以通過getQualifIEdCoordinates()方法從Landmask中獲得。
代碼實例6:Registering proximity listeners (TouristRoute's TouristData class)
try
LocationProvider.addProximityListener(this,
coordinates,
PROXIMITY_RADIUS)
catch (LocationException e)
// Platform does not have resources to add a new listener
// and coordinates to be monitored or does not support
// proximity monitoring at all
注意:所有的設備和模擬器都可能不支持通過ProximityListener接口向外發送信息,如果目標設備不支持,也就沒有監聽的功能。
3.2 陸標存儲
Landmarks可以被存儲用於特殊的數據庫陸標庫。路標對於所有J2ME所有應用程序都是共享的。路標被命名為不同的名稱可能存放在不同的目錄下,按照不同的類型分類存儲有便於快速查找。每一個設備都有一個默認的陸標存儲。當然每個設備都允許創建新的陸標。定位API同樣允許刪除現有的陸標目錄創建新的陸標目錄。
所有的陸標存儲訪問方法都可以通過LandmarkStore類實現。使用陸標的第一步是要利用getInstance方法創建一個LandmarkStore實例。如果能夠找到一個命名的存儲就會返回一個路標存儲。如果沒有命名的陸標存在,getInstant方法將返回NuLL。默認的陸標存儲可以不使用參數。創建一個路標實例請看代碼實例7。
代碼實例7:Getting a landmark store instance (TouristRoute's ControlPoints.Java class)
try
store = LandmarkStore.getInstance(STORENAME);
catch(NullPointerException npe)
if (store == null)
// code ...
通過createlandmarkStore(String StoreName)方法可以創建一個新的陸標存儲,參考代碼實例8。創建的陸標可以通過getInstance()方法進行訪問。如果因為某些原因導致創建陸標失敗,默認的陸標存儲可以通getInstance()方法訪問,其中不需要任何參數。
代碼實例8:Creating a new landmark store (TouristRoute's ControlPoints.Java class)
try
LandmarkStore.createLandmarkStore(STORENAME);
catch(IllegalArgumentException iae)
// Name is too long or landmark store with the specifIEd name
// already exists.
catch (IOException e)
// Landmark store couldn't be created due to an I/O error
catch (LandmarkException e)
// Implementation does not support creating new landmark stores.
LandmarkStore類中包含了很多陸標管理的方法。三種getLandmarks()種任何一種方法都可以獲取Landmark對象的Enumeration值。第一種方法並不使用,但是能夠列舉存儲在特殊陸標庫中的所與陸標。其余兩種方法用來獲取符合參數的陸標。代碼實例9顯示了第二種方法。在這個例子中,可以從一個明確范圍和坐標范圍的目錄中獲取陸標。第三種方法getLandmarks()可以用來顯示特殊目錄的陸標。
代碼實例9:Listing landmarks from a specific area and category
getLandmarks(String category, double minLatitude, double maxLatitude,
double minLongitude, double maxLongitude)
throws Java.io.IOException
通過addLandmark(Landmark landmark,
String category)方法可以將一個新的陸標加入到陸標庫中,新加入的陸標與陸標的種類是相關聯的。目錄的屬性為MULL,說明這個陸標不屬於任何種類相關。如果一個新的陸標對象傳輸的參數值與已有的陸標參數重復,那麼該陸標會存儲在指定的目錄。下面的圖標說明了一個新的陸標對象的產生和如何加入到TouristRoute MIDLet。
圖6:將陸標加入到TouristRoute MIDlet流程圖
通過使用updateLandmark(Landmark Landmark)方法可以將一個陸標更新。如果陸標傳遞的參數不屬於陸標庫,這個方法將跳轉到LandmarkException。另外,使用deleteLandmark(Landmark lm)方法可以將一個陸標刪除。如果傳遞的參數有誤,同樣執行LandmarkException。對於一個已經存在的陸標,如果要從指定的目錄下刪除,只能使用
removeLandmarkFromCategory (Landmark lm, String category)方法。
在使用上面所述三種陸標管理方法以前,必須先建立陸標對象實例。陸標類的結構包括名稱、描述、坐標、地址信息等參數。QualifIEdCoordinates的值可以通過陸標的LocationListner.locationUpdated()方法獲取。
代碼實例10說明了TouristRoute example MIDLet如何創建一個新的AddressInfor實例和如何將其傳遞給陸標。AddressInfor是一個存儲位置文本信息的類。其中getField(int fIEld)是用來獲取信息的,setField(int fIEld, String value)
方法用來設置信息。AddressInfo類中包含了一系列的整形常量,這些值用來傳遞到上述兩種方法(代碼實例10)。
代碼實例10:Creating a landmark instance in the TouristRoute MIDlet (TouristRoute's
LandmarkEditorUI.Java class)
AddressInfo info = new AddressInfo();
info.setField(AddressInfo.COUNTRY, countryFIEld.getString());
info.setField(AddressInfo.STATE, stateFIEld.getString());
info.setField(AddressInfo.CITY, cityFIEld.getString());
info.setField(AddressInfo.STREET, streetFIEld.getString());
info.setField(AddressInfo.BUILDING_NAME, buildingNameFIEld.getString());
Landmark lm = new Landmark(nameFIEld.getString(),
descFIEld.getString(),
coord,
info);
陸標庫類同樣具有目錄管理功能。陸標的Enumeration值可以通過getCategorIEs()方法獲取。新的目錄通過addCategory加入到陸標類,通過deleteCategory刪除已存在的陸標。
默認的目錄可能因為設備的不同而不同。比如一個設備可能存在以下設定好的目錄:"Accommodation", "Business", "Communication", "Educational
institute", "Entertainment", "Food & Beverage", "Geographical Area", "Outdoor activitIEs", "People", "Public service", "Religious places", "Shopping", "Sightseeing", "Sports", "Transport".
3.3 設備源
有恩多設備具有硬件的探測器,這決定了設備不同的定位方式。如果設備是通過磁場判斷的,應用程序中的設備源就是一個磁場。實際中,如果應用程序需要使用實際的北極點而不是地磁的北極點,那麼應用程序必須執行相應的折算程序。通過OrIEntation類的isOrIEntationMagnetic()方法就可以判斷出探測器的類型。設備源的信息可以通過API的OrIEntation類獲得。代碼實例11說明了如何獲取一個設備源的支持信息。
代碼實例11:Obtaining orIEntation support information (TouristRoute's
ConfigurationProvider.Java class)
try
orientation = Orientation.getOrIEntation();
return true;
catch (LocationException e)
return false;
如果探測器訪問Orientation.getOrIEntation()方法的時候沒有運行LocationException,說明探測器至少可以獲取compass azimuth.
如果設備的探測器只能提供horizontal compass azimuth,OrIEntatin類的getPitch()方法和getRoll()方法都將返回Float.NaN,說明信息獲取失敗。如果設備具有一個3D探測源,這兩種方法都可以提供數字信息。高度信息獲取范圍為[-90.0-90.0]。正負相對的數字表明設備的屏幕是上下重合的。左右數據的范圍為[-180.0-180]。如果左右方向的數據也是相反的,說明與其默認的方向源相反。