I am developing an Android app which takes the current location of the user and displays a list of restaurants close to his/her location. The restaurants' data is available to me (i.e I do have the lat/long of each restaurant I want to display in the search results). I can't use Google Places API, because I need to show only those restaurants that are available in our database(in our website). My question is how do I access my database(or even an URL),which is on a computer, to extract the restaurants' data and display as search results in my android app?
I am actually making a Seamless ( http://bit.ly/Jp7pUN ) type application for my company.
I am a complete newbie to android app development. So, pardon me if this is really a very broad or a stupid question. Please just tell me what topics I need to study to implement this. I would study and do it myself.
Thanks.
You will need:
a Sqlite database to store the restaurants and their longitude/latitude
a MapView to display the map (Don't forget to register your Google Maps API key)
a map overlay to show the markers on the map
GPS access to get the user's location (needs the appropriate Android permission)
a simple search algorithm that retrieves a result set of restaurants within x distance of the user's location
EDIT
If your database is stored on a server, you will need a way to query the server, preferably using an HTTP-based protocol such as REST. It is useful (but not required) to cache the restaurant locations on the Android device (using Sqlite), in case the user is offline (The good news: Since you can use Java both on Android and the server, 90% of your data access layer you will only need to write once).
For the data transfer from server to the Android client, JSON is a popular format.
To acces database on your computer (not SQLite on Android) you should use url for your database server changing localhost to: 10.0.2.2. But in case your database will be on the Internet - you should create maybe some REST API to get the data you need. Then use HttpClient to fetch the data from server.
Everything that you need is in Developer Guide: MapView
And for retrieving current location I advice using MyLocationOverlay
For example (url to server):
//public static final String SERVER_ADDRESS = "http://10.0.2.2:3000"; // for localhost server
public static final String SERVER_ADDRESS = "http://railsserver.herokuapp.com"; //for remote server
Accessing data on your server - this depends on that how you implement (and using what thechnology) your server (REST API?, WebService?, Plain HTML?) and what will be the format of the response from server (JSON? XML?, etc.)
I suggest using JSON because it is easy to parse using included classes in Android SDK:
String json = execute(new HttpGet(Constants.SERVER_URL + "/fetchData"));
JSONObject responseJSON = new JSONObject(json);
if(responseJSON.has("auth_error")) {
throw new IOException("fetchData_error");
}
Related
I am creating an android app to record a user's activity using Google Maps SDK and the Google Play Services Location API. I am attempting to retrieve the user's elevation based on a given latitude and longitude. I originally used Location#getAltitude() but then realised that does not give the elevation above sea level.
I proceeded to use the open elevation API using the following query string:
String url = "https://api.open-elevation.com/api/v1/lookup?locations=" + latLng.latitude + "," + latLng.longitude;
However, that API appears to be much too slow in generating a response. I then found the Google Maps Elevation API which we can make a request using a URL also. However, we need to pass an API key and I do not want to pass this API key in the URL string and end up committing it to the remote repository.
In this repo (https://github.com/googlemaps/google-maps-services-java) I found the class:
/src/main/java/com/google/maps/ElevationApi.java which I thought I could use to avoid messing around with http requests.
In my gradle, I included this dependency:
implementation 'com.google.maps:google-maps-services:0.18.0'
At the moment, the code to retrieve the elevation is as follows:
ElevationApi.getByPoint(new GeoApiContext.Builder().apiKey(API_KEY).build(), latLng)
.setCallback(new PendingResult.Callback<ElevationResult>() {
#Override
public void onResult(ElevationResult result) {
consumer.doAction(result.elevation);
}
#Override
public void onFailure(Throwable e) {
e.printStackTrace();
}
});
What do I pass in for API_KEY here since I don't want to commit it to the repository? I have an api key defined in local.properties for maps, however, like so:
MAPS_API_KEY=<API_KEY_HERE>
Basically, my question is, can I define an API key in a properties file that is not committed to GitHub and then reference it in the code?
Thanks for any help.
Update:
I have managed to read the API key from local.properties using gradle but got an exception from the ElevationApi saying API 21+ expected, but was 30...strange. So I went back to the open-elevation API with the following Volley request:
/**
* Calculates elevation gain for the provided recording service
* #param recordingService the recording service to calculate elevation gain for
* #param response the handler to consume the elevation gain with
*/
public static void calculateElevationGain(RecordingService recordingService, ActionHandlerConsumer<Double> response) {
ArrayList<Location> locations = recordingService.getLocations();
JSONArray array = constructLocations(locations);
try {
if (array != null) {
RequestQueue requestQueue = Volley.newRequestQueue(recordingService);
String url = "https://api.open-elevation.com/api/v1/lookup";
JSONObject requestHeader = new JSONObject(); // TODO this seems very slow
requestHeader.put("locations", array);
JsonObjectRequest request = new JsonObjectRequest(Request.Method.POST, url, requestHeader,
response1 -> handleSuccessfulResponse(response1, response), RecordingUtils::handleErrorResponse);
request.setRetryPolicy(new DefaultRetryPolicy(500000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
requestQueue.add(request);
}
} catch (JSONException ex) {
ex.printStackTrace();
}
}
I had to set the timeout to a high number not sure how hight it should be because I was getting Volley timeout errors due to the slow response times.
Are there any other ways I can retrieve elevation about sea level?
Yeah, open-elevation.com has intermittent issues with timeouts and latency.
There are some alternatives listed on this GIS stack exchange question Seeking alternative to Google Maps Elevation API. I'm the developer of Open Topo Data which is the most-voted answer over there. You can host your own server with docker, and I also have a free public API which has pretty good latency and uptime.
There's also GPXZ as an alternative to the Google Elevation API with higher-quality data, but it requires an API key so would have the same issue as with Google Maps.
I advise a different direction: stay with the Google and the API key, but employ best practices regarding secrets and source repositories. Since you are dealing with an Android app and not a webapp your key can be somewhat safe inside your app binary (versus a key in a web deployed app is exposed).
Bets practices:
Do not commit the API key. The best to achieve this is to exclude the file which contains the key from the source control repo. That can simply be done with .gitignore. For example this Codelab has a file with the secret, but it has a dummy value and normally this file should be excluded from the source. It is only there because that is an educational code lab.
As a security measure take advantage of GitGuardian to scan your repos in case you'd accidentally push an API key. In such events you'd get a notification. As for me I forked that Geospatial API codelab and saw the key file was in the gitignore and I accidentally pushed a key.
In case you accidentally push a key in a commit it's not enough to reverse the commit and delete the file! Scavenger bots will still find the information in your git history. Rather immediately disable the key and generate another one.
If you are dealing with a webapp you can restrict the API key usage to your webapp's domain. Similarly you can restrict the key to specific Android app signatures (don't forget to add your developer environment's signature) too. This guarantees that even if someone steals the key they probably won't be able to use it.
Is it possible using custom OSRM server (Docker) for routing in navigation SDK? If i have custom streets in postgrey db, how can i calculate route on this streets?
Something as
NavigationRoute.builder(this)
.baseUrl("my server url")
does make request to my server but with additional params in query which i dont want :
/route/v1/driving/directions/v5/mapbox/driving-traffic/
I need just
/route/v1/driving/
Is it possible or exist some lib which converts osrm format to mapbox format?
I've found that it's reasonably trivial to use OSRM as a backing server for the Graphhopper Navigation API (which was forked from Mapbox I believe). I haven't tried using it directly with the Mapbox SDKs, but it might be worth a shot. Basically all I had to do was start up a forwarding server that would grab the coordinates and route parameters and pass them to OSRM, then add a request UUID on the way back to stop the SDK from complaining. I implemented the server in Ruby using Sinatra, and the code is below:
require 'net/http'
require 'sinatra'
require 'sinatra/json'
get '/directions/v5/:user/driving/:coordinates' do
uri = URI("http://router.project-osrm.org/route/v1/driving/#{params['coordinates']}")
uri.query = URI.encode_www_form({
alternatives: params['alternatives'],
continue_straight: params['continue_straight'],
geometries: params['geometries'],
overview: params['overview'],
steps: params['steps']
})
res = JSON.parse(Net::HTTP.get_response(uri).body)
res["uuid"] = SecureRandom.uuid
json(res)
end
Now, I save data in datastore of google cloud.
module-backend
#Entity
public class ComprarProducto {
#Id
private String producto;
private boolean comprado;
public ComprarProducto() {
}
public ComprarProducto(String producto) {
this.producto = producto;
this.comprado = false;
}
...
}
Example data of CompraProducto
This data is displayed in a listview. When I add one item, the list is updated and saved in datastore.For save data I use AsyncTask in app.
Then, If I add one item in device1, I want to see that listview as both device1 as device2 is updated, but I don't know how to do it.
I use too GCM (google cloud messaging) and I've got to send a message to devices but only this. I want to see the data update in the device 2 without taking any action.
I want to see the data update in the device 2 without taking any
action.
This is not possible without somehow notifying from the backend server that new data has been saved to datastore. Sending a push notification to device2 (or all other devices or whatever) would definitely be the correct way to do it. What you do is have the push notification tell device2 to query datastore.
If you really don't want to use GCM you COULD have device2 just query datastore every couple minutes but that is not recommended. The correct way to do it is to use GCM to give your device2 a "tickle" to indicate that there is new data in datastore and to query accordingly.
Not sure what kind of app you are building but these are some options.
I am trying to get the Connections or user's friends info from LinkedIn using LinkedIn jar for android and example given in google code, but i wont get Connections using linkedInApiClient.getConnectionsForCurrentUser() this method call it returns null, but i can access user current profile info using linkedInApiClient.getProfileForCurrentUser()
can any body suggest me how to get User connections information in linkedIn in android. Or guide me the the wright way.
I got the solution for the above ask question, what I was doing wrong, was that we have to pass an argument of the ProfileField information we want, like this:
final Set<ProfileField> connectionFields = EnumSet.of(ProfileField.ID, ProfileField.MAIN_ADDRESS,
ProfileField.PHONE_NUMBERS, ProfileField.LOCATION,
ProfileField.LOCATION_COUNTRY, ProfileField.LOCATION_NAME,
ProfileField.FIRST_NAME, ProfileField.LAST_NAME, ProfileField.HEADLINE,
ProfileField.INDUSTRY, ProfileField.CURRENT_STATUS,
ProfileField.CURRENT_STATUS_TIMESTAMP, ProfileField.API_STANDARD_PROFILE_REQUEST,
ProfileField.EDUCATIONS, ProfileField.PUBLIC_PROFILE_URL, ProfileField.POSITIONS,
ProfileField.LOCATION, ProfileField.PICTURE_URL);
Connections connections = client.getConnectionsForCurrentUser(connectionFields);
I'm new to server side.
I'm creating a database app for my company that stores links to all our marketing videos. Each entry is a url(to video), description, industry etc.
I already have the front end somewhat set up in HTML/JavaScript. Using a local XML source file, it populates a list with video names, and has text fields for all props of the video item.
Here's my question:
How do I handle updating my view when I send the form data (new entry) to the back end?
Should I insert a new entry based on local data?
Should I wait for the response from the server, and if success then update view based on local data?
Or, same as above, but update view based on back end data?
The goal is to make sure my view always reflects the state of data on the back end.
(Back end is Java / Google App Engine)
When using AJAX:
There is a callback function included in it, which triggers asynchronously when the response of the request comes back from the server.
In this function you can call your page update functions to execute on the page updating processes.