Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 在 Android* 商務應用中實施地圖和地理圍欄特性

在 Android* 商務應用中實施地圖和地理圍欄特性

編輯:關於Android編程

摘要

本案例研究討論了如何將地圖和地理定位特性構建到 Android* 商務應用中,包括在 Google Maps* 上覆蓋商店位置,以及在設備進入商店地理圍欄鄰近區域時借助地理圍欄通知用戶。

目錄

  1. 摘要
  2. 概述
  3. 在 Google Maps 上顯示商店位置
    1. Google Maps Android API v2
    2. 在應用清單中指定應用設置
    3. 添加地圖 Fragment
    4. 發送地理圍欄通知
      1. 注冊和取消注冊地理圍欄
      2. 實施位置服務回調
      3. 實施意向服務
      4. 總結
      5. 參考文獻
      6. 作者介紹

        概述

        在本案例研究中,我們將會把地圖和地理定位功能集成到基於 Android 平板電腦的餐館商務應用中(圖 1)。 用戶可以從主菜單項“位置和地理圍欄”訪問地理定位功能(圖 2)。

        \

        圖 1 餐館應用主界面

        \

        圖 2 浮出控件菜單項

        在 Google Maps 上顯示商店位置<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+PC9wPgo8cD4KttTT2tK7v+7JzM7x06bTw7b40dSjrM/Uyr7JzLXq1Nq12M28yc+1xM671sO21NPDu6e3x7Oj1rG527rN09DTw6OozbwgM6OpoaMgR29vZ2xlIE1hcHMgQW5kcm9pZCBBUEkgv8nM4bmp0rvW1rzytaW1xLe9yr29qyBHb29nbGUgTWFwcyC8r7PJ1sEgQW5kcm9pZCDTptPDoaM8L3A+CjxwPgpHb29nbGUgTWFwcyBBbmRyb2lkIEFQSSB2MiA8YnI+CjwvcD4KPHA+CsrHIEdvb2dsZSBQbGF5ILf+zvEgQVBLILXE0ruyv7fWoaMgzqrBy7S0vajKudPDIEdvb2dsZSBNYXBzIEFuZHJvaWQgQVBJIHYyILXEIEFuZHJvaWQg06bTw6Os0OjSqs/C1NiyosXk1sMgR29vZ2xlIFBsYXkgt/7O8SBTREujrLvxyKEgQVBJIMPc1L+yotTa06bTw7XEIEFuZHJvaWRNYW5pZmVzdC54bWwgzsS8/tbQzO2808v50Oi1xMno1sPAtLbUv6q3oru3vrO9+NDQyejWw6GjPC9wPgo8cD4KytfPyKOsxOPQ6NKqsLTV1dLUz8LN+NW+yc+1xMu1w/fAtMno1sMgR29vZ2xlIFBsYXkgt/7O8SBTREujumh0dHA6Ly9kZXZlbG9wZXIuYW5kcm9pZC5jb20vZ29vZ2xlL3BsYXktc2VydmljZXMvc2V0dXAuaHRtbKGjPC9wPgo8cD4KyLu686OsxOPQ6NKqtNO5yLjov6q3osjL1LG/2NbGzKijqEdvb2dsZSBEZXZlbG9wZXJzIENvbnNvbGWjqcnPttTE47XEz+7Ev7340NDXorLhsqK78cih0ru49iBBUEkgw9zUv6O6aHR0cHM6Ly9jb25zb2xlLmRldmVsb3BlcnMuZ29vZ2xlLmNvbS9wcm9qZWN0oaMKIMTj0OjSqtTaIEFuZHJvaWRNYW5pZmVzdC54bWwgzsS8/tbQzO280yBBUEkgw9zUv6GjPC9wPgo8cD4KPGltZyBzcmM9"/uploadfile/Collfiles/20140724/2014072409390170.jpg" alt="\">

        圖 3 餐館應用在谷歌地圖上顯示商店的位置。

        在應用清單中指定應用設置

        為了使用 Google Maps Android API v2,需要將一些權限和特性指定為 元素的子項(代碼示例 1)。 其中包括網絡連接、外部存儲和位置訪問的一些必要權限。 此外,為了使用 Google Maps Android API,需要使用 OpenGL ES 版本 2 特性。

        01<uses-permission android:name=”android.permission.INTERNET"/>02<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>03<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>04<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>0507<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>08<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>09<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />10 11  <uses-feature12    android:glEsVersion="0x00020000"13    android:required="true"/>

        代碼示例 1。 建議在使用 Google Maps Android API 的應用上指定的權限。 包括 “ACCESS_MOCK_LOCATION” 權限(僅當需要使用模擬位置對應用進行測試時使用

        我們同樣需要將在 元素中獲得的 Google Play 服務版本和 API 密鑰作為 元素的子項(代碼示例 2)。
        1   
          <meta-data2   
                   android:name="com.google.android.gms.version"3   
                   android:value="@integer/google_play_services_version" />4   
              5   
           <meta-data6    
                android:name="com.google.android.maps.v2.API_KEY"7      
            android:value="copy
         your API Key here"/>
        

        代碼示例 2。 指定 Google Play 服務版本和 API 密鑰 **

        添加地圖 Fragment

        首先,在你的 activity 布局 xml 文件中,添加一個 MapFragment 元素(代碼示例 3)。

        1<fragment2    android:id="@+id/storelocationmap"3    android:layout_width="fill_parent"4    android:layout_height="fill_parent"5    android:name="com.google.android.gms.maps.MapFragment"6/>

        代碼示例 3。 在 Activity 布局中添加 MapFragment **

        在你的 activity 類中,您可以檢索 Google Maps MapFragment 對象並在每個商店位置處繪制商店圖標。

        0102private static final LatLng
         CHANDLER = new LatLng(33.455,-112.0668);0304private static final StoreLocation[]
         ALLRESTURANTLOCATIONS = new StoreLocation[]
         {05        new StoreLocation(new LatLng(33.455,-112.0668), new String("Phoenix,
         AZ")),06        new StoreLocation(new LatLng(33.5123,-111.9336), new String("SCOTTSDALE,
         AZ")),07        new StoreLocation(new LatLng(33.3333,-111.8335), new String("Chandler,
         AZ")),08        new StoreLocation(new LatLng(33.4296,-111.9436), new String("Tempe,
         AZ")),09        new StoreLocation(new LatLng(33.4152,-111.8315), new String("Mesa,
         AZ")),10        new StoreLocation(new LatLng(33.3525,-111.7896), new String("Gilbert,
         AZ"))11};1213      @Override14    protected void onCreate(Bundle
         savedInstanceState) {15        super.onCreate(savedInstanceState);16        setContentView(R.layout.geolocation_view);17         18        mMap
         = ((MapFragment) getFragmentManager().findFragmentById(R.id.storelocationmap)).getMap();19        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(CHANDLER,
         ZOOM_LEVEL));20        Drawable
         iconDrawable = getResources().getDrawable(R.drawable.ic_launcher);21        Bitmap
         iconBmp = ((BitmapDrawable) iconDrawable).getBitmap();22        for(int ix
         = 0;
         ix < ALLRESTURANTLOCATIONS.length; ix++) {23            mMap.addMarker(new MarkerOptions()24                .position(ALLRESTURANTLOCATIONS[ix].mLatLng)25                .icon(BitmapDescriptorFactory.fromBitmap(iconBmp)));26        }27

        代碼示例 4。 在 Google Maps 上繪制商店圖標 **

        發送地圖圍欄通知

        地理圍欄是一個圓形區域,該區域由一點的經緯度坐標和半徑決定。 Android 應用可以注冊帶有 Android 位置服務的地理圍欄。 Android 應用還可指定地理圍欄的使用期限。 無論地理圍欄何時切換,例如,當 Android 設備進入注冊的地理圍欄或從其中退出時,Android 位置服務都會即時通知 Android 應用。

        在我們的餐館應用中,我們能夠為每個商店位置定義地理圍欄。 當設備進入商店附近時,應用將會發送一條通知,如“您已進入最喜愛的餐館的附近!” (圖 4)。

        \

        圖 4 我們根據興趣點和半徑將地理圍欄定義為一個圓形范圍。

        注冊和取消注冊地理圍欄

        在 Android SDK 中,位置服務也是 Google Play 服務 APK 的一部分,位於 “Extras” 目錄下。

        如要申請地理圍欄監控,首先我們需要在應用的清單文件中指定 “ACCESS_FINE_LOCATION” 權限,該操作我們已經在上一部分中完成。

        此外,我們還需要查看 Google Play 服務的可用性(代碼示例 5 中的 checkGooglePlayServices() 方法)。 locationClient().connect() 調用與位置客戶端成功建立連接後,位置服務將會調用onConnected(Bundle bundle) 函數,位置客戶端可通過該函數申請添加或刪除地理圍欄。

        001public class GeolocationActivity extends Activity implements002        GooglePlayServicesClient.ConnectionCallbacks003004{005006    private LocationClient
         mLocationClient;007     008009 010    static class StoreLocation
         {011        public LatLng
         mLatLng;012        public String
         mId;013        StoreLocation(LatLng
         latlng, String id) {014            mLatLng
         = latlng;015            mId
         = id;016        }017    }018 019    @Override020    protected void onCreate(Bundle
         savedInstanceState) {021        super.onCreate(savedInstanceState);022        setContentView(R.layout.geolocation_view);023 024        mLocationClient
         = new LocationClient(this, this, this);025 026        //
         Create a new broadcast receiver to receive updates from the listeners and service027        mGeofenceBroadcastReceiver
         = new ResturantGeofenceReceiver();028 029        //
         Create an intent filter for the broadcast receiver030        mIntentFilter
         = new IntentFilter();031 032        //
         Action for broadcast Intents that report successful addition of geofences033        mIntentFilter.addAction(ACTION_GEOFENCES_ADDED);034 035        //
         Action for broadcast Intents that report successful removal of geofences036        mIntentFilter.addAction(ACTION_GEOFENCES_REMOVED);037 038        //
         Action for broadcast Intents containing various types of geofencing errors039        mIntentFilter.addAction(ACTION_GEOFENCE_ERROR);040 041        //
         All Location Services sample apps use this category042        mIntentFilter.addCategory(CATEGORY_LOCATION_SERVICES);043 044        createGeofences();045 046        mRegisterGeofenceButton
         = (Button)findViewById(R.id.geofence_switch);047        mGeofenceState
         = CAN_START_GEOFENCE;048     049    }050     051    @Override052    protected void onResume()
         {053        super.onResume();054        //
         Register the broadcast receiver to receive status updates055        LocalBroadcastManager.getInstance(this).registerReceiver(056            mGeofenceBroadcastReceiver,
         mIntentFilter);057    }058         059    /**060     *
         Create a Geofence list061     */062    public void createGeofences()
         {063        for(int ix=0;
         ix > ALLRESTURANTLOCATIONS.length; ix++) {064            Geofence
         fence = new Geofence.Builder()065                .setRequestId(ALLRESTURANTLOCATIONS[ix].mId)066                .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)067                .setCircularRegion(068                    ALLRESTURANTLOCATIONS[ix].mLatLng.latitude,
         ALLRESTURANTLOCATIONS[ix].mLatLng.longitude, GEOFENCERADIUS)069                .setExpirationDuration(Geofence.NEVER_EXPIRE)070                .build();071            mGeofenceList.add(fence);072        }073    }074 075    //
         callback function when the mRegisterGeofenceButton is clicked076    public void onRegisterGeofenceButtonClick(View
         view) {077        if (mGeofenceState
         == CAN_REGISTER_GEOFENCE) {078            registerGeofences();079            mGeofenceState
         = GEOFENCE_REGISTERED;080            mGeofenceButton.setText(R.string.unregister_geofence);081            mGeofenceButton.setClickable(true);            082        else {083            unregisterGeofences();084            mGeofenceButton.setText(R.string.register_geofence);085            mGeofenceButton.setClickable(true);086            mGeofenceState
         = CAN_REGISTER_GEOFENCE;087        }088    }089 090    private boolean checkGooglePlayServices()
         {091        int result
         = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);092        if (result
         == ConnectionResult.SUCCESS) {093            return true;094        } 095        else {096            Dialog
         errDialog = GooglePlayServicesUtil.getErrorDialog(097                    result,098                    this,099                    CONNECTION_FAILURE_RESOLUTION_REQUEST);100 101            if (errorDialog
         != null)
         {102                errorDialog.show();103            }104        }105        return false;106   }107 108 109    public void registerGeofences()
         {110     111        if (!checkGooglePlayServices())
         {112 113            return;114        }115        mRequestType
         = REQUEST_TYPE.ADD;116 117        try {118            //
         Try to add geofences119            requestConnectToLocationClient();120        } catch (UnsupportedOperationException
         e) {121            //
         handle the exception122        }123         124    }125 126    public void unregisterGeofences()
         {127 128        if (!checkGooglePlayServices())
         {129            return;130        }131 132        //
         Record the type of removal133          mRequestType
         = REQUEST_TYPE.REMOVE;134 135        //
         Try to make a removal request136        try {137            mCurrentIntent
         = getRequestPendingIntent());138            requestConnectToLocationClient();139 140        } catch (UnsupportedOperationException
         e) {141            //
         handle the exception142        }143    }144 145    public void requestConnectToLocationServices
         () throws UnsupportedOperationException
         {146        //
         If a request is not already in progress147        if (!mRequestInProgress)
         {148            mRequestInProgress
         = true;149 150            locationClient().connect();151        } 152        else {153            //
         Throw an exception and stop the request154            throw new UnsupportedOperationException();155        }156    }157 158 159    /**160     *
         Get a location client and disconnect from Location Services161     */162    private void requestDisconnectToLocationServices()
         {163 164        //
         A request is no longer in progress165        mRequestInProgress
         = false;166 167        locationClient().disconnect();168         169        if (mRequestType
         == REQUEST_TYPE.REMOVE) {170            mCurrentIntent.cancel();171        }172 173    }174 175    /**176     *
         returns A LocationClient object177     */178    private GooglePlayServicesClient
         locationClient() {179        if (mLocationClient
         == null)
         {180 181            mLocationClient
         = new LocationClient(this, this, this);182        }183        return mLocationClient;184 185}186 187    /*188     Called
         back from the Location Services when the request to connect the client finishes successfully. At this point, you can189request
         the current location or start periodic updates190     */191    @Override192    public void onConnected(Bundle
         bundle) {193        if (mRequestType
         == REQUEST_TYPE.ADD) {194        //
         Create a PendingIntent for Location Services to send when a geofence transition occurs195        mGeofencePendingIntent
         = createRequestPendingIntent();196 197        //
         Send a request to add the current geofences198        mLocationClient.addGeofences(mGeofenceList,
         mGeofencePendingIntent, this);199 200        } 201        else if (mRequestType
         == REQUEST_TYPE.REMOVE){202 203            mLocationClient.removeGeofences(mCurrentIntent, this);        204        } 205}206207}

        代碼示例 5。 通過位置服務申請地理圍欄監控 **

        實施位置服務回調

        位置服務申請通常是非阻塞或異步調用。 事實上,在上一部分的代碼示例 5 中,我們已經實施了這些函數中的一個:locationClient().connect() 調用和位置客戶端建立連接後,位置服務將會調用onConnected(Bundle bundle) 函數。 代碼示例 6 列出了我們需要實施的其他位置回調函數。

        001public class GeolocationActivity extends Activity implements002        OnAddGeofencesResultListener,003        OnRemoveGeofencesResultListener,004        GooglePlayServicesClient.ConnectionCallbacks,005        GooglePlayServicesClient.OnConnectionFailedListener
         {006007 008 009    @Override010    public void onDisconnected()
         {011        mRequestInProgress
         = false;012        mLocationClient
         = null;013}014 015     016 017    /*018     *
         Handle the result of adding the geofences019     */020    @Override021    public
         void onAddGeofencesResult(int statusCode, String[] geofenceRequestIds) {022 023        //
         Create a broadcast Intent that notifies other components of success or failure024        Intent
         broadcastIntent = new Intent();025 026        //
         Temp storage for messages027        String
         msg;028 029        //
         If adding the geocodes was successful030        if
         (LocationStatusCodes.SUCCESS == statusCode) {031 032            //
         Create a message containing all the geofence IDs added.033            msg
         = getString(R.string.add_geofences_result_success,034                    Arrays.toString(geofenceRequestIds));035 036            //
         Create an Intent to broadcast to the app037            broadcastIntent.setAction(ACTION_GEOFENCES_ADDED)038                           .addCategory(CATEGORY_LOCATION_SERVICES)039                           .putExtra(EXTRA_GEOFENCE_STATUS,
         msg);040        //
         If adding the geofences failed041        }
         else {042            msg
         = getString(043                    R.string.add_geofences_result_failure,044                    statusCode,045                    Arrays.toString(geofenceRequestIds)046            );047            broadcastIntent.setAction(ACTION_GEOFENCE_ERROR)048                           .addCategory(CATEGORY_LOCATION_SERVICES)049                           .putExtra(EXTRA_GEOFENCE_STATUS,
         msg);050        }051 052        LocalBroadcastManager.getInstance(this)053            .sendBroadcast(broadcastIntent);054 055        //
         request to disconnect the location client056        requestDisconnectToLocationServices();057    }058 059    /*060     *
         Implementation of OnConnectionFailedListener.onConnectionFailed061     *
         If a connection or disconnection request fails, report the error062     *
         connectionResult is passed in from Location Services063     */064    @Override065    public void onConnectionFailed(ConnectionResult
         connectionResult) {066        mInProgress
         = false;067        if (connectionResult.hasResolution())
         {068 069            try {070                connectionResult.startResolutionForResult(this,071                    CONNECTION_FAILURE_RESOLUTION_REQUEST);072            } 073            catch (SendIntentException
         e) {074                //
         log the error075            }076        } 077        else {078            Intent
         errorBroadcastIntent = new Intent(ACTION_CONNECTION_ERROR);079            errorBroadcastIntent.addCategory(CATEGORY_LOCATION_SERVICES)080                     .putExtra(EXTRA_CONNECTION_ERROR_CODE,081                                 connectionResult.getErrorCode());082             LocalBroadcastManager.getInstance(this)083                 .sendBroadcast(errorBroadcastIntent);084        }085    }086     087    @Override088    public void onRemoveGeofencesByPendingIntentResult(int statusCode,089            PendingIntent
         requestIntent) {090 091        //
         Create a broadcast Intent that notifies other components of success or failure092        Intent
         broadcastIntent = new Intent();093 094        //
         If removing the geofences was successful095        if (statusCode
         == LocationStatusCodes.SUCCESS) {096 
        097 // Set the action and add the result message 098 broadcastIntent.setAction(ACTION_GEOFENCES_REMOVED); 099 broadcastIntent.putExtra(EXTRA_GEOFENCE_STATUS, 100 getString(R.string.remove_geofences_intent_success)); 101 102 } 103 else { 104 // removing the geocodes failed 105 106 107 // Set the action and add the result message 108 broadcastIntent.setAction(ACTION_GEOFENCE_ERROR); 109 broadcastIntent.putExtra(EXTRA_GEOFENCE_STATUS, 110 getString(R.string.remove_geofences_intent_failure, 111 statusCode)); 112 } 113 LocalBroadcastManager.getInstance(this) 114 .sendBroadcast(broadcastIntent); 115 116 // request to disconnect the location client 117 requestDisconnectToLocationServices(); 118 } 119 120 121 public class ResturantGeofenceReceiver extends BroadcastReceiver { 122 123 124 @Override 125 public void onReceive(Context context, Intent intent) { 126 String action = intent.getAction(); 127 128 // Intent contains information about errors in adding or removing geofences 129 if (TextUtils.equals(action, ACTION_GEOFENCE_ERROR)) { 130 // handleGeofenceError(context, intent); 131 } 132 else if (TextUtils.equals(action, ACTION_GEOFENCES_ADDED) 133 || 134 TextUtils.equals(action, ACTION_GEOFENCES_REMOVED)) { 135 // handleGeofenceStatus(context, intent); 136 } 137 else if (TextUtils.equals(action, ACTION_GEOFENCE_TRANSITION)) { 138 // handleGeofenceTransition(context, intent); 139 } 140 else { 141 // handle error 142 } 143 144 } 145 } 146 147

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved