设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

谷歌Proximity Alerts教程

2014-6-16 14:09| 发布者: joejoe0332| 查看: 4615| 评论: 0|原作者: gagayu|来自: 伯乐在线

摘要: 智能手机正在逐渐统治整个手机世界,这是一个显而易见的事实。自从GPS设备被普遍的内嵌到智能手机中,它给那些利用地理定位的应用程序提供了极大的帮助。 其中一类程序是采用基于定位的服务(Location Based Service ...
  智能手机正在逐渐统治整个手机世界,这是一个显而易见的事实。自从GPS设备被普遍的内嵌到智能手机中,它给那些利用地理定位的应用程序提供了极大的帮助。 其中一类程序是采用基于定位的服务(Location Based Service),它是利用数据来计算用户所在位置的。程序通常用的技术是geocoding(从地理数据中寻找相关的地理坐标,如一条街的位置)和reverse geocoding(根据提供的坐标来提供信息)。另一类程序则采用Proximity Alerts。像它的名字那样,当用户的位置接近某个特定的Point of Interest(POI)时会进行提示。随着大量的程序打算应用这项技术,并伴有宣传精彩的示例,Proximity alert将会是接下来几年的热点。在这个教程中,我将展示怎样去利用Android的内嵌Proximity alert功能。


  在开始之前,简单的了解一下基于定位的程序或geocoding会对接下来的阅读带来极大的帮助。你可能需要要读一下我之前的几篇教程,如 “Android Location Based Services Application – GPS location”和“Android Reverse Geocoding with Yahoo API – PlaceFinder”。另一个需要提醒的是,这篇教程是受“Developing Proximity Alerts for Mobile Applications using the Android Platform”这篇文章启发而生。 这篇文章分为四个部分,对于初学者一些地方可能会稍显复杂并带来一些困难。基于这些原因,我决定写一篇相对更短更易懂的教程。


  我们将会创建一个简单的程序,它存储的一个点坐标会被用户触发并且当用户接近这个点推送消息。 当用户到达那个点坐标时会根据需求获取消息。


  我们首先创建一个Eclipse项目开始,并命名为“AndroidProximityAlertProject”。接下来,为程序创建一个Main Activity然后命名为ProxAlertActivity。 下面是程序的主页面:



  这里是UI界面的布局,命名为main.xml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?xml version="1.0" encoding="utf-8"?>
 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
>
 
    <EditText
        android:id="@+id/point_latitude"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="25dip"
        android:layout_marginRight="25dip"
    />
     
    <EditText
        android:id="@+id/point_longitude"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="25dip"
        android:layout_marginRight="25dip"
    />
         
    <Button
        android:id="@+id/find_coordinates_button"
        android:text="Find Coordinates"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
    />
     
    <Button
        android:id="@+id/save_point_button"
        android:text="Save Point"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
    />
     
</LinearLayout>


  现在我们开始做一些有意思的东西。首先,我们需要一个到LocationManager class的引用,提供系统的位置服务。你可以通过getSystemService方法从activity中获得。然后,(如果用户的位置发生改变)可以通过requestLocationUpdates方法来获得通知。在开发Proximity Alerts的时候,这并不是必须的要求,但是在这里我需要用它计算POI和用户位置之间的距离。在我们的示例中,设备在任何时候都可以调用getLastKnownLocation方法获取某个指定提供者的最后位置。最后,我们会用到addProximityAlert方法设定一个proximity alert。它可以指定你想要坐标(纬度、经度)和半径。 如果我们想要在一段特定的时间监视某个alert,还可以给那个alert设置过期时间。我们还可以提供PendingIntent,当设备进入或者离开一个监测到的alert区域时发出intent。


  示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
    package com.javacodegeeks.android.lbs;
    import java.text.DecimalFormat;
    import java.text.NumberFormat;
    import android.app.Activity;
    import android.app.PendingIntent;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.content.SharedPreferences;
    import android.location.Location;
    import android.location.LocationListener;
    import android.location.LocationManager;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.Toast;
    public class ProxAlertActivity extends Activity {
     
    private static final long MINIMUM_DISTANCECHANGE_FOR_UPDATE = 1; // in Meters
    private static final long MINIMUM_TIME_BETWEEN_UPDATE = 1000; // in Milliseconds
     
    private static final long POINT_RADIUS = 1000; // in Meters
    private static final long PROX_ALERT_EXPIRATION = -1;
 
    private static final String POINT_LATITUDE_KEY = "POINT_LATITUDE_KEY";
    private static final String POINT_LONGITUDE_KEY = "POINT_LONGITUDE_KEY";
     
    private static final String PROX_ALERT_INTENT =
         "com.javacodegeeks.android.lbs.ProximityAlert";
     
    private static final NumberFormat nf = new DecimalFormat("##.########");
     
    private LocationManager locationManager;
     
    private EditText latitudeEditText;
    private EditText longitudeEditText;
    private Button findCoordinatesButton;
    private Button savePointButton;
     
    @Override
    public void onCreate(Bundle savedInstanceState) {
         
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
         
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
 
        locationManager.requestLocationUpdates(
                        LocationManager.GPS_PROVIDER,
                        MINIMUM_TIME_BETWEEN_UPDATE,
                        MINIMUM_DISTANCECHANGE_FOR_UPDATE,
                        new MyLocationListener()
        );
         
        latitudeEditText = (EditText) findViewById(R.id.point_latitude);
        longitudeEditText = (EditText) findViewById(R.id.point_longitude);
        findCoordinatesButton = (Button) findViewById(R.id.find_coordinates_button);
        savePointButton = (Button) findViewById(R.id.save_point_button);
         
        findCoordinatesButton.setOnClickListener(new OnClickListener() {           
            @Override
            public void onClick(View v) {
                populateCoordinatesFromLastKnownLocation();
            }
        });
         
        savePointButton.setOnClickListener(new OnClickListener() {           
            @Override
            public void onClick(View v) {
                saveProximityAlertPoint();
            }
        });
        
    }
     
    private void saveProximityAlertPoint() {
        Location location =
            locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        if (location==null) {
            Toast.makeText(this, "No last known location. Aborting...",
                Toast.LENGTH_LONG).show();
            return;
        }
        saveCoordinatesInPreferences((float)location.getLatitude(),
               (float)location.getLongitude());
        addProximityAlert(location.getLatitude(), location.getLongitude());
    }
 
    private void addProximityAlert(double latitude, double longitude) {
         
        Intent intent = new Intent(PROX_ALERT_INTENT);
        PendingIntent proximityIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
         
        locationManager.addProximityAlert(
            latitude, // the latitude of the central point of the alert region
            longitude, // the longitude of the central point of the alert region
            POINT_RADIUS, // the radius of the central point of the alert region, in meters
            PROX_ALERT_EXPIRATION, // time for this proximity alert, in milliseconds, or -1 to indicate no expiration
            proximityIntent // will be used to generate an Intent to fire when entry to or exit from the alert region is detected
       );
         
       IntentFilter filter = new IntentFilter(PROX_ALERT_INTENT); 
       registerReceiver(new ProximityIntentReceiver(), filter);
        
    }
 
    private void populateCoordinatesFromLastKnownLocation() {
        Location location =
            locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        if (location!=null) {
            latitudeEditText.setText(nf.format(location.getLatitude()));
            longitudeEditText.setText(nf.format(location.getLongitude()));
        }
    }
     
    private void saveCoordinatesInPreferences(float latitude, float longitude) {
        SharedPreferences prefs =
           this.getSharedPreferences(getClass().getSimpleName(),
                           Context.MODE_PRIVATE);
        SharedPreferences.Editor prefsEditor = prefs.edit();
        prefsEditor.putFloat(POINT_LATITUDE_KEY, latitude);
        prefsEditor.putFloat(POINT_LONGITUDE_KEY, longitude);
        prefsEditor.commit();
    }
     
    private Location retrievelocationFromPreferences() {
        SharedPreferences prefs =
           this.getSharedPreferences(getClass().getSimpleName(),
                           Context.MODE_PRIVATE);
        Location location = new Location("POINT_LOCATION");
        location.setLatitude(prefs.getFloat(POINT_LATITUDE_KEY, 0));
        location.setLongitude(prefs.getFloat(POINT_LONGITUDE_KEY, 0));
        return location;
    }
     
    public class MyLocationListener implements LocationListener {
        public void onLocationChanged(Location location) {
            Location pointLocation = retrievelocationFromPreferences();
            float distance = location.distanceTo(pointLocation);
            Toast.makeText(ProxAlertActivity.this,
                    "Distance from Point:"+distance, Toast.LENGTH_LONG).show();
        }
        public void onStatusChanged(String s, int i, Bundle b) {           
        }
        public void onProviderDisabled(String s) {
        }
        public void onProviderEnabled(String s) {           
        }
    }
}




  在onCreate方法中,我们用了location manager并加入一个自定义类,它实现了LocatioListener接口。可以让我们通过onLocationChanged方法得到位置变换的通知。接下来,看一下怎样去处理更新。我们会使用不同的UI控件给按钮添加onClickListeners。


  当用户想要得到目前的坐标时,populateCoordinatesFromLastKnownLocation方法会被调用。在方法内部,使用getLastKnownLocation方法来得到Location对象,位置信息将会被填充到EditText控件。


  同样的,当位置信息第一次被获取时,用户想要保存坐标并向saveProxityAlertPoint提供alert(添加POI)。我们可以将经度和纬度以preference data的方式用SharedPreferences类来保存下来,详情请见SharedPreferences.Editor。最后,我们通过getBrodcast静态方法来创建一个PendingIntent。对于这种封装过的intent,我们创建一个intentFilter并使用registerReceiver方法来绑定一个自定义BroadcastReceiver和intentfiler。需要提醒的是,这种绑定还可以通过manifest来实现。


  现在,我们来看一下如何来处理用户位置变化。在实现接口的MyLocationListener类里,我们从SharedPreference里获取存储的位置信息(retrievelocationFromPreferences)。然后,通过distranceTo方法计算两个位置(POI和现在位置)的距离。通过这个计算,我们才会知道是否真正进入了某个区域。


  第一步,处理进入POI事件。 可以通过继承BroadcastReceiver的类(ProximityIntentReceiver)来实现。当proximity alert被触发,会返回一个自定义intent(之前绑定的locationManager)。处理过程发生在onReceive方法里,它会被事件(进出POI区域)调用。在方法内部,我们从相关intent获取KEY_PROXIMITY_ENTERING key(用来定义proximity alert类型是进入-true,还是离开-false))。


  示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
    package com.javacodegeeks.android.lbs;
    import android.app.Notification;
    import android.app.NotificationManager;
    import android.app.PendingIntent;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.graphics.Color;
    import android.location.LocationManager;
    import android.util.Log;
 
    public class ProximityIntentReceiver extends BroadcastReceiver {
     
    private static final int NOTIFICATION_ID = 1000;
 
    @Override
    public void onReceive(Context context, Intent intent) {
         
        String key = LocationManager.KEY_PROXIMITY_ENTERING;
 
        Boolean entering = intent.getBooleanExtra(key, false);
         
        if (entering) {
            Log.d(getClass().getSimpleName(), "entering");
        }
        else {
            Log.d(getClass().getSimpleName(), "exiting");
        }
         
        NotificationManager notificationManager =
            (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
         
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, null, 0);       
         
        Notification notification = createNotification();
        notification.setLatestEventInfo(context,
            "Proximity Alert!", "You are near your point of interest.", pendingIntent);
         
        notificationManager.notify(NOTIFICATION_ID, notification);
         
    }
     
    private Notification createNotification() {
        Notification notification = new Notification();
         
        notification.icon = R.drawable.ic_menu_notifications;
        notification.when = System.currentTimeMillis();
         
        notification.flags |= Notification.FLAG_AUTO_CANCEL;
        notification.flags |= Notification.FLAG_SHOW_LIGHTS;
         
        notification.defaults |= Notification.DEFAULT_VIBRATE;
        notification.defaults |= Notification.DEFAULT_LIGHTS;
         
        notification.ledARGB = Color.WHITE;
        notification.ledOnMS = 1500;
        notification.ledOffMS = 1500;
         
        return notification;
    }
}


  代码简洁明了。当我们定义了一个进入或离开的proximity alert,就可以提供一个自定义的推送了。要实现它,首先需要引用一个合适的Service,比如NotificationMananger。通过这个Service,我们发送通知给用户,并封装合适的推送对象。推送的方式是可定制的,如包括震动或者闪光灯等。我们还可以添加特定的图标在状态栏显示。如果只是简单添加标题和信息,适合调用setLastestEventInfo方法。 你可以在这里查看关于notification的详细内容。除此之外,我们可以通过PendingIntent来引导Activity进行下意识地点击推送。 为了让代码更通俗易懂,这里我就不这样做了。


  我们最后得到的manifest代码如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="utf-8"?>
 
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.javacodegeeks.android.lbs"
      android:versionCode="1"
      android:versionName="1.0">
       
    <application android:icon="@drawable/icon" android:label="@string/app_name">
         
        <activity android:name=".ProxAlertActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>    
 
    </application>
     
    <uses-sdk android:minSdkVersion="3" />
    
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.VIBRATE" />
 
</manifest>


  别忘了,添加相应的Permission到Manifest里:


  现在可以测试我们的程序了。启动Eclipse配置,然后跳转到DDMS界面查看Emulation Control标签,可以发现一个Location Controls选项。它可以给模拟器发送模拟的位置数据。在Manual标签里,点击Send按钮,这样就能生成一些坐标。




  在此之后,GPS提供者将会知道最后一次请求的已知位置。所以,点击“find Coordinates”按钮你将会得到:


  点击“Save Point”来声明当前位置为POI。 当前位置坐标会被保存到SharedPreference并且Proximity Alert会被添加到location manager中。


  接下来,让我们模拟用户接近指定位置的事件。我们会更改坐标值,例如更改维度(从37.422006到37.522006)。现在我们离的POI很远。现在我们假装我们正在接近它,所以把坐标改的近一点(从37,52206到37.423006)。


  当两点之间的半径达到预警要求(之前设置为1000米)时会得到提示。这时,创建并通过notification manager推送消息。推送的消息如下:


  好了,大功告成。本文通过一个简单的示例介绍了如何使用Android Platform来实施Proximity alerts。你可以从这里下载示例项目的Eclipse项目代码。


  本文由 伯乐在线 - gagayu 翻译自 javacodegeeks。欢迎加入Android小组。转载请参见文章末尾处的要求。


酷毙

雷人

鲜花

鸡蛋

漂亮
  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部