码迷,mamicode.com
首页 > 移动开发 > 详细

在 Android* 商务应用中实施地图和地理围栏特性

时间:2014-07-23 18:10:08      阅读:1954      评论:0      收藏:0      [点我收藏+]

标签:ndk   intelandroid   x86   android   intel   

摘要

本案例研究讨论了如何将地图和地理定位特性构建到 Android* 商务应用中,包括在 Google Maps* 上覆盖商店位置,以及在设备进入商店地理围栏邻近区域时借助地理围栏通知用户。

目录

  1. 摘要
  2. 概述
  3. 在 Google Maps 上显示商店位置
    1. Google Maps Android API v2
    2. 在应用清单中指定应用设置
    3. 添加地图 Fragment
  4. 发送地理围栏通知
    1. 注册和取消注册地理围栏
    2. 实施位置服务回调
    3. 实施意向服务
  5. 总结
  6. 参考文献
  7. 作者介绍

概述

在本案例研究中,我们将会把地图和地理定位功能集成到基于 Android 平板电脑的餐馆商务应用中(图 1)。 用户可以从主菜单项“位置和地理围栏”访问地理定位功能(图 2)。

bubuko.com,布布扣

                                                                                                图 1 餐馆应用主界面

bubuko.com,布布扣

                                                                                                 图 2 浮出控件菜单项

在 Google Maps 上显示商店位置

对于一款商务应用而言,显示商店在地图上的位置对用户非常直观和有用(图 3)。 Google Maps Android API 可提供一种简单的方式将 Google Maps 集成至 Android 应用。

Google Maps Android API v2 

是 Google Play 服务 APK 的一部分。 为了创建使用 Google Maps Android API v2 的 Android 应用,需要下载并配置 Google Play 服务 SDK,获取 API 密钥并在应用的 AndroidManifest.xml 文件中添加所需的设置来对开发环境进行设置。

首先,你需要按照以下网站上的说明来设置 Google Play 服务 SDK:http://developer.android.com/google/play-services/setup.html

然后,你需要从谷歌开发人员控制台(Google Developers Console)上对你的项目进行注册并获取一个 API 密钥:https://console.developers.google.com/project。 你需要在 AndroidManifest.xml 文件中添加 API 密钥。

bubuko.com,布布扣

                                                                                  图 3 餐馆应用在谷歌地图上显示商店的位置。

在应用清单中指定应用设置

为了使用 Google Maps Android API v2,需要将一些权限和特性指定为 <manifest> 元素的子项(代码示例 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"/>
05<!-- The following two permissions are not required to use
06     Google Maps Android API v2, but are recommended. -->
07<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-feature
12    android:glEsVersion="0x00020000"
13    android:required="true"/>

代码示例 1。 建议在使用 Google Maps Android API 的应用上指定的权限。 包括 “ACCESS_MOCK_LOCATION” 权限(仅当需要使用模拟位置对应用进行测试时使用

我们同样需要将在 <meta-data> 元素中获得的 Google Play 服务版本和 API 密钥作为 <application> 元素的子项(代码示例 2)。
1     <meta-data
2              android:name="com.google.android.gms.version"
3              android:value="@integer/google_play_services_version" />
4         
5      <meta-data
6            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<fragment
2    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 对象并在每个商店位置处绘制商店图标。

01
02private static final LatLng CHANDLER = new LatLng(33.455,-112.0668);
03
04private 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};
12…   
13      @Override
14    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)。

bubuko.com,布布扣

图 4 我们根据兴趣点和半径将地理围栏定义为一个圆形范围。

注册和取消注册地理围栏

在 Android SDK 中,位置服务也是 Google Play 服务 APK 的一部分,位于 “Extras” 目录下。

如要申请地理围栏监控,首先我们需要在应用的清单文件中指定 “ACCESS_FINE_LOCATION” 权限,该操作我们已经在上一部分中完成。

此外,我们还需要查看 Google Play 服务的可用性(代码示例 5 中的 checkGooglePlayServices() 方法)。 locationClient().connect() 调用与位置客户端成功建立连接后,位置服务将会调用onConnected(Bundle bundle) 函数,位置客户端可通过该函数申请添加或删除地理围栏。

001public class GeolocationActivity extends Activity implements
002        GooglePlayServicesClient.ConnectionCallbacks
003
004{
005…  
006    private LocationClient mLocationClient;
007     
008
009 
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    @Override
020    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 service
027        mGeofenceBroadcastReceiver = new ResturantGeofenceReceiver();
028 
029        // Create an intent filter for the broadcast receiver
030        mIntentFilter = new IntentFilter();
031 
032        // Action for broadcast Intents that report successful addition of geofences
033        mIntentFilter.addAction(ACTION_GEOFENCES_ADDED);
034 
035        // Action for broadcast Intents that report successful removal of geofences
036        mIntentFilter.addAction(ACTION_GEOFENCES_REMOVED);
037 
038        // Action for broadcast Intents containing various types of geofencing errors
039        mIntentFilter.addAction(ACTION_GEOFENCE_ERROR);
040 
041        // All Location Services sample apps use this category
042        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    @Override
052    protected void onResume() {
053        super.onResume();
054        // Register the broadcast receiver to receive status updates
055        LocalBroadcastManager.getInstance(this).registerReceiver(
056            mGeofenceBroadcastReceiver, mIntentFilter);
057    }
058         
059    /**
060     * Create a Geofence list
061     */
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 clicked
076    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 geofences
119            requestConnectToLocationClient();
120        } catch (UnsupportedOperationException e) {
121            // handle the exception
122        }
123         
124    }
125 
126    public void unregisterGeofences() {
127 
128        if (!checkGooglePlayServices()) {
129            return;
130        }
131 
132        // Record the type of removal
133          mRequestType = REQUEST_TYPE.REMOVE;
134 
135        // Try to make a removal request
136        try {
137            mCurrentIntent = getRequestPendingIntent());
138            requestConnectToLocationClient();
139 
140        } catch (UnsupportedOperationException e) {
141            // handle the exception
142        }
143    }
144 
145    public void requestConnectToLocationServices () throws UnsupportedOperationException {
146        // If a request is not already in progress
147        if (!mRequestInProgress) {
148            mRequestInProgress = true;
149 
150            locationClient().connect();
151        }
152        else {
153            // Throw an exception and stop the request
154            throw new UnsupportedOperationException();
155        }
156    }
157 
158 
159    /**
160     * Get a location client and disconnect from Location Services
161     */
162    private void requestDisconnectToLocationServices() {
163 
164        // A request is no longer in progress
165        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 object
177     */
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 can
189request the current location or start periodic updates
190     */
191    @Override
192    public void onConnected(Bundle bundle) {
193        if (mRequestType == REQUEST_TYPE.ADD) {
194        // Create a PendingIntent for Location Services to send when a geofence transition occurs
195        mGeofencePendingIntent = createRequestPendingIntent();
196 
197        // Send a request to add the current geofences
198        mLocationClient.addGeofences(mGeofenceList, mGeofencePendingIntent, this);
199 
200        }
201        else if (mRequestType == REQUEST_TYPE.REMOVE){
202 
203            mLocationClient.removeGeofences(mCurrentIntent, this);       
204        }
205}
206
207}

代码示例 5。 通过位置服务申请地理围栏监控 **

实施位置服务回调

位置服务申请通常是非阻塞或异步调用。 事实上,在上一部分的代码示例 5 中,我们已经实施了这些函数中的一个:locationClient().connect() 调用和位置客户端建立连接后,位置服务将会调用onConnected(Bundle bundle) 函数。 代码示例 6 列出了我们需要实施的其他位置回调函数。

001public class GeolocationActivity extends Activity implements
002        OnAddGeofencesResultListener,
003        OnRemoveGeofencesResultListener,
004        GooglePlayServicesClient.ConnectionCallbacks,
005        GooglePlayServicesClient.OnConnectionFailedListener {
006…  
007 
008 
009    @Override
010    public void onDisconnected() {
011        mRequestInProgress = false;
012        mLocationClient = null;
013}
014 
015     
016 
017    /*
018     * Handle the result of adding the geofences
019     */
020    @Override
021    public void onAddGeofencesResult(int statusCode, String[] geofenceRequestIds) {
022 
023        // Create a broadcast Intent that notifies other components of success or failure
024        Intent broadcastIntent = new Intent();
025 
026        // Temp storage for messages
027        String msg;
028 
029        // If adding the geocodes was successful
030        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 app
037            broadcastIntent.setAction(ACTION_GEOFENCES_ADDED)
038                           .addCategory(CATEGORY_LOCATION_SERVICES)
039                           .putExtra(EXTRA_GEOFENCE_STATUS, msg);
040        // If adding the geofences failed
041        } 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 client
056        requestDisconnectToLocationServices();
057    }
058 
059    /*
060     * Implementation of OnConnectionFailedListener.onConnectionFailed
061     * If a connection or disconnection request fails, report the error
062     * connectionResult is passed in from Location Services
063     */
064    @Override
065    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 error
075            }
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    @Override
088    public void onRemoveGeofencesByPendingIntentResult(int statusCode,
089            PendingIntent requestIntent) {
090 
091        // Create a broadcast Intent that notifies other components of success or failure
092        Intent broadcastIntent = new Intent();
093 
094        // If removing the geofences was successful
095        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  


在 Android* 商务应用中实施地图和地理围栏特性

标签:ndk   intelandroid   x86   android   intel   

原文地址:http://blog.csdn.net/x86android/article/details/38067605

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!