Android
Data objects
Using GeoPoints
34 min
using parse geopoints on your android app introduction parse allows you to associate real world latitude and longitude coordinates with an object adding a parsegeopoint to a parseuser , you will be able to easily find out which user is closest to another, show the locations of the users of your app and also store the user’s location information, among other possibilities you can also associate a parsegeopoint to any parseobject for example, if your app is associated with a store with physical affiliates, you will be able to create an activity to show the location of those stores or to show the user which store is closest to him another example of this association usage if your app is a game in which you created parseobjects to represent characters, adding parsegeopoints to these characters would allow them to be shown along the player’s path this tutorial explains how to use some features of parsegeopoint through back4app after following this tutorial, you will be able to do this at any time, you can access the complete android project built with this tutorial at our github repository prerequisites to complete this tutorial, we need android studio an user registration login app created on back4app note follow the user registration login tutorial to learn how to create an user registration login app on back4app a real device running android 4 0 (ice cream sandwich) or newer note it is very likely that the app built with this tutorial won't run as expected in a virtual device and may even crush because it might not retrieve the current location of the virtual device so we strongly recommend that you use a real device to run it 1 set up google api key to show the location you stored in a parsegeopoint, you will need to display a map to do that, it’s interesting to use a google maps activity in order to create a google maps activity in android studio, do the following go to file file > new new > google google > google maps activity google maps activity then, automatically, it will create a java java file, a layout layout file and a values values file corresponding to the google maps activity that you have created go to the created values values file (you can do this by accessing app app > res res > values values > google maps api xml google maps api xml ), as shown in the image below this file will give you some instructions on how to get a google maps api key basically, you should open the link shown in the image 3\ after opening it, you should login in your google account, select the create a project create a project option and click on continue continue while creating the project, google will enable your api 4\ after your api is enabled, you will be able to get an api key, to do so click on 5\ then, your key will be created and you can copy it and paste it in the values values file that lead you to this page, in the place where its written your key here your key here 6\ it’s important to have the uses permission below in your androidmanifest xml file if you created the google maps activity following the instructions above, then one of these permissions should already be in your manifest, anyway, you’ll need both of them for your app to work properly, so check if they are in your androidmanifest xml file, otherwise, insert them on it 1 \<uses permission android\ name="android permission access coarse location" /> 2 \<uses permission android\ name="android permission access fine location" /> 7\ at the beginning of your mapsactivity mapsactivity , import the following 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 set up back4app dashboard to save user’s location go to back4app website login, find your app and open its dashboard go to core core > browser browser > user user , as shown in the image below 3\ now, create a new column to save the user’s location to do so, click on the edit edit button in the top right, as shown below 4\ then, click on add a column add a column 5\ in the field what type of data do you want to store?, choose the geopoint option 6\ in the field what should we call it?, type “ location ” 7\ so, click on add column, as shown in the image below 8\ now, your app is able to store location data of users and your user class in your back4pp dashboard should look like this 3 save users current location in your back4pp dashboard open your mapsactivity mapsactivity and inside the public class mapsactivity mapsactivity define an int called request location request location with value 1 and a locationmanager locationmanager , as in the following code 1 private static final int request location = 1; 2 locationmanager locationmanager; 2\ in the oncreate oncreate method create the locationmanager locationmanager , as in the following code 1 locationmanager = (locationmanager)getsystemservice(context location service); 3\ to save user’s location in your back4pp dashboard, simply implement the following method and call it in your onmapready onmapready method 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\ it’s really important to implement the following method in order to make savecurrentuserlocation savecurrentuserlocation method works 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 retrieve user’s location to retrieve user’s location, you’ll need to find who is the current user, save its location and then return the location saved in your back4app dashboard in order to do that, implement the following method in your mapsactivity mapsactivity and call it when needed 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 showing current user’s location in map to display user’s location in the map, you’ll need to retrieve user’s location and then create a marker in the map using the information retrieved in order to do that, implement the following method in your mapsactivity mapsactivity and call it in the onmapready onmapready method 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 finding the closest user to the current one now that you have a bunch of users with spatial coordinates associated, it would be good to find out which user is closest to another this can be done by using a parsequery first, you’ll need to create a parseuser query and restrict it with wherenear wherenear , informing in which column of the user class on back4app you are doing the query (in this case the “location” column) and also inform the reference parsegeopoint for the query from which will be found the closest user (in this case the parsegeopoint associated to the current user location) the following code do that 1 parsequery\<parseuser> query = parseuser getquery(); 2 query wherenear("location", getcurrentuserlocation()); 2\ you can limit the number of results of this query adding to it the restriction setlimit setlimit by default, results are limited to 100 as the wherenear wherenear restriction will make the query retrieve an array of users ordered by distance (nearest to farthest) from currentuserlocation, setting the limit of close users to find to the number 2, the list of results of the query will only have two users the current and the closest user from him the following code set the limit of results to 2 1 query setlimit(2); 3\ now that you restricted your query, let’s retrieve its results in order to do that, you will call a findinbackground findinbackground method and pass as argument a list of users, in which it’ll be stored the results of the query and also a parseexception to handle errors to avoid errors, don’t forget to clear cached results after the query run the following code do that 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\ if no error occurs, you’ll have in the nearusers nearusers list the two closest users to the current user (the actual current user and the closest user from him), now you’ll only have to find who isn’t the current user to do that, inside the if (e == null) if (e == null) block use the following code 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\ now that you know who is the closest user to the current one you can mesure the distance between them using the distanceinkilometersto distanceinkilometersto method in order to do that, use the following code 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 "); the alertdisplayer alertdisplayer method used above, is the following 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\ you can also show both users in the map, using the following code 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)); the complete method that executes all 6 steps above is the following 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 set up back4app to associate parsegeopoint to parseobjects supose that the example app you are builiding is associated with a group of stores with physical affiliates it would be interesting to show all the physical affiliates of this store in the map in order to do so create a stores class on back4pp dashboard, save the existing stores as parseobjects, their locations and after that the app will be able to query the physical affiliates and display their possitions on the map the following steps will help you with that 1 go to back4app website , login, find your app and open its dashboard 2\ go to core core > browser browser > create a class create a class , as shown in the image below 3\ in the field what typ e of class do you need? e of class do you need? , choose the custom custom option 4\ in the field what should we call it? what should we call it? , type “stores” and then click on create class create class button 5\ then a new class called “stores” will be shown and you should insert 2 columns on it a collumn with data type string string called name name , as well as another column with data type geopoint geopoint called location location if you don’t remember how to create a column, go back to step 2, there it’s explained how to create a column at back4app dashboard your class should end up like this 6\ now, fill this class with information to do so, click on add a row add a row button in the menu on the top right or in the middle of the page, as shown in the image below 7\ then fill the row with the informations required the name of the store and its latitude and longitude after inserting some data, your stores class should look like the image below if you want to insert more data, you can click on the add a row add a row button on the top, or in the + + button bellow the last row of data now you are ready to use the location information of the stores in your app 8 display all the stores location on map 1\ you can show all the stores you added to your class on the mapsactivity mapsactivity by using a parsequery first, you’ll need to create a parseobject query, informing the name of the back4pp dashboard class you want to query (in this case the “stores” class), and restrict it with whereexists whereexists , informing the column of the store class on back4app you are doing the query (in this case the “location” column) the following code do that 1 parsequery\<parseobject> query = parsequery getquery("stores"); 2 query whereexists("location"); 2\ now that you restricted your query, let’s retrieve its results in order to do that, you will call a findinbackground findinbackground method and pass as argument a list of stores, in which it’ll be stored the results of the query and also a parseexception to handle errors the whereexists whereexists restriction will make only the parseobjects of the class that have a parsegeopoint associated to them indicating their location be stored in the list of stores to avoid errors, don’t forget to clear cached results after the query run the following code do that 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\ if no error occurs, you’ll have in the stores stores list all the stores with location associated, now you’ll only have to make a loop to display them on the map to do so, inside the if (e == null) if (e == null) block use the following code 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 } the complete method that executes all 3 steps above is below call it on the onmapready onmapready method for it to work 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 show closest user to a store 1\ now that you have a bunch of stores with spatial coordinates associated, it would be good to find out which store is closest to a user this can be done by using a parsequery first, you’ll need to create a parseobject query, informing the name of the back4pp dashboard class you want to query (in this case the “stores” class), and restrict it with wherenear wherenear , informing the column of the store class on back4app you are doing the query (in this case the “location” column) the following code do that 1 parsequery\<parseobject> query = parsequery getquery("stores"); 2 query wherenear("location", getcurrentuserlocation()); 2\ you can limit the number of results of this query adding to it the restriction setlimit setlimit by default, results are limited to 100 as the wherenear wherenear restriction will make the query retrieve an array of users ordered by distance (nearest to farthest) from currentuserlocation, setting the limit of close users to find to the number 1, the list of results of the query will only have one store the closest to the current user the following code set the limit of results to 1 1 query setlimit(1); 3\ now that you restricted your query, let’s retrieve its results in order to do that, you will call a findinbackground findinbackground method and pass as argument a list of store obejcts, in which it’ll be stored the results of the query and also a parseexception to handle errors to avoid errors, don’t forget to clear cached results after the query found any result the following code do that 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\ if no error occurs, you’ll have in the nearstores nearstores list the closest store to the current user, now you’ll only have to display it on the mapsactivity mapsactivity to do that, inside the if (e == null) if (e == null) block use the following code 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)); the alertdisplayer alertdisplayer method used above, is the same of the step 6 (finding the closest user to the current one) the complete method that executes all 4 steps above is the following 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 test your app 1\ login at back4app website https //www back4app com/ 2\ find your app and click on dashboard dashboard > core core > browser browser > user user and create some users with location associated to them to allow the method showclosestuser showclosestuser to work 3\ run your app in a real device and sign up an account try every feature! 4\ go back to back4pp dashboard and verify if your location is stored in your user row it’s done! at this stage, you can use some features of parsegeopoint through back4app!