亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

【Android Developers Training】 106. 創建并

系統 1865 0

注:本文翻譯自Google官方的Android Developers Training文檔,譯者技術一般,由于喜愛安卓而產生了翻譯的念頭,純屬個人興趣愛好。

原文鏈接: http://developer.android.com/training/location/geofencing.html


地理圍欄可以將用戶當前地點信息和周圍的地點信息相結合,它其實是用戶接近潛在的感興趣的地點的程度。要標記一個感興趣的地點,你需要指定它的經緯度。要調整接近的位置,你還需要添加一個半徑。經緯度和半徑加起來就成為了一個地理圍欄。你可以同一時間有多個激活的地理圍欄。

定位服務將一個地理圍欄看做是一塊面積而不是點和距離。這就可以當用戶進入或離開地理圍欄時檢測到。對于每一個地理圍欄,你可以讓定位服務向你發送進入事件或離開事件或者都發送。你還可以限制地理圍欄的持續時間,方法是定義一個有效期(以毫秒為單位)。當地理圍欄過期后,定位服務會自動移除它。


一). 請求地理圍欄監測

請求地理圍欄監測的第一步是申請必需的權限。要使用地理圍欄,你的應用必須申請 ACCESS_FINE_LOCATION 。要申請這一權限,將下列元素添加為 <manifest> 標簽的子標簽:

      
        <
      
      
        uses-permission 
      
      
        android:name
      
      
        ="android.permission.ACCESS_FINE_LOCATION"
      
      
        />
      
    

檢查Google Play服務

位置服務是Google Play服務APK的其中一部分。由于用戶設備的狀態時難以預料的,你應該一直在你嘗試連接定位服務之前,檢查APK是否已經安裝。要檢查APK是否安裝,可以調用 GooglePlayServicesUtil.isGooglePlayServicesAvailable() ,它會返回一個整形的結果碼,其含義可以參閱: ConnectionResult 。如果你遇到了一個錯誤,可以調用 GooglePlayServicesUtil.getErrorDialog() ,來獲取一個本地的對話框,引導用戶執行正確地行為,之后將這一對話框顯示在一個 DialogFragment 上。這一對話框可能允許用戶解決當前的問題,此時Google Play服務會發回一個結果到你的activity中。要處理這一結果,需要覆寫 onActivityResult() 方法。

Note:

要使你的應用可以兼容1.6及以后版本的系統,顯示 DialogFragment 的activity必須是 FragmentActivity 的子類,而非 Activity 。使用 FragmentActivity 還可以允許你調用 getSupportFragmentManager() 方法來顯示 DialogFragment

由于你一直需要在你的代碼多個地方檢查Google Play服務,所以應該定義一個方法將檢查行為進行封裝,之后在每次連接嘗試之前進行檢查。下面的代碼片段包含了檢查Google Play服務所需要的代碼:

      
        public
      
      
        class
      
       MainActivity 
      
        extends
      
      
         FragmentActivity {

    ...

    
      
      
        //
      
      
         Global constants
      
      
        /*
      
      
        

     * Define a request code to send to Google Play services

     * This code is returned in Activity.onActivityResult

     
      
      
        */
      
      
        private
      
      
        final
      
      
        static
      
      
        int
      
      
        

            CONNECTION_FAILURE_RESOLUTION_REQUEST 
      
      = 9000
      
        ;

    ...

    
      
      
        //
      
      
         Define a DialogFragment that displays the error dialog
      
      
        public
      
      
        static
      
      
        class
      
       ErrorDialogFragment 
      
        extends
      
      
         DialogFragment {

        
      
      
        //
      
      
         Global field to contain the error dialog
      
      
        private
      
      
         Dialog mDialog;

        ...

        
      
      
        //
      
      
         Default constructor. Sets the dialog field to null
      
      
        public
      
      
         ErrorDialogFragment() {

            
      
      
        super
      
      
        ();

            mDialog 
      
      = 
      
        null
      
      
        ;

        }

        ...

        
      
      
        //
      
      
         Set the dialog to display
      
      
        public
      
      
        void
      
      
         setDialog(Dialog dialog) {

            mDialog 
      
      =
      
         dialog;

        }

        ...

        
      
      
        //
      
      
         Return a Dialog to the DialogFragment.
      
      
                @Override

        
      
      
        public
      
      
         Dialog onCreateDialog(Bundle savedInstanceState) {

            
      
      
        return
      
      
         mDialog;

        }

        ...

    }

    ...

    
      
      
        /*
      
      
        

     * Handle results returned to the FragmentActivity

     * by Google Play services

     
      
      
        */
      
      
        

     @Override

    
      
      
        protected
      
      
        void
      
      
         onActivityResult(

            
      
      
        int
      
       requestCode, 
      
        int
      
      
         resultCode, Intent data) {

        
      
      
        //
      
      
         Decide what to do based on the original request code
      
      
        switch
      
      
         (requestCode) {

            ...

            
      
      
        case
      
      
         CONNECTION_FAILURE_RESOLUTION_REQUEST :

            
      
      
        /*
      
      
        

             * If the result code is Activity.RESULT_OK, try

             * to connect again

             
      
      
        */
      
      
        switch
      
      
         (resultCode) {

                    ...

                    
      
      
        case
      
      
         Activity.RESULT_OK :

                    
      
      
        /*
      
      
        

                     * Try the request again

                     
      
      
        */
      
      
        

                    ...

                    
      
      
        break
      
      
        ;

                }

            ...

        }

        ...

    }

    ...

    
      
      
        private
      
      
        boolean
      
      
         servicesConnected() {

        
      
      
        //
      
      
         Check that Google Play services is available
      
      
        int
      
       resultCode =
      
        

                GooglePlayServicesUtil.

                        isGooglePlayServicesAvailable(
      
      
        this
      
      
        );

        
      
      
        //
      
      
         If Google Play services is available
      
      
        if
      
       (ConnectionResult.SUCCESS ==
      
         resultCode) {

            
      
      
        //
      
      
         In debug mode, log the status
      
      

            Log.d("Geofence Detection"
      
        ,

                    
      
      "Google Play services is available."
      
        );

            
      
      
        //
      
      
         Continue
      
      
        return
      
      
        true
      
      
        ;

        
      
      
        //
      
      
         Google Play services was not available for some reason
      
      

        } 
      
        else
      
      
         {

            
      
      
        //
      
      
         Get the error code
      
      
        int
      
       errorCode =
      
         connectionResult.getErrorCode();

            
      
      
        //
      
      
         Get the error dialog from Google Play services
      
      

            Dialog errorDialog =
      
         GooglePlayServicesUtil.getErrorDialog(

                    errorCode,

                    
      
      
        this
      
      
        ,

                    CONNECTION_FAILURE_RESOLUTION_REQUEST);



            
      
      
        //
      
      
         If Google Play services can provide an error dialog
      
      
        if
      
       (errorDialog != 
      
        null
      
      
        ) {

                
      
      
        //
      
      
         Create a new DialogFragment for the error dialog
      
      

                ErrorDialogFragment errorFragment =

                        
      
        new
      
      
         ErrorDialogFragment();

                
      
      
        //
      
      
         Set the dialog in the DialogFragment
      
      
                        errorFragment.setDialog(errorDialog);

                
      
      
        //
      
      
         Show the error dialog in the DialogFragment
      
      
                        errorFragment.show(

                        getSupportFragmentManager(),

                        
      
      "Geofence Detection"
      
        );

            }

        }

    }

    ...

}
      
    

在后續章節的代碼片段中,都會調用這一方法來驗證是否可獲取Google Play服務。

要使用地理圍欄,首先定義你想要監測的地理圍欄。雖然你經常要將地理圍欄信息保存到一個本地的數據庫或者從網絡上下載下來,你需要將一個地理圍欄發送給定位服務作為一個 Geofence 的實例(通過 Geofence.Builder 創建的)。每一個對象包含下列信息:

經緯度和半徑:

給地理圍欄定義一個圓形區域。使用經緯度標記一個感興趣的地點,并且使用半徑來調整當用戶具體該地點多近后地理圍欄會被檢測到。半徑越大,用戶接近地理圍欄時,激活它的可能性就越高。例如,如果一個應用提供了一個大半徑的地理圍欄,當用戶回家時可以自動打開房間里的燈。由于半徑設的太大,很有可能用戶離開之后燈還是亮著的。

有效期:

設置地理圍欄的有效期。一旦超過了有效期,定位服務將會刪除該地理圍欄。在大多數情況下,你應該指定一個有效期,但你也可能希望為用戶的屋子或者工作地點的地理圍欄長期保留。

過度類型:

當用戶進入了地理圍欄的范圍(“ 進入 ”)以及當用于離開了此范圍(“ 離開 ”),定位服務可以檢測到這兩個類型之一,或者兩者都檢測到。

地理圍欄ID:

一個和地理圍欄一起保存的字符串。你應該讓這個值保持唯一,所以你可以使用它從定位服務中移除一個地理圍欄。

定義一個地理圍欄存儲

一個地理圍欄應用需要讀寫地理圍欄數據以持久化數據。你不應該使用 Geofence 對象來做這件事情;相反的,使用諸如數據庫等存儲技術來保存相關的數據是比較好的。

作為一個存儲數據的例子,下面的代碼片段定義了兩個類,它們使用應用的 SharedPreferences 實例持久化數據。類 SimpleGeofence ,是一個類似于數據庫記錄的類,它以一個“ 稀疏 ”的形式保存一個單一的 Geofence 對象。類 SimpleGeofenceStore 類似于一個數據庫,它向 SharedPreferences 實例讀寫 SimpleGeofence 數據。

      
        public
      
      
        class
      
       MainActivity 
      
        extends
      
      
         FragmentActivity {

    ...

    
      
      
        /**
      
      
        

     * A single Geofence object, defined by its center and radius.

     
      
      
        */
      
      
        public
      
      
        class
      
      
         SimpleGeofence {

            
      
      
        //
      
      
         Instance variables
      
      
        private
      
      
        final
      
      
         String mId;

            
      
      
        private
      
      
        final
      
      
        double
      
      
         mLatitude;

            
      
      
        private
      
      
        final
      
      
        double
      
      
         mLongitude;

            
      
      
        private
      
      
        final
      
      
        float
      
      
         mRadius;

            
      
      
        private
      
      
        long
      
      
         mExpirationDuration;

            
      
      
        private
      
      
        int
      
      
         mTransitionType;



        
      
      
        /**
      
      
        

         * 
      
      
        @param
      
      
         geofenceId The Geofence's request ID

         * 
      
      
        @param
      
      
         latitude Latitude of the Geofence's center.

         * 
      
      
        @param
      
      
         longitude Longitude of the Geofence's center.

         * 
      
      
        @param
      
      
         radius Radius of the geofence circle.

         * 
      
      
        @param
      
      
         expiration Geofence expiration duration

         * 
      
      
        @param
      
      
         transition Type of Geofence transition.

         
      
      
        */
      
      
        public
      
      
         SimpleGeofence(

                String geofenceId,

                
      
      
        double
      
      
         latitude,

                
      
      
        double
      
      
         longitude,

                
      
      
        float
      
      
         radius,

                
      
      
        long
      
      
         expiration,

                
      
      
        int
      
      
         transition) {

            
      
      
        //
      
      
         Set the instance fields from the constructor
      
      
        this
      
      .mId =
      
         geofenceId;

            
      
      
        this
      
      .mLatitude =
      
         latitude;

            
      
      
        this
      
      .mLongitude =
      
         longitude;

            
      
      
        this
      
      .mRadius =
      
         radius;

            
      
      
        this
      
      .mExpirationDuration =
      
         expiration;

            
      
      
        this
      
      .mTransitionType =
      
         transition;

        }

        
      
      
        //
      
      
         Instance field getters
      
      
        public
      
      
         String getId() {

            
      
      
        return
      
      
         mId;

        }

        
      
      
        public
      
      
        double
      
      
         getLatitude() {

            
      
      
        return
      
      
         mLatitude;

        }

        
      
      
        public
      
      
        double
      
      
         getLongitude() {

            
      
      
        return
      
      
         mLongitude;

        }

        
      
      
        public
      
      
        float
      
      
         getRadius() {

            
      
      
        return
      
      
         mRadius;

        }

        
      
      
        public
      
      
        long
      
      
         getExpirationDuration() {

            
      
      
        return
      
      
         mExpirationDuration;

        }

        
      
      
        public
      
      
        int
      
      
         getTransitionType() {

            
      
      
        return
      
      
         mTransitionType;

        }

        
      
      
        /**
      
      
        

         * Creates a Location Services Geofence object from a

         * SimpleGeofence.

         *

         * 
      
      
        @return
      
      
         A Geofence object

         
      
      
        */
      
      
        public
      
      
         Geofence toGeofence() {

            
      
      
        //
      
      
         Build a new Geofence object
      
      
        return
      
      
        new
      
      
         Geofence.Builder()

                    .setRequestId(getId())

                    .setTransitionTypes(mTransitionType)

                    .setCircularRegion(

                            getLatitude(), getLongitude(), getRadius())

                    .setExpirationDuration(mExpirationDuration)

                    .build();

        }

    }

    ...

    
      
      
        /**
      
      
        

     * Storage for geofence values, implemented in SharedPreferences.

     
      
      
        */
      
      
        public
      
      
        class
      
      
         SimpleGeofenceStore {

        
      
      
        //
      
      
         Keys for flattened geofences stored in SharedPreferences
      
      
        public
      
      
        static
      
      
        final
      
       String KEY_LATITUDE =

                "com.example.android.geofence.KEY_LATITUDE"
      
        ;

        
      
      
        public
      
      
        static
      
      
        final
      
       String KEY_LONGITUDE =

                "com.example.android.geofence.KEY_LONGITUDE"
      
        ;

        
      
      
        public
      
      
        static
      
      
        final
      
       String KEY_RADIUS =

                "com.example.android.geofence.KEY_RADIUS"
      
        ;

        
      
      
        public
      
      
        static
      
      
        final
      
       String KEY_EXPIRATION_DURATION =

                "com.example.android.geofence.KEY_EXPIRATION_DURATION"
      
        ;

        
      
      
        public
      
      
        static
      
      
        final
      
       String KEY_TRANSITION_TYPE =

                "com.example.android.geofence.KEY_TRANSITION_TYPE"
      
        ;

        
      
      
        //
      
      
         The prefix for flattened geofence keys
      
      
        public
      
      
        static
      
      
        final
      
       String KEY_PREFIX =

                "com.example.android.geofence.KEY"
      
        ;

        
      
      
        /*
      
      
        

         * Invalid values, used to test geofence storage when

         * retrieving geofences

         
      
      
        */
      
      
        public
      
      
        static
      
      
        final
      
      
        long
      
       INVALID_LONG_VALUE = -999l
      
        ;

        
      
      
        public
      
      
        static
      
      
        final
      
      
        float
      
       INVALID_FLOAT_VALUE = -999.0f
      
        ;

        
      
      
        public
      
      
        static
      
      
        final
      
      
        int
      
       INVALID_INT_VALUE = -999
      
        ;

        
      
      
        //
      
      
         The SharedPreferences object in which geofences are stored
      
      
        private
      
      
        final
      
      
         SharedPreferences mPrefs;

        
      
      
        //
      
      
         The name of the SharedPreferences
      
      
        private
      
      
        static
      
      
        final
      
       String SHARED_PREFERENCES =

                "SharedPreferences"
      
        ;

        
      
      
        //
      
      
         Create the SharedPreferences storage with private access only
      
      
        public
      
      
         SimpleGeofenceStore(Context context) {

            mPrefs 
      
      =
      
        

                    context.getSharedPreferences(

                            SHARED_PREFERENCES,

                            Context.MODE_PRIVATE);

        }

        
      
      
        /**
      
      
        

         * Returns a stored geofence by its id, or returns null

         * if it's not found.

         *

         * 
      
      
        @param
      
      
         id The ID of a stored geofence

         * 
      
      
        @return
      
      
         A geofence defined by its center and radius. See

         
      
      
        */
      
      
        public
      
      
         SimpleGeofence getGeofence(String id) {

            
      
      
        /*
      
      
        

             * Get the latitude for the geofence identified by id, or

             * INVALID_FLOAT_VALUE if it doesn't exist

             
      
      
        */
      
      
        double
      
       lat =
      
         mPrefs.getFloat(

                    getGeofenceFieldKey(id, KEY_LATITUDE),

                    INVALID_FLOAT_VALUE);

            
      
      
        /*
      
      
        

             * Get the longitude for the geofence identified by id, or

             * INVALID_FLOAT_VALUE if it doesn't exist

             
      
      
        */
      
      
        double
      
       lng =
      
         mPrefs.getFloat(

                    getGeofenceFieldKey(id, KEY_LONGITUDE),

                    INVALID_FLOAT_VALUE);

            
      
      
        /*
      
      
        

             * Get the radius for the geofence identified by id, or

             * INVALID_FLOAT_VALUE if it doesn't exist

             
      
      
        */
      
      
        float
      
       radius =
      
         mPrefs.getFloat(

                    getGeofenceFieldKey(id, KEY_RADIUS),

                    INVALID_FLOAT_VALUE);

            
      
      
        /*
      
      
        

             * Get the expiration duration for the geofence identified

             * by id, or INVALID_LONG_VALUE if it doesn't exist

             
      
      
        */
      
      
        long
      
       expirationDuration =
      
         mPrefs.getLong(

                    getGeofenceFieldKey(id, KEY_EXPIRATION_DURATION),

                    INVALID_LONG_VALUE);

            
      
      
        /*
      
      
        

             * Get the transition type for the geofence identified by

             * id, or INVALID_INT_VALUE if it doesn't exist

             
      
      
        */
      
      
        int
      
       transitionType =
      
         mPrefs.getInt(

                    getGeofenceFieldKey(id, KEY_TRANSITION_TYPE),

                    INVALID_INT_VALUE);

            
      
      
        //
      
      
         If none of the values is incorrect, return the object
      
      
        if
      
      
         (

                lat 
      
      != GeofenceUtils.INVALID_FLOAT_VALUE &&
      
        

                lng 
      
      != GeofenceUtils.INVALID_FLOAT_VALUE &&
      
        

                radius 
      
      != GeofenceUtils.INVALID_FLOAT_VALUE &&
      
        

                expirationDuration 
      
      !=
      
        

                        GeofenceUtils.INVALID_LONG_VALUE 
      
      &&
      
        

                transitionType 
      
      !=
      
         GeofenceUtils.INVALID_INT_VALUE) {



                
      
      
        //
      
      
         Return a true Geofence object
      
      
        return
      
      
        new
      
      
         SimpleGeofence(

                        id, lat, lng, radius, expirationDuration,

                        transitionType);

            
      
      
        //
      
      
         Otherwise, return null.
      
      

            } 
      
        else
      
      
         {

                
      
      
        return
      
      
        null
      
      
        ;

            }

        }

        
      
      
        /**
      
      
        

         * Save a geofence.

         * 
      
      
        @param
      
      
         geofence The SimpleGeofence containing the

         * values you want to save in SharedPreferences

         
      
      
        */
      
      
        public
      
      
        void
      
      
         setGeofence(String id, SimpleGeofence geofence) {

            
      
      
        /*
      
      
        

             * Get a SharedPreferences editor instance. Among other

             * things, SharedPreferences ensures that updates are atomic

             * and non-concurrent

             
      
      
        */
      
      
        

            Editor editor 
      
      =
      
         mPrefs.edit();

            
      
      
        //
      
      
         Write the Geofence values to SharedPreferences
      
      
                    editor.putFloat(

                    getGeofenceFieldKey(id, KEY_LATITUDE),

                    (
      
      
        float
      
      
        ) geofence.getLatitude());

            editor.putFloat(

                    getGeofenceFieldKey(id, KEY_LONGITUDE),

                    (
      
      
        float
      
      
        ) geofence.getLongitude());

            editor.putFloat(

                    getGeofenceFieldKey(id, KEY_RADIUS),

                    geofence.getRadius());

            editor.putLong(

                    getGeofenceFieldKey(id, KEY_EXPIRATION_DURATION),

                    geofence.getExpirationDuration());

            editor.putInt(

                    getGeofenceFieldKey(id, KEY_TRANSITION_TYPE),

                    geofence.getTransitionType());

            
      
      
        //
      
      
         Commit the changes
      
      
                    editor.commit();

        }

        
      
      
        public
      
      
        void
      
      
         clearGeofence(String id) {

            
      
      
        /*
      
      
        

             * Remove a flattened geofence object from storage by

             * removing all of its keys

             
      
      
        */
      
      
        

            Editor editor 
      
      =
      
         mPrefs.edit();

            editor.remove(getGeofenceFieldKey(id, KEY_LATITUDE));

            editor.remove(getGeofenceFieldKey(id, KEY_LONGITUDE));

            editor.remove(getGeofenceFieldKey(id, KEY_RADIUS));

            editor.remove(getGeofenceFieldKey(id,

                    KEY_EXPIRATION_DURATION));

            editor.remove(getGeofenceFieldKey(id, KEY_TRANSITION_TYPE));

            editor.commit();

        }

        
      
      
        /**
      
      
        

         * Given a Geofence object's ID and the name of a field

         * (for example, KEY_LATITUDE), return the key name of the

         * object's values in SharedPreferences.

         *

         * 
      
      
        @param
      
      
         id The ID of a Geofence object

         * 
      
      
        @param
      
      
         fieldName The field represented by the key

         * 
      
      
        @return
      
      
         The full key name of a value in SharedPreferences

         
      
      
        */
      
      
        private
      
      
         String getGeofenceFieldKey(String id,

                String fieldName) {

            
      
      
        return
      
       KEY_PREFIX + "_" + id + "_" +
      
         fieldName;

        }

    }

    ...

}
      
    

創建地理圍欄對象

