Android
Data objects
在Android中应用Parse GeoPoints实现用户和地点定位
30 分
在您的 android 应用中使用 parse geopoints 介绍 parse 允许您将现实世界的纬度和经度坐标与对象关联。将一个 parsegeopoint 添加到一个 parseuser , 您将能够轻松找出哪个用户离另一个用户最近,显示您应用的用户位置,并存储用户的位置信息,以及其他可能性。 您还可以将一个 parsegeopoint 关联到任何 parseobject 例如,如果您的应用与有实体分支的商店相关联,您将能够创建一个活动来显示这些商店的位置,或向用户显示哪个商店离他最近。另一个使用此关联的示例:如果您的应用是一个游戏,您创建了 parseobjects 来表示角色,向这些角色添加 parsegeopoints 将允许它们沿着玩家的路径显示。 本教程解释了如何通过 back4app 使用一些 parsegeopoint 的功能。 在完成本教程后,您将能够做到这一点: 随时可以在我们的 https //github com/back4app/android geopoints tutorial 中访问完整的 android 项目,该项目是通过本教程构建的。 先决条件 要完成本教程,我们需要: https //developer android com/studio/index html 在 back4app 上创建的用户注册 登录应用程序。 注意: 请按照用户注册 登录教程学习如何在 back4app 上创建用户注册 登录应用程序。 一台运行 android 4 0(冰淇淋三明治)或更新版本的真实设备。 注意: 使用本教程构建的应用程序在虚拟设备上可能无法按预期运行,甚至可能崩溃,因为它可能无法获取虚拟设备的当前位置。因此,我们强烈建议您使用真实设备来运行它。 1 设置 google api 密钥 要显示您在 parsegeopoint 中存储的位置,您需要显示地图。为此,使用 google maps activity 是很有趣的。在 android studio 中创建 google maps activity,请执行以下操作: 转到 文件 文件 > 新建 新建 > google google > google maps activity google maps activity 然后,它会自动创建一个 java java 文件,一个 布局 布局 文件和一个 值 值 文件,分别对应您创建的 google maps activity。 转到创建的 值 值 文件(您可以通过访问 app app > res res > values values > google maps api xml google maps api xml ),如下图所示。此文件将为您提供有关如何获取 google maps api 密钥的一些说明。基本上,您应该打开图中显示的链接。 3\ 打开后,您应该登录到您的 google 帐户,选择 创建项目 创建项目 选项并点击 继续 继续 。在创建项目时,google 将启用您的 api。 4\ 在您的 api 启用后,您将能够获取 api 密钥,点击 5\ 然后,您的密钥将被创建,您可以复制并粘贴到 值 值 文件中,粘贴到写有 您的密钥在这里 您的密钥在这里 的地方。 6\ 在您的 androidmanifest xml 文件中,必须包含以下使用权限。如果您按照上述说明创建了 google 地图活动,那么这些权限中的一个应该已经在您的清单中,无论如何,您需要这两个权限才能使您的应用正常工作,因此请检查它们是否在您的 androidmanifest xml 文件中,否则,请将它们插入其中。 1 \<uses permission android\ name="android permission access coarse location" /> 2 \<uses permission android\ name="android permission access fine location" /> 7\ 在你的 mapsactivity mapsactivity , 导入以下内容 1 // android dependencies 2 import android manifest; 3 import android app progressdialog; 4 import android content context; 5 import android content dialoginterface; 6 import android content intent; 7 import android content pm packagemanager; 8 import android location location; 9 import android location locationmanager; 10 import android support annotation nonnull; 11 import android support v4 app activitycompat; 12 import android support v4 app fragmentactivity; 13 import android os bundle; 14 import android util log; 15 import android view\ view; 16 import android widget button; 17 // google maps dependencies 18 import com google android gms maps cameraupdatefactory; 19 import com google android gms maps googlemap; 20 import com google android gms maps onmapreadycallback; 21 import com google android gms maps supportmapfragment; 22 import com google android gms maps model bitmapdescriptorfactory; 23 import com google android gms maps model latlng; 24 import com google android gms maps model markeroptions; 25 // parse dependencies 26 import com parse findcallback; 27 import com parse parseexception; 28 import com parse parsegeopoint; 29 import com parse parsequery; 30 import com parse parseuser; 31 // java dependencies 32 import java util list; 2 设置 back4app 控制面板以保存用户的位置 前往 https //www back4app com/ 登录,找到你的应用并打开其仪表板。 前往 核心 核心 > 浏览器 浏览器 > 用户 用户 , 如下图所示。 3\ 现在,创建一个新列以保存用户的位置。为此,请点击右上角的 编辑 编辑 按钮,如下所示。 4\ 然后,点击 添加列 添加列 5\ 在字段“您想存储什么类型的数据?”中,选择geopoint选项。 6\ 在字段“我们应该称它为?”中,输入“ 位置 ” 7\ 所以,点击添加列,如下图所示。 8\ 现在,您的应用程序能够存储用户的位置数据,您的 back4pp 控制面板中的用户类应如下所示: 3 在您的 back4pp 控制面板中保存用户当前位置 打开您的 mapsactivity mapsactivity ,在公共类 mapsactivity mapsactivity 中定义一个名为 request location request location 的整数,值为 1,以及一个 locationmanager locationmanager ,如下代码所示。 1 private static final int request location = 1; 2 locationmanager locationmanager; 2\ 在 oncreate oncreate 方法中创建 locationmanager locationmanager ,如下代码所示。 1 locationmanager = (locationmanager)getsystemservice(context location service); 3\ 要在您的 back4pp 控制面板中保存用户的位置,只需实现以下方法并在您的 onmapready onmapready 方法中调用它。 1 private void savecurrentuserlocation() { 2 // requesting permission to get user's location 3 if(activitycompat checkselfpermission(usersactivity this, manifest permission access fine location) != packagemanager permission granted && activitycompat checkselfpermission(usersactivity this, manifest permission access coarse location) != packagemanager permission granted){ 4 activitycompat requestpermissions(usersactivity this, new string\[]{android manifest permission access fine location}, request location); 5 } 6 else { 7 // getting last know user's location 8 location location = locationmanager getlastknownlocation(locationmanager network provider); 9 10 // checking if the location is null 11 if(location != null){ 12 // if it isn't, save it to back4app dashboard 13 parsegeopoint currentuserlocation = new parsegeopoint(location getlatitude(), location getlongitude()); 14 15 parseuser currentuser = parseuser getcurrentuser(); 16 17 if (currentuser != null) { 18 currentuser put("location", currentuserlocation); 19 currentuser saveinbackground(); 20 } else { 21 // do something like coming back to the login activity 22 } 23 } 24 else { 25 // if it is null, do something like displaying error and coming back to the menu activity 26 } 27 } 28 } 4\ 实现以下方法以确保 savecurrentuserlocation savecurrentuserlocation 方法正常工作是非常重要的。 1 @override 2 public void onrequestpermissionsresult(int requestcode, @nonnull string\[] permissions, @nonnull int\[] grantresults){ 3 super onrequestpermissionsresult(requestcode, permissions, grantresults); 4 5 switch (requestcode){ 6 case request location 7 savecurrentuserlocation(); 8 break; 9 } 10 } 4 获取用户的位置 要获取用户的位置,您需要找到当前用户,保存其位置,然后返回保存在您的 back4app 控制面板中的位置。 为此,请在您的 mapsactivity mapsactivity 中实现以下方法,并在需要时调用它。 1 / saving the current user location, using the savecurrentuserlocation method of step 3, to avoid 2 null pointer exception and also to return the user's most current location / 3 savecurrentuserlocation(); 4 private parsegeopoint getcurrentuserlocation(){ 5 6 // finding currentuser 7 parseuser currentuser = parseuser getcurrentuser(); 8 9 if (currentuser == null) { 10 // if it's not possible to find the user, do something like returning to login activity 11 } 12 // otherwise, return the current user location 13 return currentuser getparsegeopoint("location"); 14 15 } 5 在地图上显示当前用户的位置 要在地图上显示用户的位置,您需要检索用户的位置,然后使用检索到的信息在地图上创建一个标记。 为此,请在您的 mapsactivity mapsactivity 中实现以下方法,并在 onmapready onmapready 方法中调用它。 1 private void showcurrentuserinmap(final googlemap googlemap){ 2 3 // calling retrieve user's location method of step 4 4 parsegeopoint currentuserlocation = getcurrentuserlocation(); 5 6 // creating a marker in the map showing the current user location 7 latlng currentuser = new latlng(currentuserlocation getlatitude(), currentuserlocation getlongitude()); 8 googlemap addmarker(new markeroptions() position(currentuser) title(parseuser getcurrentuser() getusername()) icon(bitmapdescriptorfactory defaultmarker(bitmapdescriptorfactory hue red))); 9 10 // zoom the map to the currentuserlocation 11 googlemap animatecamera(cameraupdatefactory newlatlngzoom(currentuser, 5)); 12 } 6 查找与当前用户最近的用户 现在您有一堆与空间坐标相关的用户,找出哪个用户离另一个用户最近是很有意义的。这可以通过使用parsequery来完成。首先,您需要创建一个parseuser查询,并使用 wherenear wherenear , 指明您在back4app的user类中在哪一列进行查询(在这种情况下是“location”列),并且还要提供用于查询的参考parsegeopoint,以找到离当前用户位置最近的用户(在这种情况下是与当前用户位置相关的parsegeopoint)。以下代码实现了这一点 1 parsequery\<parseuser> query = parseuser getquery(); 2 query wherenear("location", getcurrentuserlocation()); 2\ 您可以通过添加限制来限制此查询的结果数量 setlimit setlimit 默认情况下,结果限制为100。由于 wherenear wherenear 限制将使查询检索按距离(从最近到最远)排序的用户数组,从当前用户位置开始,将要查找的近用户限制设置为数字2,查询的结果列表将仅包含两个用户:当前用户和离他最近的用户。以下代码将结果限制设置为2 1 query setlimit(2); 3\ 现在您已经限制了查询,让我们检索其结果。为此,您将调用一个 findinbackground findinbackground 方法,并将一个用户列表作为参数传递,在其中将存储查询的结果,以及一个parseexception来处理错误。为了避免错误,请不要忘记在查询运行后清除缓存结果。以下代码执行此操作 1 query findinbackground(new findcallback\<parseuser>() { 2 @override public void done(list\<parseuser> nearusers, parseexception e) { 3 if (e == null) { 4 // do something with the list of results of your query 5 } else { 6 // handle the error 7 } 8 } 9 }); 10 parsequery clearallcachedresults(); 11 } 4\ 如果没有错误发生,您将会在 nearusers nearusers 列表中看到当前用户(实际的当前用户和离他最近的用户)两个最接近的用户,现在您只需找出谁不是当前用户。为此,在 if (e == null) if (e == null) 块中使用以下代码 1 // avoiding null pointer 2 parseuser closestuser = parseuser getcurrentuser(); 3 // set the closestuser to the one that isn't the current user 4 for(int i = 0; i < nearusers size(); i++) { 5 if(!nearusers get(i) getobjectid() equals(parseuser getcurrentuser() getobjectid())) { 6 closestuser = nearusers get(i); 7 } 8 } 5\ 现在您知道谁是离当前用户最近的用户,您可以使用 distanceinkilometersto distanceinkilometersto 方法来测量他们之间的距离。为此,请使用以下代码 1 // finding and displaying the distance between the current user and the closest user to him 2 double distance = getcurrentuserlocation() distanceinkilometersto(closestuser getparsegeopoint("location")); 3 alertdisplayer("we found the closest user from you!", "it's " + closestuser getusername() + " \nyou are " + math round (distance 100 0) / 100 0 + " km from this user "); 上面使用的 alertdisplayer alertdisplayer 方法如下 1 private void alertdisplayer(string title,string message){ 2 android app alertdialog builder builder = new android app alertdialog builder(usersactivity this) 3 settitle(title) 4 setmessage(message) 5 setpositivebutton("ok", new dialoginterface onclicklistener() { 6 @override 7 public void onclick(dialoginterface dialog, int which) { 8 dialog cancel(); 9 } 10 }); 11 android app alertdialog ok = builder create(); 12 ok show(); 13 } 6\ 您还可以使用以下代码在地图上显示两个用户 1 // showing current user in map, using the method implemented in step 5 2 showcurrentuserinmap(mmap); 3 // creating a marker in the map showing the closest user to the current user location, using method implemented in step 4 4 latlng closestuserlocation = new latlng(closestuser getparsegeopoint("location") getlatitude(), closestuser getparsegeopoint("location") getlongitude()); 5 googlemap addmarker(new markeroptions() position(closestuserlocation) title(closestuser getusername()) icon(bitmapdescriptorfactory defaultmarker(bitmapdescriptorfactory hue green))); 6 // zoom the map to the currentuserlocation 7 googlemap animatecamera(cameraupdatefactory newlatlngzoom(closestuserlocation, 3)); 执行上述所有6个步骤的完整方法如下: 1 private void showclosestuser(final googlemap googlemap){ 2 parsequery\<parseuser> query = parseuser getquery(); 3 query wherenear("location", getcurrentuserlocation()); 4 // setting the limit of near users to find to 2, you'll have in the nearusers list only two users the current user and the closest user from the current 5 query setlimit(2); 6 query findinbackground(new findcallback\<parseuser>() { 7 @override public void done(list\<parseuser> nearusers, parseexception e) { 8 if (e == null) { 9 // avoiding null pointer 10 parseuser closestuser = parseuser getcurrentuser(); 11 // set the closestuser to the one that isn't the current user 12 for(int i = 0; i < nearusers size(); i++) { 13 if(!nearusers get(i) getobjectid() equals(parseuser getcurrentuser() getobjectid())) { 14 closestuser = nearusers get(i); 15 } 16 } 17 // finding and displaying the distance between the current user and the closest user to him, using method implemented in step 4 18 double distance = getcurrentuserlocation() distanceinkilometersto(closestuser getparsegeopoint("location")); 19 alertdisplayer("we found the closest user from you!", "it's " + closestuser getusername() + " \n you are " + math round (distance 100 0) / 100 0 + " km from this user "); 20 // showing current user in map, using the method implemented in step 5 21 showcurrentuserinmap(mmap); 22 // creating a marker in the map showing the closest user to the current user location 23 latlng closestuserlocation = new latlng(closestuser getparsegeopoint("location") getlatitude(), closestuser getparsegeopoint("location") getlongitude()); 24 googlemap addmarker(new markeroptions() position(closestuserlocation) title(closestuser getusername()) icon(bitmapdescriptorfactory defaultmarker(bitmapdescriptorfactory hue green))); 25 // zoom the map to the currentuserlocation 26 googlemap animatecamera(cameraupdatefactory newlatlngzoom(closestuserlocation, 3)); 27 } else { 28 log d("store", "error " + e getmessage()); 29 } 30 } 31 }); 32 parsequery clearallcachedresults(); 33 } 7 设置back4app以将parsegeopoint与parseobjects关联 假设您正在构建的示例应用程序与一组具有实体附属店的商店相关联。在地图上显示该商店的所有实体附属店将是很有趣的。为此,请在 back4pp dashboard 上创建一个 stores 类,将现有商店保存为 parseobjects,保存它们的位置,之后应用程序将能够查询实体附属店并在地图上显示它们的位置。以下步骤将帮助您完成此操作。 1 转到 https //www back4app com/ , 登录,找到您的应用程序并打开其仪表板。 2\ 转到 核心 核心 > 浏览器 浏览器 > 创建一个类 创建一个类 , 如下图所示。 3\ 在字段中选择您需要的 类的类型? 类的类型? , 选择 自定义 自定义 选项。 4\ 在字段 我们应该称它为? 我们应该称它为? , 输入 “stores” 然后点击 创建类 创建类 按钮。 5\ 然后会显示一个名为 “stores” 的新类,你应该在其中插入 2 列:一列数据类型为 字符串 字符串 称为 名称 名称 , 以及另一列数据类型为 地理点 地理点 称为 位置 位置 如果你不记得如何创建列,请返回第 2 步,那里解释了如何在 back4app 仪表板上创建列。你的类应该最终是这样的 6\ 现在,填写此类的信息。为此,请单击右上角菜单或页面中间的 添加一行 添加一行 按钮,如下图所示。 7\ 然后填写所需的信息:商店的名称及其纬度和经度。在插入一些数据后,您的商店类应如下图所示。如果您想插入更多数据,可以单击顶部的 添加一行 添加一行 按钮,或在数据最后一行下方的 + + 按钮。 现在您准备好在应用程序中使用商店的位置信息。 8 在地图上显示所有商店的位置 1\ 您可以通过使用 mapsactivity mapsactivity 显示您添加到类中的所有商店。首先,您需要创建一个 parseobject 查询,告知您要查询的 back4pp dashboard 类的名称(在这种情况下是“stores”类),并使用 whereexists whereexists , 指明您在 back4app 上进行查询的 store 类的列(在这种情况下是“location”列)。以下代码实现了这一点 1 parsequery\<parseobject> query = parsequery getquery("stores"); 2 query whereexists("location"); 2\ 现在您已经限制了查询,让我们检索其结果。为此,您将调用一个 findinbackground findinbackground 方法,并将一个商店列表作为参数传递,其中将存储查询的结果,以及一个 parseexception 来处理错误。 whereexists whereexists 限制将使只有与其位置相关联的 parsegeopoint 的类的 parseobjects 被存储在商店列表中。为了避免错误,请在查询运行后不要忘记清除缓存结果。以下代码实现了这一点 1 query findinbackground(new findcallback\<parseobject>() { 2 @override public void done(list\<parseobject> stores, parseexception e) { 3 if (e == null) { 4 // do something with the list of results of your query 5 } else { 6 // handle the error 7 } 8 } 9 }); 10 parsequery clearallcachedresults(); 11 } 3\ 如果没有发生错误,您将在 stores stores 列表中拥有所有与位置相关的商店,现在您只需循环显示它们在地图上。为此,在 if (e == null) if (e == null) 块中使用以下代码。 1 for(int i = 0; i < stores size(); i++) { 2 latlng storelocation = new latlng(stores get(i) getparsegeopoint("location") getlatitude(), stores get(i) getparsegeopoint("location") getlongitude()); 3 googlemap addmarker(new markeroptions() position(storelocation) title(stores get(i) getstring("name")) icon(bitmapdescriptorfactory defaultmarker(bitmapdescriptorfactory hue azure))); 4 } 完整的方法执行上述所有 3 个步骤如下。调用它以在 onmapready onmapready 方法上使其工作。 1 private void showstoresinmap(final googlemap googlemap){ 2 3 parsequery\<parseobject> query = parsequery getquery("stores"); 4 query whereexists("location"); 5 query findinbackground(new findcallback\<parseobject>() { 6 @override public void done(list\<parseobject> stores, parseexception e) { 7 if (e == null) { 8 for(int i = 0; i < stores size(); i++) { 9 latlng storelocation = new latlng(stores get(i) getparsegeopoint("location") getlatitude(), stores get(i) getparsegeopoint("location") getlongitude()); 10 googlemap addmarker(new markeroptions() position(storelocation) title(stores get(i) getstring("name")) icon(bitmapdescriptorfactory defaultmarker(bitmapdescriptorfactory hue azure))); 11 } 12 } else { 13 // handle the error 14 log d("store", "error " + e getmessage()); 15 } 16 } 17 }); 18 parsequery clearallcachedresults(); 19 } 9 显示离商店最近的用户 1\ 现在你有一堆与空间坐标相关的商店,找出哪个商店离用户最近是很好的。这可以通过使用 parsequery 来完成。首先,你需要创建一个 parseobject 查询,告知你想查询的 back4pp dashboard 类的名称(在这种情况下是“stores”类),并用 wherenear wherenear 限制它,告知你在 back4app 上进行查询的商店类的列(在这种情况下是“location”列)。以下代码实现了这一点 1 parsequery\<parseobject> query = parsequery getquery("stores"); 2 query wherenear("location", getcurrentuserlocation()); 2\ 你可以通过添加限制 setlimit setlimit , 来限制此查询的结果数量。默认情况下,结果限制为 100。由于 wherenear wherenear 限制将使查询检索按距离(从最近到最远)排序的用户数组,因此将近用户的限制设置为 1,查询的结果列表将只有一个商店:离当前用户最近的商店。以下代码将结果限制设置为 1 1 query setlimit(1); 3\ 现在您已经限制了查询,让我们检索其结果。为此,您将调用一个 findinbackground findinbackground 方法,并作为参数传递一个商店对象的列表,其中将存储查询的结果,以及一个用于处理错误的parseexception。为了避免错误,请在查询找到任何结果后不要忘记清除缓存的结果。以下代码执行此操作: 1 query findinbackground(new findcallback\<parseobject>() { 2 @override public void done(list\<parseobject> nearstores, parseexception e) { 3 if (e == null) { 4 // do something with the list of results of your query 5 } else { 6 // handle the error 7 } 8 } 9 }); 10 parsequery clearallcachedresults(); 11 } 4\ 如果没有错误发生,您将在 nearstores nearstores 列表中找到离当前用户最近的商店,现在您只需在 mapsactivity mapsactivity 中显示它。为此,在 if (e == null) if (e == null) 块中使用以下代码: 1 parseobject closeststore = nearstores get(0); 2 // showing current user location, using the method implemented in step 5 3 showcurrentuserinmap(mmap); 4 // finding and displaying the distance between the current user and the closest store to him, using method implemented in step 4 5 double distance = getcurrentuserlocation() distanceinkilometersto(closeststore getparsegeopoint("location")); 6 alertdisplayer("we found the closest store from you!", "it's " + closeststore getstring("name") + " \n you are " + math round (distance 100 0) / 100 0 + " km from this store "); 7 // creating a marker in the map showing the closest store to the current user 8 latlng closeststorelocation = new latlng(closeststore getparsegeopoint("location") getlatitude(), closeststore getparsegeopoint("location") getlongitude()); 9 googlemap addmarker(new markeroptions() position(closeststorelocation) title(closeststore getstring("name")) icon(bitmapdescriptorfactory defaultmarker(bitmapdescriptorfactory hue green))); 10 // zoom the map to the closeststorelocation 11 googlemap animatecamera(cameraupdatefactory newlatlngzoom(closeststorelocation, 3)); 上述使用的 alertdisplayer alertdisplayer 方法,与第6步(查找离当前用户最近的用户)相同。 执行上述所有4个步骤的完整方法如下: 1 private void showcloseststore(final googlemap googlemap){ 2 parsequery\<parseobject> query = parsequery getquery("stores"); 3 query wherenear("location", getcurrentuserlocation()); 4 // setting the limit of near stores to 1, you'll have in the nearstores list only one object the closest store from the current user 5 query setlimit(1); 6 query findinbackground(new findcallback\<parseobject>() { 7 @override public void done(list\<parseobject> nearstores, parseexception e) { 8 if (e == null) { 9 parseobject closeststore = nearstores get(0); 10 // showing current user location, using the method implemented in step 5 11 showcurrentuserinmap(mmap); 12 // finding and displaying the distance between the current user and the closest store to him, using method implemented in step 4 13 double distance = getcurrentuserlocation() distanceinkilometersto(closeststore getparsegeopoint("location")); 14 alertdisplayer("we found the closest store from you!", "it's " + closeststore getstring("name") + " \nyou are " + math round (distance 100 0) / 100 0 + " km from this store "); 15 // creating a marker in the map showing the closest store to the current user 16 latlng closeststorelocation = new latlng(closeststore getparsegeopoint("location") getlatitude(), closeststore getparsegeopoint("location") getlongitude()); 17 googlemap addmarker(new markeroptions() position(closeststorelocation) title(closeststore getstring("name")) icon(bitmapdescriptorfactory defaultmarker(bitmapdescriptorfactory hue green))); 18 // zoom the map to the closeststorelocation 19 googlemap animatecamera(cameraupdatefactory newlatlngzoom(closeststorelocation, 3)); 20 } else { 21 log d("store", "error " + e getmessage()); 22 } 23 } 24 }); 25 26 parsequery clearallcachedresults(); 27 28 } 10 测试你的应用 1\ 登录到 https //www back4app com/ 2\ 找到你的应用并点击 仪表板 仪表板 > 核心 核心 > 浏览器 浏览器 > 用户 用户 并创建一些与位置相关的用户,以便方法 showclosestuser showclosestuser 能够正常工作。 3\ 在真实设备上运行你的应用并注册一个账户。尝试每个功能! 4\ 返回 back4pp 仪表板,验证你的位置信息是否存储在你的用户行中。 完成了! 在这个阶段,你可以通过 back4app 使用 parsegeopoint 的一些功能!