一些条件如下:
- 即使设备没有GPS,我也希望能够获取纬度/经度。 - 如果用户不触摸或点击通知,我仍然希望获取纬度/经度,即使设备处于睡眠模式。 - 我也不想为整天运行后台服务,因为这会消耗设备的电量。
我会强烈建议在这里使用 Google Cloud Messaging
。这样做的好处是,一旦设备运行您的应用程序,您可以使其注册到 GCM
并向它们发送一条消息,让他们将自己的坐标注册到您的数据库中。
这种方法需要您实现一些服务器(例如,使用 PHP 的 Web 服务器)并让用户与之通信,因此流程如下:
您的服务器向所有已注册的设备发送广播消息,告诉它们需要注册到 GCM
服务。
设备接收到消息后,您需要实现 BroadcastReceiver
来获取纬度和经度,并通过 POST
请求将其发送到您的远程服务器,例如 http://www.mysuperserver.com/getlonglat.php
。
您的服务器获取两个参数后,对其进行保存或进行其他必要的操作。
如果您想采用这种方法,请按照以下步骤进行:
前往 https://console.developers.google.com。使用您的 Google 帐户注册一个新项目。这将为您提供一个 API 密钥和一个 Sender ID。
您需要使设备在 GCM
中注册到您的项目中。您可以通过将 Google Play Services
导入您的项目中来实现这一点,然后执行类似于以下内容的操作:
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
final String regid = gcm.register("YOUR_SENDER_ID");
此时,GCM
服务器已经知道该用户在您的项目中注册,并为其提供了一个regid
。
下一步是通知您自己的远程服务器该用户已完成注册,并在某个地方保存它所获得的regid
,以便稍后发送消息。因此,在客户端上,使用HTTP POST
请求针对您的服务器发送该regid
,并使用类似以下方式处理它:
$regid = $_POST['regid'];
if (($regId) && ($ipAddr))
sql_query("INSERT INTO gcm_subscribers(regid) VALUES($regid')");
完成后,您就知道已经在您的数据库中注册的用户。您可以SELECT
所有用户并发送信号要求他们将其坐标发送回您。在下面的示例中,参数将是首先是注册ID的数组,其次是要发送的消息(例如, $messageData = "sendMeYourCoords!"
)。
function sendNotification($registrationIdsArray, $messageData) {
$apiKey = "YOUR_API_KEY";
$headers = array("Content-Type:" . "application/json", "Authorization:" . "key=" . $apiKey);
$data = array(
'data' => $messageData,
'registration_ids' => $registrationIdsArray
);
$ch = curl_init();
curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
curl_setopt( $ch, CURLOPT_URL, "https://android.googleapis.com/gcm/send" );
curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0 );
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_POSTFIELDS, json_encode($data) );
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
在客户端中,只需处理GCM
消息并向远程服务器上的另一个URL
发送另一个POST
,并将longitude
和latitude
传递给它。为了处理这些消息,我在下面包含了一些链接。
如果不使用GPS获取坐标,似乎并没有太多解决方案,但还是有一些的。以下是一个示例:如何在Android中不使用GPS获取纬度经度值?
更多相关内容:
这是我所做的。
使用Google Play服务融合位置提供程序获取和存储位置,如此处所述here。
我建议避免设置一个服务,而是应该触发一个请求最后可用位置的闹钟。这进一步节省电池,因为应用程序不会寻找位置值,而是使用其他应用程序可能最近请求的位置。在我看来,接收到的响应相当准确。因此,可以像这样做:
public class LocationReceiver extends BroadcastReceiver {
// 每30秒重启服务
private static final long REPEAT_TIME = 1000 * 60 * 5;
private static final long REPEAT_DAILY = 1000 * 60 * 60 * 24;
@Override
public void onReceive(Context context, Intent intent)
{
Log.v("TEST", "Service loaded at start");
AlarmManager service = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 0);
Intent i = new Intent(context, ServiceStartReceiver.class);
PendingIntent pending = PendingIntent.getBroadcast(context, 0, i,PendingIntent.FLAG_CANCEL_CURRENT);
service.setInexactRepeating(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis(), REPEAT_TIME, pending);
}
}
由于您没有提到您想要实时更新,我认为您可以将所有数据转储到临时SQLite数据库中。
创建一个接收器以侦听网络中的更改,当通过wifi时,只需将所有数据发送到您的服务器。在执行此操作时,您可以更加聪明,仅在积累了一定数量的条目或在周期性间隔时发送。
或者,服务器可以通过GCM mnotification向应用程序发送ping,这也可以触发将数据发送到您的服务器。this是一个惊人的教程,描述了向应用程序发送GCM消息。
最后,here提到了一些非常有趣的位置策略。您可以根据用户活动或其他上下文选择何时触发位置保存。