我正在开发一个应用程序,需要实时(如3秒的更新)我的应用程序的所有用户的位置,这些用户也知道其他用户位置,在地图中,例如:
这个位置需要是实时的,因为所有用户都可以访问地图,他们需要知道应用程序的用户在哪一刻,才能找到自己。
我需要做些什么才能让我的应用程序以gps坐标实时获取所有用户的位置(以供以后在地图上使用)?
我不是要求一个完整的应用程序,我只想知道如何获得每个用户的坐标,顺便说一句,如果一个答案包含如何将坐标放在地图上,那将是非常有用的!并将得到赏金
答案 0 :(得分:20)
您希望您的用户以固定的时间间隔检索他们的坐标,因此您(最低限度)需要:
良好的中央服务器(或服务器)。考虑到每3秒发送一个位置并拥有(例如)100个用户将导致良好的信息请求突发,因此它还需要一个良好的基础设施。
向您的客户广播信息的一些技术。获得信息后,您希望将其传播给您的用户,让他们知道谁在他们附近。
存储您从用户那里获得的信息的一些技术:最相应的一个:数据库。
所以,一步一步:
会出现什么样的坐标?
有两种类型的位置坐标:
在获取坐标信息时,网络位置通常比GPS快。此外,GPS在某些情况下可能非常慢,例如室内位置,更糟糕的是,它会相当快地耗尽电池。但是,网络位置提供商依赖于手机信号塔,实际上它将返回的值(不是您当前的真实位置),因此GPS位置相当准确。我建议使用后者。
如何获取坐标?
这是一个已在SO
上多次解决过的主题,只需进行搜索即可获得大量信息。关于每X次发送用户的位置,可以使用LocationManager
来完成。所以你要定义这样的东西:
LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, REFRESH_TIME, MIN_DISTANCE, locationListener);
这将请求用户的当前位置,每REFRESH_TIME
次刷新一次(它是自定义常量,您可以将其设置为您想要的任何位置,但您必须对其进行调整取决于您的远程服务器的技术能力),MIN_DISTANCE
(同样在这里,它是一个常数)作为位置更新之间的最小距离(以米为单位),并应提供结果到将处理结果的Listener
。这个监听器应该是这样的:
private final LocationListener locationListener = new LocationListener() {
@Override
public void onLocationChanged(final Location location) {
...
}
};
因此,每当用户的位置根据定义的上述2个参数发生变化时,将调用此onLocationChanged()
方法。
请勿忘记将此行添加到AndroidManifest
文件中:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
好的,我在这个方法中加入了什么?
您向远程服务器发出请求,通知您当前的位置。最简单的方法是部署一个Web服务器,该服务器将使用您喜欢的语言(PHP
,Python
...)提供Web服务,并相应地处理请求。最简单的通知方式是对Web服务执行简单的HTTP POST
请求,因此内部的代码将是这样的:
final HttpClient httpclient = new DefaultHttpClient();
final HttpPost httppost = new HttpPost("http://www.yourremoteserver.com/mywebservice.php");
try {
final List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("Latitude", String.valueOf(location.getLatitude()));
nameValuePairs.add(new BasicNameValuePair("Longitude", String.valueOf(location.getLongitude()));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);
}
catch (final ClientProtocolException e) { e.printStackTrace(); }
catch (final IOException e) { e.printStackTrace(); }
即便如此,现在您的远程服务器将接收您的数据。但还有其他一些缺失:如何识别每个用户?根据您的实施情况,您可能希望发送用户的IP地址,或者更有可能发送用户名的IP地址。因此,在后一种情况下,您可以像这样添加另一个BasicNameValuePair
:
nameValuePairs.add(new BasicNameValuePair("username", methodThatReturnsUsersName());
如果您想使用IP地址,则不需要发送它,更好地依赖服务器可能收到的信息(否则,它可能会被篡改)。
如何处理服务器端的所有信息?
我假设您使用PHP
(因为这是我已知的语言),但您可以随意使用,唯一的条件是它必须是一些http友好语言。您可以通过这种方式获取已发送的变量:
<?php
$latitude = $_POST['Latitude'];
$longitude = $_POST['Longitude'];
$username = $_POST['username'];
?>
例如,将其存储在包含3个字段的表中:
mysqli_query("INSERT INTO current_locations(longitude, latitude, username) VALUES($latitude, $longitude, '$username')", $my_link);
如果您想要包含用户的IP地址,可以通过以下方式获取:
$ip = $_SERVER['REMOTE_ADDR'];
这就是全部。您已收到用户的信息并将其存储在数据库中。
很好,现在如何在用户中传播所有信息?
您需要一些模拟multicast
协议的机制来发送所有信息。这种情况看起来非常适合使用Google Cloud Messaging
。我已经写了an answer a time ago来描述如何实现它,所以我不会在这里扩展它。总结:您已经知道谁已经注册到您的Google Cloud Messaging
项目中,您现在可以向他们发送您需要的信息。需要考虑的几点:
您的用户会在没有任何同情心的情况下从他们的位置发送数据而受到轰炸。过了一会儿,如果你有足够的用户,你可以每分钟存储数千个地点。不知何故,你必须传播这些信息并删除无用的信息。
在这种方法中,似乎管理所有数据量的最佳方法是使用同步方法来处理数据库中的所有当前信息。如果您的服务器是linux / unix环境,那么您可能希望使用cron
。在MS下,编程任务就足够了。
也就是说,您需要触发一个脚本,该脚本将提取所有数据并再次以您喜欢的语言对其进行处理,并将其放入cron
/编程任务中每隔一定时间被解雇。
提示1 :您可能希望自己的应用在全球范围内使用。因此,如果您在阿根廷,为什么要将您的位置发送给位于中国的用户?为此,您可以在该脚本中实现一些距离算法,对于每个位置,将根据距离阈值计算最近的用户,并将该用户的信息发送给他们。其中最着名的是Haversine formula,但有很多。找一个你认为合适的并实现它。这将减少无用的发送信息,但是,计算需要更多时间,因此您的远程服务器规范也很重要。作为类比,你不会像Hub那样行事,而是作为Switch。
提示2 :我已经提到了存储的信息量。每次运行此脚本时,都应提取当时的整个数据集,决定向每个位置发送数据,然后从数据库中删除。一旦发送,这些信息将被淘汰,那么为什么要继续存储它并使你的数据库变得庞大而低效呢?
如何显示收到的坐标?
Google有Google Maps
的API,我建议您使用它。标记的相关信息是here。如果您阅读了我上面提到的关于Google Cloud Messaging
和GCM documentation
的引用链接,您会看到IntentService
处理发送到的public class GCMprocess extends IntentService {
public GCMprocess() { super("GCMIntentService"); }
@Override
protected void onHandleIntent(final Intent intent) {
final GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
final String messageType = gcm.getMessageType(intent);
final Bundle extras = intent.getExtras();
if ((!extras.isEmpty()) && (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType))) {
// This method will be fired for each location of each user sent by your cron'ed script
String longitude = extras.getString("longitude");
String latitude = extras.getString("latitude");
String username = extras.getString("username");
// And this places the content in your google map:
private GoogleMap mMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
mMap.addMarker(new MarkerOptions().position(new LatLng(Double.parseDouble(longitude), Double.parseDouble(latitude))).title("User " + username));
}
GCMBroadcastReceiver.completeWakefulIntent(intent);
}
}
消息特定的客户。所以在这里,类似于上面关于发送您的位置的代码,现在您接收一个位置。所以你需要实现这样的东西:
{{1}}