下面的代碼片段使用 SimpleGeofence SimpleGeofenceStore 類從UI中獲取地理圍欄數據,把這些對象存儲在一個 SimpleGeofenceStore 對象中,之后創建 Geofence 對象:

      
        public
      
      
        class
      
       MainActivity 
      
        extends
      
      
         FragmentActivity {

    ...

    
      
      
        /*
      
      
        

     * Use to set an expiration time for a geofence. After this amount

     * of time Location Services will stop tracking the geofence.

     
      
      
        */
      
      
        private
      
      
        static
      
      
        final
      
      
        long
      
       SECONDS_PER_HOUR = 60
      
        ;

    
      
      
        private
      
      
        static
      
      
        final
      
      
        long
      
       MILLISECONDS_PER_SECOND = 1000
      
        ;

    
      
      
        private
      
      
        static
      
      
        final
      
      
        long
      
       GEOFENCE_EXPIRATION_IN_HOURS = 12
      
        ;

    
      
      
        private
      
      
        static
      
      
        final
      
      
        long
      
       GEOFENCE_EXPIRATION_TIME =
      
        

            GEOFENCE_EXPIRATION_IN_HOURS 
      
      *
      
        

            SECONDS_PER_HOUR 
      
      *
      
        

            MILLISECONDS_PER_SECOND;

    ...

    
      
      
        /*
      
      
        

     * Handles to UI views containing geofence data

     
      
      
        */
      
      
        //
      
      
         Handle to geofence 1 latitude in the UI
      
      
        private
      
      
         EditText mLatitude1;

    
      
      
        //
      
      
         Handle to geofence 1 longitude in the UI
      
      
        private
      
      
         EditText mLongitude1;

    
      
      
        //
      
      
         Handle to geofence 1 radius in the UI
      
      
        private
      
      
         EditText mRadius1;

    
      
      
        //
      
      
         Handle to geofence 2 latitude in the UI
      
      
        private
      
      
         EditText mLatitude2;

    
      
      
        //
      
      
         Handle to geofence 2 longitude in the UI
      
      
        private
      
      
         EditText mLongitude2;

    
      
      
        //
      
      
         Handle to geofence 2 radius in the UI
      
      
        private
      
      
         EditText mRadius2;

    
      
      
        /*
      
      
        

     * Internal geofence objects for geofence 1 and 2

     
      
      
        */
      
      
        private
      
      
         SimpleGeofence mUIGeofence1;

    
      
      
        private
      
      
         SimpleGeofence mUIGeofence2;

    ...

    
      
      
        //
      
      
         Internal List of Geofence objects
      
      

    List<Geofence>
      
         mGeofenceList;

    
      
      
        //
      
      
         Persistent storage for geofences
      
      
        private
      
      
         SimpleGeofenceStore mGeofenceStorage;

    ...

    @Override

    
      
      
        protected
      
      
        void
      
      
         onCreate(Bundle savedInstanceState) {

        
      
      
        super
      
      
        .onCreate(savedInstanceState);

        ...

        
      
      
        //
      
      
         Instantiate a new geofence storage area
      
      

        mGeofenceStorage = 
      
        new
      
       SimpleGeofenceStore(
      
        this
      
      
        );



        
      
      
        //
      
      
         Instantiate the current List of geofences
      
      

        mCurrentGeofences = 
      
        new
      
       ArrayList<Geofence>
      
        ();

    }

    ...

    
      
      
        /**
      
      
        

     * Get the geofence parameters for each geofence from the UI

     * and add them to a List.

     
      
      
        */
      
      
        public
      
      
        void
      
      
         createGeofences() {

        
      
      
        /*
      
      
        

         * Create an internal object to store the data. Set its

         * ID to "1". This is a "flattened" object that contains

         * a set of strings

         
      
      
        */
      
      
        

        mUIGeofence1 
      
      = 
      
        new
      
      
         SimpleGeofence(

                
      
      "1"
      
        ,

                Double.valueOf(mLatitude1.getText().toString()),

                Double.valueOf(mLongitude1.getText().toString()),

                Float.valueOf(mRadius1.getText().toString()),

                GEOFENCE_EXPIRATION_TIME,

                
      
      
        //
      
      
         This geofence records only entry transitions
      
      
                        Geofence.GEOFENCE_TRANSITION_ENTER);

        
      
      
        //
      
      
         Store this flat version
      
      

        mGeofenceStorage.setGeofence("1"
      
        , mUIGeofence1);

        
      
      
        //
      
      
         Create another internal object. Set its ID to "2"
      
      

        mUIGeofence2 = 
      
        new
      
      
         SimpleGeofence(

                
      
      "2"
      
        ,

                Double.valueOf(mLatitude2.getText().toString()),

                Double.valueOf(mLongitude2.getText().toString()),

                Float.valueOf(mRadius2.getText().toString()),

                GEOFENCE_EXPIRATION_TIME,

                
      
      
        //
      
      
         This geofence records both entry and exit transitions
      
      

                Geofence.GEOFENCE_TRANSITION_ENTER |
      
        

                Geofence.GEOFENCE_TRANSITION_EXIT);

        
      
      
        //
      
      
         Store this flat version
      
      

        mGeofenceStorage.setGeofence(2
      
        , mUIGeofence2);

        mGeofenceList.add(mUIGeofence1.toGeofence());

        mGeofenceList.add(mUIGeofence2.toGeofence());

    }

    ...

}
      
    

除了你希望監測的存儲 Geofence 對象的 List ,你還需要向定位服務提供一個 Intent ,當監測到地理圍欄轉換的時候會將它發送給你的應用。

為地理圍欄轉換定義一個Intent

從定位服務發送的 Intent 可以激活你應用中的多個行為,但是你不應該讓它啟動一個activity或者fragment,因為組件只有在用戶行為的出發條件下變的向用戶可見才行。在很多情況下,用一個 IntentService 來處理intent是一個不錯的方式。一個 IntentService 可以發布一個通知,在后臺執行一個長時間運作的任務,將intent發送給其它服務,或者發送一個廣播intent。下面的代碼片段展示了如何定義一個 PendingIntent 來啟動一個 IntentService

      
        public
      
      
        class
      
       MainActivity 
      
        extends
      
      
         FragmentActivity {

    ...

    
      
      
        /*
      
      
        

     * Create a PendingIntent that triggers an IntentService in your

     * app when a geofence transition occurs.

     
      
      
        */
      
      
        private
      
      
         PendingIntent getTransitionPendingIntent() {

        
      
      
        //
      
      
         Create an explicit Intent
      
      

        Intent intent = 
      
        new
      
       Intent(
      
        this
      
      
        ,

                ReceiveTransitionsIntentService.
      
      
        class
      
      
        );

        
      
      
        /*
      
      
        

         * Return the PendingIntent

         
      
      
        */
      
      
        return
      
      
         PendingIntent.getService(

                
      
      
        this
      
      
        ,

                
      
      0
      
        ,

                intent,

                PendingIntent.FLAG_UPDATE_CURRENT);

    }

    ...

}
      
    

要向定位服務請求監測地理圍欄,所需的代碼現在你已經都有了。

發送監測請求

發送監測請求需要兩種異步操作。第一種操作為請求獲取一個定位客戶端,第二個操作使用客戶端發送請求。在這兩個情況中,定位服務會在它完成了操作后調用一個回調函數。要處理這些操作的最佳方法是將這些函數調用串聯起來。下面的代碼片段將演示如何設置一個acitvity,定義方法,并以正確地順序調用他們。

首先,修改activity類定義來實現必要的回調接口。添加下列接口:

ConnectionCallbacks

當一個定位客戶端連接或者斷開連接后,定位服務需要調用的方法。

OnConnectionFailedListener

當嘗試連接定位客戶端失敗或發生錯誤后,定位服務需要調用的方法。

OnAddGeofencesResultListener

一旦添加了地理圍欄,定位服務調用的方法。

例如:

      
        public
      
      
        class
      
       MainActivity 
      
        extends
      
       FragmentActivity 
      
        implements
      
      
        

        ConnectionCallbacks,

        OnConnectionFailedListener,

        OnAddGeofencesResultListener {

    ...

}
      
    

開始請求過程

接下來,定義一個方法,它通過連接定位服務來開始請求的過程。通過設置一個全局變量來標記它是一個添加地理圍欄的請求。這將允許你使用 ConnectionCallbacks.onConnected() 這一回調函數來添加地理圍欄或者移除它們,這些細節將在下面的章節展開。

為了防止競爭場景的發生(比如你的應用在第一個請求結束之前又發出了第二個請求),定義一個布爾變量,用來標記當前請求的狀態:

      
        public
      
      
        class
      
       MainActivity 
      
        extends
      
       FragmentActivity 
      
        implements
      
      
        

        ConnectionCallbacks,

        OnConnectionFailedListener,

        OnAddGeofencesResultListener {

    ...

    
      
      
        //
      
      
         Holds the location client
      
      
        private
      
      
         LocationClient mLocationClient;

    
      
      
        //
      
      
         Stores the PendingIntent used to request geofence monitoring
      
      
        private
      
      
         PendingIntent mGeofenceRequestIntent;

    
      
      
        //
      
      
         Defines the allowable request types.
      
      
        public
      
      
        enum
      
       REQUEST_TYPE =
      
         {ADD}

    
      
      
        private
      
      
         REQUEST_TYPE mRequestType;

    
      
      
        //
      
      
         Flag that indicates if a request is underway.
      
      
        private
      
      
        boolean
      
      
         mInProgress;

    ...

    @Override

    
      
      
        protected
      
      
        void
      
      
         onCreate(Bundle savedInstanceState) {

        ...

        
      
      
        //
      
      
         Start with the request flag set to false
      
      

        mInProgress = 
      
        false
      
      
        ;

        ...

    }

    ...

    
      
      
        /**
      
      
        

     * Start a request for geofence monitoring by calling

     * LocationClient.connect().

     
      
      
        */
      
      
        public
      
      
        void
      
      
         addGeofences() {

        
      
      
        //
      
      
         Start a request to add geofences
      
      

        mRequestType =
      
         ADD;

        
      
      
        /*
      
      
        

         * Test for Google Play services after setting the request type.

         * If Google Play services isn't present, the proper request

         * can be restarted.

         
      
      
        */
      
      
        if
      
       (!
      
        servicesConnected()) {

            
      
      
        return
      
      
        ;

        }

        
      
      
        /*
      
      
        

         * Create a new location client object. Since the current

         * activity class implements ConnectionCallbacks and

         * OnConnectionFailedListener, pass the current activity object

         * as the listener for both parameters

         
      
      
        */
      
      
        

        mLocationClient 
      
      = 
      
        new
      
       LocationClient(
      
        this
      
      , 
      
        this
      
      , 
      
        this
      
      
        )

        
      
      
        //
      
      
         If a request is not already underway
      
      
        if
      
       (!
      
        mInProgress) {

            
      
      
        //
      
      
         Indicate that a request is underway
      
      

            mInProgress = 
      
        true
      
      
        ;

            
      
      
        //
      
      
         Request a connection from the client to Location Services
      
      
                    mLocationClient.connect();

        } 
      
      
        else
      
      
         {

            
      
      
        /*
      
      
        

             * A request is already underway. You can handle

             * this situation by disconnecting the client,

             * re-setting the flag, and then re-trying the

             * request.

             
      
      
        */
      
      
        

        }

    }

    ...

}
      
    

發送請求來添加地理圍欄

在你的 ConnectionCallbacks.onConnected() 實現中,調用 LocationClient.addGeofences() 。注意,如果連接失敗了, onConnected() 不會被調用,請求被中止。

      
        public
      
      
        class
      
       MainActivity 
      
        extends
      
       FragmentActivity 
      
        implements
      
      
        

        ConnectionCallbacks,

        OnConnectionFailedListener,

        OnAddGeofencesResultListener {

    ...

    
      
      
        /*
      
      
        

     * Provide the implementation of ConnectionCallbacks.onConnected()

     * Once the connection is available, send a request to add the

     * Geofences

     
      
      
        */
      
      
        

    @Override

    
      
      
        private
      
      
        void
      
      
         onConnected(Bundle dataBundle) {

        ...

        
      
      
        switch
      
      
         (mRequestType) {

            
      
      
        case
      
      
         ADD :

                
      
      
        //
      
      
         Get the PendingIntent for the request
      
      

                mTransitionPendingIntent =
      
        

                        getTransitionPendingIntent();

                
      
      
        //
      
      
         Send a request to add the current geofences
      
      
                        mLocationClient.addGeofences(

                        mCurrentGeofences, pendingIntent, 
      
      
        this
      
      
        );

            ...

        }

    }

    ...

}
      
    

注意 addGeofences() 會迅速返回,但是請求的狀態在定位服務調用 onAddGeofencesResult() 之前是不定的。一旦這一方法被調用,你就能夠確定請求是否成功。

檢查定位服務返回的結果

當定位服務調用了你的回調函數 onAddGeofencesResult() 的實現,這就代表請求完成了,之后檢查傳入的狀態碼。如果請求成功,那么你所請求的地理圍欄將被激活。否則,地理圍欄不會被激活,你需要繼續嘗試請求或者報告錯誤。例如:

      
        public
      
      
        class
      
       MainActivity 
      
        extends
      
       FragmentActivity 
      
        implements
      
      
        

        ConnectionCallbacks,

        OnConnectionFailedListener,

        OnAddGeofencesResultListener {

        ...

    
      
      
        /*
      
      
        

     * Provide the implementation of

     * OnAddGeofencesResultListener.onAddGeofencesResult.

     * Handle the result of adding the geofences

     *

     
      
      
        */
      
      
        

    @Override

    
      
      
        public
      
      
        void
      
      
         onAddGeofencesResult(

            
      
      
        int
      
      
         statusCode, String[] geofenceRequestIds) {

        
      
      
        //
      
      
         If adding the geofences was successful
      
      
        if
      
       (LocationStatusCodes.SUCCESS ==
      
         statusCode) {

            
      
      
        /*
      
      
        

             * Handle successful addition of geofences here.

             * You can send out a broadcast intent or update the UI.

             * geofences into the Intent's extended data.

             
      
      
        */
      
      
        

        } 
      
      
        else
      
      
         {

        
      
      
        //
      
      
         If adding the geofences failed
      
      
        /*
      
      
        

             * Report errors here.

             * You can log the error using Log.e() or update

             * the UI.

             
      
      
        */
      
      
        

        }

        
      
      
        //
      
      
         Turn off the in progress flag and disconnect the client
      
      

        mInProgress = 
      
        false
      
      
        ;

        mLocationClient.disconnect();

    }

    ...

}
      
    

處理連接中斷

在有些情況下,定位服務可能會在你調用了 disconnect() 之前就中斷連接了。要處理這種情況,需要實現 onDisconnected() 方法。在這個方法中,設置請求標識,以表明當前沒有進行中的請求,并將客戶端移除:

      
        public
      
      
        class
      
       MainActivity 
      
        extends
      
       FragmentActivity 
      
        implements
      
      
        

        ConnectionCallbacks,

        OnConnectionFailedListener,

        OnAddGeofencesResultListener {

    ...

    
      
      
        /*
      
      
        

     * Implement ConnectionCallbacks.onDisconnected()

     * Called by Location Services once the location client is

     * disconnected.

     
      
      
        */
      
      
        

    @Override

    
      
      
        public
      
      
        void
      
      
         onDisconnected() {

        
      
      
        //
      
      
         Turn off the request flag
      
      

        mInProgress = 
      
        false
      
      
        ;

        
      
      
        //
      
      
         Destroy the current location client
      
      

        mLocationClient = 
      
        null
      
      
        ;

    }

    ...

}
      
    

處理連接錯誤

除了處理定位服務的常規回調函數外,你還需要提供一個回調函數,該函數會在連接錯誤發生的時候被定為服務調用。該回調函數可以重用 DialogFragment 類(你在檢查Google Play服務時所定義的類)。同時它也可以重用當用戶與錯誤對話框交互時,接收任何由Google Play服務返回的結果的 onActivityResult() 函數。下面的代碼片段展示了該回調函數的一個例子:

      
        public
      
      
        class
      
       MainActivity 
      
        extends
      
       FragmentActivity 
      
        implements
      
      
        

        ConnectionCallbacks,

        OnConnectionFailedListener,

        OnAddGeofencesResultListener {

    ...

    
      
      
        //
      
      
         Implementation of OnConnectionFailedListener.onConnectionFailed
      
      
            @Override

    
      
      
        public
      
      
        void
      
      
         onConnectionFailed(ConnectionResult connectionResult) {

        
      
      
        //
      
      
         Turn off the request flag
      
      

        mInProgress = 
      
        false
      
      
        ;

        
      
      
        /*
      
      
        

         * If the error has a resolution, start a Google Play services

         * activity to resolve it.

         
      
      
        */
      
      
        if
      
      
         (connectionResult.hasResolution()) {

            
      
      
        try
      
      
         {

                connectionResult.startResolutionForResult(

                        
      
      
        this
      
      
        ,

                        CONNECTION_FAILURE_RESOLUTION_REQUEST);

            } 
      
      
        catch
      
      
         (SendIntentException e) {

                
      
      
        //
      
      
         Log the error
      
      
                        e.printStackTrace();

            }

        
      
      
        //
      
      
         If no resolution is available, display an error dialog
      
      

        } 
      
        else
      
      
         {

            
      
      
        //
      
      
         Get the error code
      
      
        int
      
       errorCode =
      
         connectionResult.getErrorCode();

            
      
      
        //
      
      
         Get the error dialog from Google Play services
      
      

            Dialog errorDialog =
      
         GooglePlayServicesUtil.getErrorDialog(

                    errorCode,

                    
      
      
        this
      
      
        ,

                    CONNECTION_FAILURE_RESOLUTION_REQUEST);

            
      
      
        //
      
      
         If Google Play services can provide an error dialog
      
      
        if
      
       (errorDialog != 
      
        null
      
      
        ) {

                
      
      
        //
      
      
         Create a new DialogFragment for the error dialog
      
      

                ErrorDialogFragment errorFragment =

                        
      
        new
      
      
         ErrorDialogFragment();

                
      
      
        //
      
      
         Set the dialog in the DialogFragment
      
      
                        errorFragment.setDialog(errorDialog);

                
      
      
        //
      
      
         Show the error dialog in the DialogFragment
      
      
                        errorFragment.show(

                        getSupportFragmentManager(),

                        
      
      "Geofence Detection"
      
        );

            }

        }

    }

    ...

}
      
    

二). 處理地理圍欄轉換

當定位服務檢測到了用戶進入或者離開了一個地理圍欄,它會發送一個 Intent ,該 Intent 來自于你請求添加地理圍欄時所用到的 PendingIntent

定義一個IntentService

下面的代碼片段展示了當一個地理圍欄轉換發生的時候, 如何定義一個 IntentService 。當用戶點擊通知時, 顯示 應用的主activity:

      
        public
      
      
        class
      
       ReceiveTransitionsIntentService 
      
        extends
      
      
         IntentService {

    ...

    
      
      
        /**
      
      
        

     * Sets an identifier for the service

     
      
      
        */
      
      
        public
      
      
         ReceiveTransitionsIntentService() {

        
      
      
        super
      
      ("ReceiveTransitionsIntentService"
      
        );

    }

    
      
      
        /**
      
      
        

     * Handles incoming intents

     *
      
      
        @param
      
      
         intent The Intent sent by Location Services. This

     * Intent is provided

     * to Location Services (inside a PendingIntent) when you call

     * addGeofences()

     
      
      
        */
      
      
        

    @Override

    
      
      
        protected
      
      
        void
      
      
         onHandleIntent(Intent intent) {

        
      
      
        //
      
      
         First check for errors
      
      
        if
      
      
         (LocationClient.hasError(intent)) {

            
      
      
        //
      
      
         Get the error code with a static method
      
      
        int
      
       errorCode =
      
         LocationClient.getErrorCode(intent);

            
      
      
        //
      
      
         Log the error
      
      

            Log.e("ReceiveTransitionsIntentService"
      
        ,

                    
      
      "Location Services error: " +
      
        

                    Integer.toString(errorCode));

            
      
      
        /*
      
      
        

             * You can also send the error code to an Activity or

             * Fragment with a broadcast Intent

             
      
      
        */
      
      
        /*
      
      
        

         * If there's no error, get the transition type and the IDs

         * of the geofence or geofences that triggered the transition

         
      
      
        */
      
      
        

        } 
      
      
        else
      
      
         {

            
      
      
        //
      
      
         Get the type of transition (entry or exit)
      
      
        int
      
       transitionType =
      
        

                    LocationClient.getGeofenceTransition(intent);

            
      
      
        //
      
      
         Test that a valid transition was reported
      
      
        if
      
      
         (

                (transitionType 
      
      ==
      
         Geofence.GEOFENCE_TRANSITION_ENTER)

                 
      
      ||
      
        

                (transitionType 
      
      ==
      
         Geofence.GEOFENCE_TRANSITION_EXIT)

               ) {

                List 
      
      <Geofence> triggerList =
      
        

                        getTriggeringGeofences(intent);



                String[] triggerIds 
      
      = 
      
        new
      
      
         String[geofenceList.size()];



                
      
      
        for
      
       (
      
        int
      
       i = 0; i < triggerIds.length; i++
      
        ) {

                    
      
      
        //
      
      
         Store the Id of each geofence
      
      

                    triggerIds[i] =
      
         triggerList.get(i).getRequestId();

                }

                
      
      
        /*
      
      
        

                 * At this point, you can store the IDs for further use

                 * display them, or display the details associated with

                 * them.

                 
      
      
        */
      
      
        

            }

        
      
      
        //
      
      
         An invalid transition was reported
      
      

        } 
      
        else
      
      
         {

            Log.e(
      
      "ReceiveTransitionsIntentService"
      
        ,

                    
      
      "Geofence transition error: " +
      
        

                    Integer.toString()transitionType));

        }

    }

    ...
        
}

在清單列表中聲明IntentService

要在系統中使用 IntentService ,在應用清單文件中添加一個 <service> 標簽,例如:

      
        <
      
      
        service

    
      
      
        android:name
      
      
        ="com.example.android.location.ReceiveTransitionsIntentService"
      
      
        

    android:label
      
      
        ="@string/app_name"
      
      
        

    android:exported
      
      
        ="false"
      
      
        >
      
      
        </
      
      
        service
      
      
        >
      
    

注意,你不需要為該服務指定intent過濾器,因為它僅會接收顯式的intent。如何創建地理圍欄轉換intent,可以閱讀: Send the monitoring request


停止地理圍欄監控

要停止地理圍欄監控,你需要將它們移除。你可以通過一個 PendingIntent 將所有地理圍欄全部移除,或者只移除一部分。過程與添加地理圍欄類似。首先需要為移除請求獲取定位客戶端,然后使用客戶端提出申請。

定位服務在完成移除后所調用的回調函數在 LocationClient.OnRemoveGeofencesResultListener 接口中被定義。將該接口聲明為你的類定義的一部分,之后添加其兩個方法的定義:

onRemoveGeofencesByPendingIntentResult()

當定位服務使用函數 removeGeofences(PendingIntent, LocationClient.OnRemoveGeofencesResultListener) 移除了所有地理圍欄后被調用。

onRemoveGeofencesByRequestIdsResult(List<String>, LocationClient.OnRemoveGeofencesResultListener)

當定位服務使用函數 removeGeofences(List<String>, LocationClient.OnRemoveGeofencesResultListener) 將給定ID所對應的部分地理圍欄移除后被調用。

下面給出這些方法的使用樣例:

移除所有地理圍欄

由于移除地理圍欄會使用一些添加地理圍欄時所使用的方法,我們從定義另一個請求類型開始:

      
        public
      
      
        class
      
       MainActivity 
      
        extends
      
       FragmentActivity 
      
        implements
      
      
        

        ConnectionCallbacks,

        OnConnectionFailedListener,

        OnAddGeofencesResultListener {

    ...

    
      
      
        //
      
      
         Enum type for controlling the type of removal requested
      
      
        public
      
      
        enum
      
       REQUEST_TYPE =
      
         {ADD, REMOVE_INTENT}

    ...

}
      
    

通過獲取定位服務的連接開始移除請求。如果連接失敗了, onConnected() 不會被調用,請求中止。下面的代碼片段展示了如何開始請求:

      
        public
      
      
        class
      
       MainActivity 
      
        extends
      
       FragmentActivity 
      
        implements
      
      
        

        ConnectionCallbacks,

        OnConnectionFailedListener,

        OnAddGeofencesResultListener {

    ...

    
      
      
        /**
      
      
        

     * Start a request to remove geofences by calling

     * LocationClient.connect()

     
      
      
        */
      
      
        public
      
      
        void
      
      
         removeGeofences(PendingIntent requestIntent) {

        
      
      
        //
      
      
         Record the type of removal request
      
      

        mRequestType =
      
         REMOVE_INTENT;

        
      
      
        /*
      
      
        

         * Test for Google Play services after setting the request type.

         * If Google Play services isn't present, the request can be

         * restarted.

         
      
      
        */
      
      
        if
      
       (!
      
        servicesConnected()) {

            
      
      
        return
      
      
        ;

        }

        
      
      
        //
      
      
         Store the PendingIntent
      
      

        mGeofenceRequestIntent =
      
         requestIntent;

        
      
      
        /*
      
      
        

         * Create a new location client object. Since the current

         * activity class implements ConnectionCallbacks and

         * OnConnectionFailedListener, pass the current activity object

         * as the listener for both parameters

         
      
      
        */
      
      
        

        mLocationClient 
      
      = 
      
        new
      
       LocationClient(
      
        this
      
      , 
      
        this
      
      , 
      
        this
      
      
        );

        
      
      
        //
      
      
         If a request is not already underway
      
      
        if
      
       (!
      
        mInProgress) {

            
      
      
        //
      
      
         Indicate that a request is underway
      
      

            mInProgress = 
      
        true
      
      
        ;

            
      
      
        //
      
      
         Request a connection from the client to Location Services
      
      
                    mLocationClient.connect();

        } 
      
      
        else
      
      
         {

            
      
      
        /*
      
      
        

             * A request is already underway. You can handle

             * this situation by disconnecting the client,

             * re-setting the flag, and then re-trying the

             * request.

             
      
      
        */
      
      
        

        }

    }

    ...

}
      
    

當定位服務調用了回調函數指明連接已建立,那么就發出移除所有地理圍欄的請求。再發出請求后記得關閉連接。例如:

      
        public
      
      
        class
      
       MainActivity 
      
        extends
      
       FragmentActivity 
      
        implements
      
      
        

        ConnectionCallbacks,

        OnConnectionFailedListener,

        OnAddGeofencesResultListener {

    ...

    
      
      
        /**
      
      
        

     * Once the connection is available, send a request to remove the

     * Geofences. The method signature used depends on which type of

     * remove request was originally received.

     
      
      
        */
      
      
        private
      
      
        void
      
      
         onConnected(Bundle dataBundle) {

        
      
      
        /*
      
      
        

         * Choose what to do based on the request type set in

         * removeGeofences

         
      
      
        */
      
      
        switch
      
      
         (mRequestType) {

            ...

            
      
      
        case
      
      
         REMOVE_INTENT :

                mLocationClient.removeGeofences(

                        mGeofenceRequestIntent, 
      
      
        this
      
      
        );

                
      
      
        break
      
      
        ;

            ...

        }

    }

    ...

}
      
    

雖然對 removeGeofences(PendingIntent, LocationClient.OnRemoveGeofencesResultListener) 的調用后,服務端會馬上返回,但移除請求的結果在定位服務調用 onRemoveGeofencesByPendingIntentResult() 之前是不定的。下面的代碼片段展示了如何定義這一方法:

      
        public
      
      
        class
      
       MainActivity 
      
        extends
      
       FragmentActivity 
      
        implements
      
      
        

        ConnectionCallbacks,

        OnConnectionFailedListener,

        OnAddGeofencesResultListener {

    ...

    
      
      
        /**
      
      
        

     * When the request to remove geofences by PendingIntent returns,

     * handle the result.

     *

     *
      
      
        @param
      
      
         statusCode the code returned by Location Services

     *
      
      
        @param
      
      
         requestIntent The Intent used to request the removal.

     
      
      
        */
      
      
        

    @Override

    
      
      
        public
      
      
        void
      
       onRemoveGeofencesByPendingIntentResult(
      
        int
      
      
         statusCode,

            PendingIntent requestIntent) {

        
      
      
        //
      
      
         If removing the geofences was successful
      
      
        if
      
       (statusCode ==
      
         LocationStatusCodes.SUCCESS) {

            
      
      
        /*
      
      
        

             * Handle successful removal of geofences here.

             * You can send out a broadcast intent or update the UI.

             * geofences into the Intent's extended data.

             
      
      
        */
      
      
        

        } 
      
      
        else
      
      
         {

        
      
      
        //
      
      
         If adding the geocodes failed
      
      
        /*
      
      
        

             * Report errors here.

             * You can log the error using Log.e() or update

             * the UI.

             
      
      
        */
      
      
        

        }

        
      
      
        /*
      
      
        

         * Disconnect the location client regardless of the

         * request status, and indicate that a request is no

         * longer in progress

         
      
      
        */
      
      
        

        mInProgress 
      
      = 
      
        false
      
      
        ;

        mLocationClient.disconnect();

    }

    ...

}
      
    

移除單個地理圍欄

移除單個地理圍欄或者部分地理圍欄的過程同刪除全部地理圍欄相似。要指定你想要移除的地理圍欄,需要把地理圍欄的ID添加到一個String的 List 對象中。將這個 List 傳遞給 removeGeofences,該方法之后便開始移除。

通過添加一個移除地理圍欄請求類型的list,然后添加一個全局變量來存儲地理圍欄的list:

      
            ...

    
      
      
        //
      
      
         Enum type for controlling the type of removal requested
      
      
        public
      
      
        enum
      
       REQUEST_TYPE =
      
         {ADD, REMOVE_INTENT, REMOVE_LIST}

    
      
      
        //
      
      
         Store the list of geofence Ids to remove
      
      

    String<List> mGeofencesToRemove;
    

之后定義你想要移除的地理圍欄list。例如,在下面的例子中,要移除的 Geofence 的ID為“1”:

      
        public
      
      
        class
      
       MainActivity 
      
        extends
      
       FragmentActivity 
      
        implements
      
      
        

        ConnectionCallbacks,

        OnConnectionFailedListener,

        OnAddGeofencesResultListener {

    ...

        List
      
      <String> listOfGeofences =
      
        

                Collections.singletonList(
      
      "1"
      
        );

        removeGeofences(listOfGeofences);

    ...

}
      
    

下面的代碼片段定義了removeGeofences()方法:

      
        public
      
      
        class
      
       MainActivity 
      
        extends
      
       FragmentActivity 
      
        implements
      
      
        

        ConnectionCallbacks,

        OnConnectionFailedListener,

        OnAddGeofencesResultListener {

    ...

    
      
      
        /**
      
      
        

     * Start a request to remove monitoring by

     * calling LocationClient.connect()

     *

     
      
      
        */
      
      
        public
      
      
        void
      
       removeGeofences(List<String>
      
         geofenceIds) {

        
      
      
        //
      
      
         If Google Play services is unavailable, exit

        
      
      
        //
      
      
         Record the type of removal request
      
      

        mRequestType =
      
         REMOVE_LIST;

        
      
      
        /*
      
      
        

         * Test for Google Play services after setting the request type.

         * If Google Play services isn't present, the request can be

         * restarted.

         
      
      
        */
      
      
        if
      
       (!
      
        servicesConnected()) {

            
      
      
        return
      
      
        ;

        }

        
      
      
        //
      
      
         Store the list of geofences to remove
      
      

        mGeofencesToRemove =
      
         geofenceIds;

        
      
      
        /*
      
      
        

         * Create a new location client object. Since the current

         * activity class implements ConnectionCallbacks and

         * OnConnectionFailedListener, pass the current activity object

         * as the listener for both parameters

         
      
      
        */
      
      
        

        mLocationClient 
      
      = 
      
        new
      
       LocationClient(
      
        this
      
      , 
      
        this
      
      , 
      
        this
      
      
        );

        
      
      
        //
      
      
         If a request is not already underway
      
      
        if
      
       (!
      
        mInProgress) {

            
      
      
        //
      
      
         Indicate that a request is underway
      
      

            mInProgress = 
      
        true
      
      
        ;

            
      
      
        //
      
      
         Request a connection from the client to Location Services
      
      
                    mLocationClient.connect();

        } 
      
      
        else
      
      
         {

            
      
      
        /*
      
      
        

             * A request is already underway. You can handle

             * this situation by disconnecting the client,

             * re-setting the flag, and then re-trying the

             * request.

             
      
      
        */
      
      
        

        }

    }

    ...

}
      
    

當定位服務激活了回調函數表明這個鏈接已經建立以后,發出該請求來移除列表中的地理圍欄。在發出請求之后關閉連接。例如:

      
        public
      
      
        class
      
       MainActivity 
      
        extends
      
       FragmentActivity 
      
        implements
      
      
        

        ConnectionCallbacks,

        OnConnectionFailedListener,

        OnAddGeofencesResultListener {

    ...

    
      
      
        private
      
      
        void
      
      
         onConnected(Bundle dataBundle) {

        ...

        
      
      
        switch
      
      
         (mRequestType) {

        ...

        
      
      
        //
      
      
         If removeGeofencesById was called
      
      
        case
      
      
         REMOVE_LIST :

                mLocationClient.removeGeofences(

                        mGeofencesToRemove, 
      
      
        this
      
      
        );

                
      
      
        break
      
      
        ;

        ...

        }

        ...

    }

    ...

}
      
      
        ?
      
    

定義 onRemoveGeofencesByRequestIdsResult() 的實現。定位服務會激活該回調函數來指出這個移除地理圍欄的請求已經完成。在該方法中,檢查傳入的狀態碼然后采取對應的措施:

      
        public
      
      
        class
      
       MainActivity 
      
        extends
      
       FragmentActivity 
      
        implements
      
      
        

        ConnectionCallbacks,

        OnConnectionFailedListener,

        OnAddGeofencesResultListener {

    ...

    
      
      
        /**
      
      
        

     * When the request to remove geofences by IDs returns, handle the

     * result.

     *

     * 
      
      
        @param
      
      
         statusCode The code returned by Location Services

     * 
      
      
        @param
      
      
         geofenceRequestIds The IDs removed

     
      
      
        */
      
      
        

    @Override

    
      
      
        public
      
      
        void
      
      
         onRemoveGeofencesByRequestIdsResult(

            
      
      
        int
      
      
         statusCode, String[] geofenceRequestIds) {

        
      
      
        //
      
      
         If removing the geocodes was successful
      
      
        if
      
       (LocationStatusCodes.SUCCESS ==
      
         statusCode) {

            
      
      
        /*
      
      
        

             * Handle successful removal of geofences here.

             * You can send out a broadcast intent or update the UI.

             * geofences into the Intent's extended data.

             
      
      
        */
      
      
        

        } 
      
      
        else
      
      
         {

        
      
      
        //
      
      
         If removing the geofences failed
      
      
        /*
      
      
        

             * Report errors here.

             * You can log the error using Log.e() or update

             * the UI.

             
      
      
        */
      
      
        

        }

        
      
      
        //
      
      
         Indicate that a request is no longer in progress
      
      

        mInProgress = 
      
        false
      
      
        ;

        
      
      
        //
      
      
         Disconnect the location client
      
      
                mLocationClient.disconnect();

    }

    ...

}
      
    

你可以將地理圍欄和其它地點感知的功能結合起來,比如定期的地點更新或者行為認知等,這些會在該系列課程中的后續課程中展開。

在下一節課程中,會向你展示請求和接收activity更新。在定期的間隔中,定位服務可以給你發送有關用戶當前物理行為的信息。基于這一信息,你可以改變你的應用行為,例如,如果你檢測到用戶在步行而不在開車,你可以增加定期更新的間隔。

【Android Developers Training】 106. 創建并檢測地理圍欄


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 婷婷在线免费视频 | 日本久久中文字幕精品 | 久久精品亚洲 | 亚洲精品欧美日本中文字幕 | 四虎影视4hu4虎成人 | 亚洲精品久久99久久一区 | 一本本久综合久久爱 | 久久91精品久久久久久水蜜桃 | 久久精品国产欧美日韩亚洲 | 亚洲精品tv久久久久久久久久 | 国产一区二区亚洲精品 | 国产成人精品高清在线观看99 | 亚洲国产人成在线观看69网站 | 99热这里精品 | 久久久精品视频在线观看 | 久久天天躁夜夜躁2019 | 永久黄网站色视频免费观看99 | 国产成人a在一区线观看高清 | 99视频免费 | 国产精品免费久久久久影院 | 99爱在线视频这里只有精品 | 久久免费视频观看 | 色色视频网 | 亚洲另类网| 国产精品夜夜春夜夜爽久久 | 九九热精 | 久久精品国产午夜伦班片 | 天天干夜夜骑 | 日本涩涩网站 | 91亚洲在线 | 亚洲欧洲一区二区 | 日本中文字幕在线精品 | 手机在线一区二区三区 | 国产性色视频在线高清 | 性欧美高清come | 日韩欧美在线免费观看 | 91手机看片国产福利精品 | 按摩毛片 | 日韩字幕无线乱码 | 日韩欧美高清在线 | 老色99久久九九精品尤物 |