W3Cschool
恭喜您成為首批注冊(cè)用戶(hù)
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
編寫(xiě):penkzhou - 原文:http://developer.android.com/training/location/geofencing.html
地理圍欄將用戶(hù)當(dāng)前位置感知和附件地點(diǎn)特征感知相結(jié)合。為了標(biāo)示一個(gè)感興趣的位置,我們需要指定這個(gè)位置的經(jīng)緯度。為了調(diào)整位置的鄰近度,需要添加一個(gè)半徑。經(jīng)緯度和半徑定義一個(gè)地理圍欄,即在感興趣的位置創(chuàng)建一個(gè)圓形區(qū)域或者圍欄。
我們可以有多個(gè)活動(dòng)的地理圍欄(限制是一個(gè)設(shè)備用戶(hù)100個(gè))。對(duì)于每個(gè)地理圍欄,我們可以讓 Location Services 發(fā)出進(jìn)入和離開(kāi)事件,或者我們可以在觸發(fā)一個(gè)事件之前,指定在某個(gè)地理圍欄區(qū)域等待一段時(shí)間或者停留。通過(guò)指定一個(gè)以毫秒為單位的截止時(shí)間,我們可以限制任何一個(gè)地理圍欄的持續(xù)時(shí)間。當(dāng)?shù)乩韲鷻谑Ш?,Location Services 會(huì)自動(dòng)刪除這個(gè)地理圍欄。
這節(jié)課介紹如何添加和刪除地理圍欄,和用 IntentService 監(jiān)聽(tīng)地理位置變化。
請(qǐng)求地理圍欄監(jiān)視的第一步就是設(shè)置必要的權(quán)限。在使用地理圍欄時(shí),我們必須設(shè)置 ACCESS_FINE_LOCATION 權(quán)限。在應(yīng)用的 manifest 文件中添加如下子節(jié)點(diǎn)即可:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
如果想要用 IntentService 監(jiān)聽(tīng)地理位置變化,那么還需要添加一個(gè)節(jié)點(diǎn)來(lái)指定服務(wù)名字。這個(gè)節(jié)點(diǎn)必須是 的子節(jié)點(diǎn):
<application
android:allowBackup="true">
...
<service android:name=".GeofenceTransitionsIntentService"/>
<application/>
為了訪(fǎng)問(wèn)位置 API,我們需要?jiǎng)?chuàng)建一個(gè) Google Play services API client 的實(shí)例。想要學(xué)習(xí)如何連接 client,請(qǐng)見(jiàn)連接Google Play Services。
我們的應(yīng)用需要用位置 API 的 builder 類(lèi)來(lái)創(chuàng)建地理圍欄,用 convenience 類(lèi)來(lái)添加地理圍欄。另外,我們可以定義一個(gè) PendingIntent(將在這節(jié)課介紹)來(lái)處理當(dāng)?shù)乩砦恢冒l(fā)生遷移時(shí),Location Services 發(fā)出的 intent。
首先,用 Geofence.Builder 創(chuàng)建一個(gè)地理圍欄,設(shè)置想要的半徑,持續(xù)時(shí)間,和地理圍欄遷移的類(lèi)型。例如,填充一個(gè)叫做 mGeofenceList
的 list 對(duì)象:
mGeofenceList.add(new Geofence.Builder()
// Set the request ID of the geofence. This is a string to identify this
// geofence.
.setRequestId(entry.getKey())
.setCircularRegion(
entry.getValue().latitude,
entry.getValue().longitude,
Constants.GEOFENCE_RADIUS_IN_METERS
)
.setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
Geofence.GEOFENCE_TRANSITION_EXIT)
.build());
這個(gè)例子從一個(gè)固定的文件中獲取數(shù)據(jù)。在實(shí)際情況下,應(yīng)用可能會(huì)根據(jù)用戶(hù)的位置動(dòng)態(tài)地創(chuàng)建地理圍欄。
下面的代碼用到 GeofencingRequest 類(lèi)。該類(lèi)嵌套了 GeofencingRequestBuilder 類(lèi)來(lái)需要監(jiān)視的地理圍欄和設(shè)置如何觸發(fā)地理圍欄事件:
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(mGeofenceList);
return builder.build();
}
這個(gè)例子介紹了兩個(gè)地理圍欄觸發(fā)器。當(dāng)設(shè)備進(jìn)入一個(gè)地理圍欄時(shí), GEOFENCE_TRANSITION_ENTER 轉(zhuǎn)移會(huì)觸發(fā)。當(dāng)設(shè)備離開(kāi)一個(gè)地理圍欄時(shí), GEOFENCE_TRANSITION_EXIT 轉(zhuǎn)移會(huì)觸發(fā)。如果設(shè)備已經(jīng)在地理圍欄里面,那么指定 INITIAL_TRIGGER_ENTER 來(lái)通知位置服務(wù)觸發(fā) GEOFENCE_TRANSITION_ENTER。
在很多情況下,使用 INITIAL_TRIGGER_DWELL 可能會(huì)更好。僅僅當(dāng)由于到達(dá)地理圍欄中已定義好的持續(xù)時(shí)間,而導(dǎo)致用戶(hù)停止時(shí),INITIAL_TRIGGER_DWELL 才會(huì)觸發(fā)事件。這個(gè)方法可以減少當(dāng)設(shè)備短暫地進(jìn)入和離開(kāi)地理圍欄時(shí),由大量的通知造成的“垃圾警告信息”。另一種獲取最好的地理圍欄結(jié)果的策略是設(shè)置最小半徑為100米。這有助于估計(jì)典型的 Wifi 網(wǎng)絡(luò)的位置精確度,也有利于降低設(shè)備的功耗。
從 Location Services 發(fā)送來(lái)的Intent能夠觸發(fā)各種應(yīng)用內(nèi)的動(dòng)作,但是不能用它來(lái)打開(kāi)一個(gè) Activity 或者 Fragment,這是因?yàn)閼?yīng)用內(nèi)的組件只能在響應(yīng)用戶(hù)動(dòng)作時(shí)才可見(jiàn)。大多數(shù)情況下,處理這一類(lèi) Intent 最好使用 IntentService。一個(gè) IntentService 可以推送一個(gè)通知,可以進(jìn)行長(zhǎng)時(shí)間的后臺(tái)作業(yè),可以將 intent 發(fā)送給其他的 services ,還可以發(fā)送一個(gè)廣播 intent。下面的代碼展示了如何定義一個(gè) PendingIntent 來(lái)啟動(dòng)一個(gè) IntentService:
public class MainActivity extends FragmentActivity {
...
private PendingIntent getGeofencePendingIntent() {
// Reuse the PendingIntent if we already have it.
if (mGeofencePendingIntent != null) {
return mGeofencePendingIntent;
}
Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when
// calling addGeofences() and removeGeofences().
return PendingIntent.getService(this, 0, intent, PendingIntent.
FLAG_UPDATE_CURRENT);
}
使用 GeoencingApi.addGeofences() 方法來(lái)添加地理圍欄。為該方法提供 Google API client,GeofencingRequest 對(duì)象和 PendingIntent。下面的代碼,在 onResult()) 中處理結(jié)果,假設(shè)主 activity 實(shí)現(xiàn) ResultCallback。
public class MainActivity extends FragmentActivity {
...
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
).setResultCallback(this);
當(dāng) Location Services 探測(cè)到用戶(hù)進(jìn)入或者離開(kāi)一個(gè)地理圍欄,它會(huì)發(fā)送一個(gè)包含在 PendingIntent 的 Intent,這個(gè) PendingIntent 就是在添加地理圍欄時(shí)被我們包括在請(qǐng)求當(dāng)中。這個(gè) Intent 被一個(gè)類(lèi)似 GeofenceTransitionsIntentService
的 service 接收,這個(gè) service 從 intent 得到地理圍欄事件,決定地理圍欄轉(zhuǎn)移的類(lèi)型,和決定觸發(fā)哪個(gè)已定義的地理圍欄。然后它會(huì)發(fā)出一個(gè)通知。
下面的代碼介紹了如何定義一個(gè) IntentService。這個(gè) IntentService 在地理圍欄轉(zhuǎn)移出現(xiàn)時(shí),會(huì)推送一個(gè)通知。當(dāng)用戶(hù)點(diǎn)擊這個(gè)通知,那么應(yīng)用的主 activity 會(huì)出現(xiàn):
public class GeofenceTransitionsIntentService extends IntentService {
...
protected void onHandleIntent(Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
String errorMessage = GeofenceErrorMessages.getErrorString(this,
geofencingEvent.getErrorCode());
Log.e(TAG, errorMessage);
return;
}
// Get the transition type.
int geofenceTransition = geofencingEvent.getGeofenceTransition();
// Test that the reported transition was of interest.
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
// Get the geofences that were triggered. A single event can trigger
// multiple geofences.
List triggeringGeofences = geofencingEvent.getTriggeringGeofences();
// Get the transition details as a String.
String geofenceTransitionDetails = getGeofenceTransitionDetails(
this,
geofenceTransition,
triggeringGeofences
);
// Send notification and log the transition details.
sendNotification(geofenceTransitionDetails);
Log.i(TAG, geofenceTransitionDetails);
} else {
// Log the error.
Log.e(TAG, getString(R.string.geofence_transition_invalid_type,
geofenceTransition));
}
}
在通過(guò) PendingIntent 檢測(cè)轉(zhuǎn)移事件之后,這個(gè) IntentService 獲取地理圍欄轉(zhuǎn)移類(lèi)型和測(cè)試一個(gè)事件是不是應(yīng)用用來(lái)觸發(fā)通知的 —— 要么是 GEOFENCE_TRANSITION_ENTER,要么是 GEOFENCE_TRANSITION_EXIT。然后,這個(gè) service 會(huì)發(fā)出一個(gè)通知并且記錄轉(zhuǎn)移的詳細(xì)信息。
當(dāng)不再需要監(jiān)視地理圍欄或者想要節(jié)省設(shè)備的電池電量和 CPU 周期時(shí),需要停止地理圍欄監(jiān)視。我們可以在用于添加和刪除地理圍欄的主 activity 里停止地理圍欄監(jiān)視;刪除地理圍欄會(huì)導(dǎo)致它馬上停止。API 要么通過(guò) request IDs,要么通過(guò)刪除與指定 PendingIntent 相關(guān)的地理圍欄來(lái)刪除地理圍欄。
下面的代碼通過(guò) PendingIntent 刪除地理圍欄,當(dāng)設(shè)備進(jìn)入或者離開(kāi)之前已經(jīng)添加的地理圍欄時(shí),停止所有通知:
LocationServices.GeofencingApi.removeGeofences(
mGoogleApiClient,
// This is the same pending intent that was used in addGeofences().
getGeofencePendingIntent()
).setResultCallback(this); // Result processed in onResult().
}
你可以將地理圍欄同其他位置感知的特性結(jié)合起來(lái),比如周期性的位置更新。像要了解更多的信息,請(qǐng)看本章的其它課程。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話(huà):173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: