Android Wear 上的位置檢測(cè)

2018-07-13 09:26 更新

編寫:heray1990 - 原文: http://developer.android.com/training/articles/wear-location-detection.html

可穿戴設(shè)備上的位置感知讓我們可以創(chuàng)建為用戶提供更好地了解地理位置、移動(dòng)和周圍事物的應(yīng)用。由于可穿戴設(shè)備小型和方便的特點(diǎn),我們可以構(gòu)建低摩擦應(yīng)用來記錄和響應(yīng)位置數(shù)據(jù)。

一些可穿戴設(shè)備帶有 GPS 感應(yīng)器,它們可以在不需要其它設(shè)備的幫助下檢索位置數(shù)據(jù)。無論如何,當(dāng)我們?cè)诳纱┐鲬?yīng)用上請(qǐng)求獲取位置數(shù)據(jù),我們不需要擔(dān)心位置數(shù)據(jù)從哪里發(fā)出;系統(tǒng)會(huì)用最節(jié)能的方法來檢索位置更新。我們的應(yīng)用應(yīng)該可以處理位置數(shù)據(jù)的丟失,以防沒有內(nèi)置 GPS 感應(yīng)器的可穿戴設(shè)備與配套設(shè)備斷開連接。

這篇文章介紹如何檢查設(shè)備上的位置感應(yīng)器、檢索位置數(shù)據(jù)和監(jiān)視數(shù)據(jù)連接。

Note: 這篇文章假設(shè)我們知道如何使用 Google Play services API 來檢索位置數(shù)據(jù)。更多相關(guān)的內(nèi)容,請(qǐng)見 Android 位置信息。

連接 Google Play Services

可穿戴設(shè)備上的位置數(shù)據(jù)可以通過 Google Play services location APIs 來獲取。我們可以使用 FusedLocationProviderApi 和它伴隨的類來獲取這個(gè)數(shù)據(jù)。為了訪問位置服務(wù),可以創(chuàng)建 GoogleApiClient 實(shí)例,這個(gè)實(shí)例是任何 Google Play services APIs 的主要入口。

Caution: 不要使用 Android 框架已有的 Location APIs。檢索位置更新最好的方法是通過這篇文章介紹的 Google Play services API 獲取。

為了連接 Google Play services,配置應(yīng)用來創(chuàng)建 GoogleApiClient 實(shí)例:

  1. 創(chuàng)建一個(gè) activity 來指定 ConnectionCallbacksOnConnectionFailedListener 和 LocationListener 接口的實(shí)現(xiàn)。
  2. 在 activity 的 onCreate()) 方法中,創(chuàng)建 GoogleApiClient 實(shí)例和添加位置服務(wù)。
  3. 為了優(yōu)雅地管理連接的生命周期,在 onResume()) 方法里調(diào)用 connect()) 和在 onPause()) 方法里調(diào)用 disconnect())。

下面的代碼示例介紹了一個(gè) activity 的實(shí)現(xiàn)來實(shí)現(xiàn) LocationListener 接口:

public class WearableMainActivity extends Activity implements
    GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener,
    LocationListener {

    private GoogleApiClient mGoogleApiClient;
    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ...
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addApi(LocationServices.API)
                .addApi(Wearable.API)  // used for data layer API
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();
    }

    @Override
    protected void onResume() {
        super.onResume();
        mGoogleApiClient.connect();
        ...
    }

    @Override
    protected void onPause() {
        super.onPause();
        ...
        mGoogleApiClient.disconnect();
    }
}

更多關(guān)于連接 Google Play services 的內(nèi)容,請(qǐng)見 Accessing Google APIs。

請(qǐng)求位置更新

應(yīng)用連接到 Google Play services API 之后,它已經(jīng)準(zhǔn)備好開始接收位置更新了。當(dāng)系統(tǒng)為我們的客戶端調(diào)用 onConnected()) 回調(diào)函數(shù)時(shí),我們可以按照下面的步驟構(gòu)建位置更新請(qǐng)求:

  1. 創(chuàng)建一個(gè) LocationRequest 對(duì)象并且用像 setPriority()) 這樣的方法設(shè)置選項(xiàng)。
  2. 使用 requestLocationUpdates() 請(qǐng)求位置更新。
  3. 在 onPause() 方法里使用 removeLocationUpdates() 刪除位置更新。

下面的例子介紹了如何接收和刪除位置更新:

@Override
public void onConnected(Bundle bundle) {
    LocationRequest locationRequest = LocationRequest.create()
            .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
            .setInterval(UPDATE_INTERVAL_MS)
            .setFastestInterval(FASTEST_INTERVAL_MS);

    LocationServices.FusedLocationApi
            .requestLocationUpdates(mGoogleApiClient, locationRequest, this)
            .setResultCallback(new ResultCallback() {

                @Override
                public void onResult(Status status) {
                    if (status.getStatus().isSuccess()) {
                        if (Log.isLoggable(TAG, Log.DEBUG)) {
                            Log.d(TAG, "Successfully requested location updates");
                        }
                    } else {
                        Log.e(TAG,
                                "Failed in requesting location updates, "
                                        + "status code: "
                                        + status.getStatusCode()
                                        + ", message: "
                                        + status.getStatusMessage());
                    }
                }
            });
}

@Override
protected void onPause() {
    super.onPause();
    if (mGoogleApiClient.isConnected()) {
        LocationServices.FusedLocationApi
             .removeLocationUpdates(mGoogleApiClient, this);
    }
    mGoogleApiClient.disconnect();
}

@Override
public void onConnectionSuspended(int i) {
    if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(TAG, "connection to location client suspended");
    }
}

至此,我們已經(jīng)打開了位置更新,系統(tǒng)調(diào)用 onLocationChanged()) 方法,同時(shí)按照 setInterval()) 指定的時(shí)間間隔更新位置。

檢測(cè)設(shè)備上的 GPS

不是所有的可穿戴設(shè)備都有 GPS 感應(yīng)器。如果用戶出去外面并且將他們的手機(jī)放在家里,那么我們的可穿戴應(yīng)用無法通過一個(gè)綁定連接來接收位置數(shù)據(jù)。如果可穿戴設(shè)備沒有 GPS 感應(yīng)器,那么我們應(yīng)該檢測(cè)到這種情況并且警告用戶位置功能不可用。

使用 hasSystemFeature()) 方法確定 Android Wear 設(shè)備是否有內(nèi)置的 GPS 感應(yīng)器。下面的代碼用于當(dāng)我們啟動(dòng)一個(gè) activity 時(shí),檢測(cè)設(shè)備是否有內(nèi)置的 GPS 感應(yīng)器:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main_activity);
    if (!hasGps()) {
        Log.d(TAG, "This hardware doesn't have GPS.");
        // Fall back to functionality that does not use location or
        // warn the user that location function is not available.
    }

    ...
}

private boolean hasGps() {
    return getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS);
}

處理斷開事件

可穿戴設(shè)備在回答綁定連接位置數(shù)據(jù)時(shí)可能會(huì)突然斷開連接。如果我們的可穿戴應(yīng)用期待持續(xù)的數(shù)據(jù),那么我們必須處理數(shù)據(jù)中斷或者不可用的斷線問題。在一個(gè)不帶有 GPS 感應(yīng)器的可穿戴設(shè)備上,當(dāng)設(shè)備與綁定數(shù)據(jù)連接斷開時(shí),位置數(shù)據(jù)會(huì)丟失。

以防基于綁定位置數(shù)據(jù)連接的應(yīng)用和可穿戴設(shè)備沒有 GPS 感應(yīng)器,我們應(yīng)該檢測(cè)連接的斷線,警告用戶和優(yōu)雅地降低應(yīng)用的功能。

為了檢測(cè)數(shù)據(jù)連接的斷線:

  1. 繼承 WearableListenerService 來監(jiān)聽重要的數(shù)據(jù)層事件。
  2. 在 Android manifest 文件中聲明一個(gè) intent filter 來把WearableListenerService 通知給系統(tǒng)。這個(gè) filter 允許系統(tǒng)按需綁定我們的服務(wù)。
    <service android:name=".NodeListenerService">
     <intent-filter>
         <action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
     </intent-filter>
    </service>
    
  3. 實(shí)現(xiàn) onPeerDisconnected()) 方法并處理設(shè)備是否有內(nèi)置 GPS 的情況。
public class NodeListenerService extends WearableListenerService {

    private static final String TAG = "NodeListenerService";

    @Override
    public void onPeerDisconnected(Node peer) {
        Log.d(TAG, "You have been disconnected.");
        if(!hasGPS()) {
            // Notify user to bring tethered handset
            // Fall back to functionality that does not use location
        }
    }
    ...
}

更多相關(guān)的信息,請(qǐng)見 監(jiān)聽數(shù)據(jù)層事件 指南。

處理找不到位置的情況

當(dāng) GPS 信號(hào)丟失了,我們?nèi)匀豢梢允褂?nbsp;getLastLocation()) 檢索最后可知位置。這個(gè)方法在我們無法修復(fù) GPS 連接或者設(shè)備沒有內(nèi)置 GPS 并且斷開與手機(jī)連接的情況下很有用。

下面的代碼使用 getLastLocation()) 檢索最后可知位置:

Location location = LocationServices.FusedLocationApi
                .getLastLocation(mGoogleApiClient);

同步數(shù)據(jù)

如果可穿戴應(yīng)用使用內(nèi)置 GPS 記錄數(shù)據(jù),那么我們可能想要與手持應(yīng)用同步位置數(shù)據(jù)。對(duì)于 LocationListener,我們可以實(shí)現(xiàn) onLocationChanged()) 方法來檢測(cè)和記錄它改變的位置。

下面的可穿戴應(yīng)用代碼檢測(cè)位置變化和使用數(shù)據(jù)層 API 來保存用于手機(jī)應(yīng)用日后檢索的數(shù)據(jù):

@Override
public void onLocationChanged(Location location) {
    ...
    addLocationEntry(location.getLatitude(), location.getLongitude());

}

private void addLocationEntry(double latitude, double longitude) {
    if (!mSaveGpsLocation || !mGoogleApiClient.isConnected()) {
        return;
    }

    mCalendar.setTimeInMillis(System.currentTimeMillis());

    // Set the path of the data map
    String path = Constants.PATH + "/" + mCalendar.getTimeInMillis();
    PutDataMapRequest putDataMapRequest = PutDataMapRequest.create(path);

    // Set the location values in the data map
    putDataMapRequest.getDataMap()
            .putDouble(Constants.KEY_LATITUDE, latitude);
    putDataMapRequest.getDataMap()
            .putDouble(Constants.KEY_LONGITUDE, longitude);
    putDataMapRequest.getDataMap()
            .putLong(Constants.KEY_TIME, mCalendar.getTimeInMillis());

    // Prepare the data map for the request
    PutDataRequest request = putDataMapRequest.asPutDataRequest();

    // Request the system to create the data item
    Wearable.DataApi.putDataItem(mGoogleApiClient, request)
            .setResultCallback(new ResultCallback() {
                @Override
                public void onResult(DataApi.DataItemResult dataItemResult) {
                    if (!dataItemResult.getStatus().isSuccess()) {
                        Log.e(TAG, "Failed to set the data, "
                                + "status: " + dataItemResult.getStatus()
                                .getStatusCode());
                    }
                }
            });
}

更多關(guān)于如何使用數(shù)據(jù)層 API 的內(nèi)容,請(qǐng)見 發(fā)送與同步數(shù)據(jù) 指南。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)