Spoiled by Python (e.g. requests.post(url, data={'p1':'v1','p2':'v2'}, headers={'H1': 'V1'})), I am looking for an equivalent to use on Android.
My code is already run on separate Threads, so I don't need AsyncWhatever.
HttpURLConnection is recommended for Android because it is all kinds of lightweight, but the equivalent of the Python request is... large.
I see multiple partial (e.g. pre-encoded params string) solutions, and several problems to work around. Rather than risk mistakes or overlooking something writing it myself, I ask:
Is such a wrapper available already, a request(Method, String, Map<String,String>, Map<String,String>), or similar?
I expect such a solution to need little code per call, and manage all weirdness (e.g. pre-Froyo keepAlive hack) itself.
I suppose I have the right solution for you. Had the same problem (spoiled by Node.js request) and didn't like the "interface" of HttpURLConnection.
You can find a tiny library without dependencies which wrappes HttpURLConnection in a way that not so common use cases can be implemented by using the wrapped HUC. It's called DavidWebb. There is also a link to alternative libraries in case you miss something.
A typical POST request with JSON payload and JSON response with some headers would look like this:
JSONObject postObj = new JSONObject();
postObj.put("p1", "v1");
postObj.put("p2", "v2");
Webb webb = Webb.create();
Response<JSONObject> response = webb
.post("http://www.example.com/app/myresource")
.header("x-date-header", new Date())
.header("x-other-header", "some-text")
.body(postObj)
.connectTimeout(3000)
.asJsonObject();
if (response.isSuccess()) {
JSONObject outcome = response.getBody();
// ...
} else {
System.out.println(response.getStatusCode());
System.out.println(response.getResponseMessage());
System.out.println(response.getErrorBody());
}
There are many ways to set default values for the Webb instance and use or overwrite them in the Request object.
The library is well tested, especially on Android, but it has no specific code or dependencies on Android API, so you have to manage keepAlive for Froyo by yourself.
Related
So I'm trying to use an API from a website but inorder to use it i'll have to send my login informaton. The documentation shows me a python example on how to login.
R = requests.post('http://nova.astrometry.net/api/login', data={'request-json':
json.dumps({"apikey": "XXXXXXXX"})})
print(R.text)
So what is the Kotlin equivalent of the above code ? In the websites documentation it states
"Note the request-json=VALUE: we’re not sending raw JSON, we’re sending the JSON-encoded string as though it were a text field called request-json."
I have attempted to use Android Volley but im not entirely sure how to use it.
private fun plateSolve(){
val json=JSONObject(map).toString()
Log.d(TAG,"URL:$url")
Log.d(TAG,"Hashmap:$json")
JSONObject(map).toString()
val jsonObjectRequest = JsonObjectRequest(
Request.Method.POST, url, null,
{ response ->
try {
Log.d(TAG,"POST Response: %s".format(response.toString()))
}catch (e:Exception){
Log.d(TAG,"Exception: $e")
}
},
{ error ->
// TODO: Handle error
Log.d(TAG,"There Was an Error")
error.stackTraceToString()
}
)
// Access the RequestQueue through your singleton class.
VolleySingleton.instance?.addToRequestQueue(jsonObjectRequest)
}
Thanks in advance
it's not recommended to use volley anymore for android please use retrofit as its google's recommended library,the answer for your question is too big so i will write some checkpoints to do and also i have shared a simple working example with retrofit one of my own projects on github , hopefully this helps you
retrofit link - https://square.github.io/retrofit/
Insert library files in gradle
create response classes
create retrofit api class
4.create interface class with api calls
Github project with app using retrofit for api calls
https://github.com/zaidzak9/NewsApp
I am using retrofit for http calls in my Android application and retrofit.client.UrlConnectionClient as the client while building the adapter.
RestAdapter.Builder builder = new RestAdapter.Builder()
.setEndpoint(url)
.setLogLevel(RestAdapter.LogLevel.FULL)
.setClient(
new Client.Provider() {
public Client get() {
return new UrlConnectionClient() {
#Override
protected HttpURLConnection openConnection(Request request)
throws IOException {
HttpURLConnection connection = super.openConnection(request);
connection.setConnectTimeout(connectionTimeout);
return connection;
}
I wanted to set the timeout so I have used UrlConnectionClient as my client. I could not find a way with other clients like OkHttp.
Question is : How can I cancel the ongoing request ?.
I have seen a similar post # Using Square's Retrofit Client, is it possible to cancel an in progress request? If so how? but my code would get really complex if I try to add my own executors and try to cancel the request using that. I am looking if there is slightly a better way with my existing code.
I also see that Retorofit V2.0 has plan for Retry and Cancel but not sure when that would be released..https://github.com/square/retrofit/issues/297
Need help !
In fact I also need a way to retry with the same code.
This has been available since 2.0.0-beta2 (https://github.com/square/retrofit/releases/tag/parent-2.0.0-beta2). I don't know if there is a doc that explains that but here is the link to API:
http://square.github.io/retrofit/2.x/retrofit/retrofit/Call.html#cancel--
'Call' API allows to do Retry as well by 'Clone'ing the request.
for study we have to develop an Android game which is location based. Currently we use OSMDroid to show the map. There are resources (like wood, stone, ...) which the player has to collect. These resources are currently stored in our backend with hardcoded long/lat and will be added with setMarker onto the current map.
To provide this game globally, we want to set the resources dynamically based on the "real" world. So we need different layers from OSM (like forest, sea, ..) to set our resources automatically without asking our backend.
After some hours searching with google I found out that the Overpass API seems to help me implementing this functionality. But I can't find any tutorial for using Overpass API in Android. I tried some things but I don't get it... So I need your help, please give me an example or explanation how to implement this :/
This is my current code, but I don't think that this is correct..
URL url = new URL("http://overpass-api.de/api/interpreter");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
inputStream.close();
Following exception will be thrown at InputStream inputStream = urlConnection.getInputStream();:
W/System.err(3958): java.io.FileNotFoundException: http://overpass-api.de/api/interpreter
W/System.err(3958): at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177)
W/System.err(3958): at de.htw.berlin.games.based.location.gui.MapActivity$test.doInBackground(MapActivity.java:536)
W/System.err(3958): at de.htw.berlin.games.based.location.gui.MapActivity$test.doInBackground(MapActivity.java:1)
W/System.err(3958): at android.os.AsyncTask$2.call(AsyncTask.java:287)
W/System.err(3958): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
W/System.err(3958): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
W/System.err(3958): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
W/System.err(3958): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
W/System.err(3958): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
W/System.err(3958): at java.lang.Thread.run(Thread.java:856)
Thanks for all helpful replies :)
This exception you're getting is thrown because an HTTP GET call to http://overpass-api.de/api/interpreter returns a 400 Bad Request response.
What you want to do is a POST request to http://overpass-api.de/api/interpreter. An example of form-data to pass to this API is :
data='<?xml version="1.0" encoding="UTF-8"?><osm-script><!--
This is an example Overpass query.
Try it out by pressing the Run button above!
You can find more examples with the Load tool.
-->
<query type="node">
<has-kv k="amenity" v="drinking_water"/>
<bbox-query s="41.88659196260802" w="12.488558292388916" n="41.89248629819397" e="12.51119613647461"/><!--this is auto-completed with the
current map view coordinates.-->
</query>
<print/></osm-script>'
To find out how the API is working you should check, using your browser, what HTTP query is made to the API when clicking on Run in the example I pointed out.
EDIT
You can find plenty of examples like this one that shows how to post data using HTTP in Android. You'll have to add data as a key and the XML query string as a value in the used value pair container, such as :
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
nameValuePairs.add(new BasicNameValuePair("data", _The_XML_Query_String_));
Stick to the linked example for the rest and you hould be fine.
Check out https://github.com/zsoltk/overpasser. It's a Java library to ease working with the Overpass API.
You don't have to write the QL string yourself
It comes with a Retrofit adapter (so you can skip the networking part)
It has an Android sample showing how to put them all together over a Google Maps to get you started in no time
For anyone in future who needs to find a solution with overpass api, here is what I did very often: Overpass API can be addressed with a GET-Request. A GET-Request comes with a HTTP-protocoll and can be used in (I think) every programming language. You have to make a GET-request to the overpass-interpreter with all the queries in the url. In Android it would look like this:
String urlOverpass = "https://overpass-api.de/api/interpreter?data=[out:json][timeout:100];(node[shop=supermarket](52.402957,13.337429,52.420730,13.379530);way[shop=supermarket](52.402957,13.337429,52.420730,13.379530););out%20body;%3E;out%20skel%20qt;";
/* here you speak to the interpreter and you can insert whatever query you need. As an example look at overpass-turbo.eu*/
StringRequest request = new StringRequest(urlOverpass, new Response.Listener<String>() {
#Override
public void onResponse(String string) {
/* Here you can do whatever you like with the data which comes from the interpreter. The "string" is the response.*/
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
/* Here you can explain what happens when an error is coming from the interpreter*/
}
});
RequestQueue rQueue = Volley.newRequestQueue(MainActivity.this);
rQueue.add(request);
Dont forget to implement the library: implementation 'com.android.volley:volley:1.1.1'
But there are multiple possibilities to fetch data from an api with a GET-request.
So long story short I have a android app and I used cocos2dx to dev it. One component I am working on is bringing my facebook friends into my game. The way I did it was on the native side (java) I setup my facebook sdk. I succefuly login and pull down my friends list without problems. My issue is that I need to forward this data to the c++ side so I can access the data and bring it into labels etc..
Here I guess some structure of how stuff is happening:
Java native - start activity, login to facebook, get friends -> STRING DATA JNI TO C++ -> CPP parse JSON data with Jannson.
My issue is that if I have a sample data like this:
[
{
"pic_square": "https://www.facebook.com/blah",
"uid": 4654546445,
"name": "somename"
}
]
I can parse that no problem, But in reality what facebook response with is something like this:
{
Response: responseCode: 200,
graphObject: GraphObject{
graphObjectClass=GraphObject,
state={
"data": [
{
"pic_square": "https://www.facebook.com/blah",
"uid": 4654546445,
"name": "somename"
}
]
}
}
}
And with that Jansson fails stating that its not an array (exact error is "error: root is not an array").
Not sure how to handle this. Should I be somehow parsing out the stuff after "data": and then figuring out where to stop correctly or is there a better way.
Thanks!!
What you'll need to do is modify the parsing logic to first handle the Json objects that wrap the data array you're interested in. Although this will require some extra programming, it definitely beats any String manipulation attempts. Unless you're a 100% sure that "[" and "]" will always be part of the response, then I wouldn't be making any assumptions about what you're receiving.
I'm not familiar with Jannson, but you'll want to do some other bits and pieces before handling the data array. Just from looking at the tutorial, it should probably look somewhat like this:
// make request
text = request(url);
// decode json
root = json_loads(text, 0, &error);
// parse "Response"
json_t *response = json_object_get(root, "Response");
json_t *responseCode = json_object_get(response, "responseCode");
int responseCodeValue = json_integer_value(responseCode);
// parse "graphObject"
json_t *graphObject = json_object_get(root, "graphObject");
json_t *graphObjectClass = json_object_get(graphObject, "graphObjectClass");
json_t *state = json_object_get(graphObject, "state");
json_t *data = json_object_get(state, "data");
// iterate over the "data" array, parse the key/values etc.
for(i = 0; i < json_array_size(data); i++) {
json_t *data = json_array_get(root, i);
}
For the sake of this example, I've omitted all type checks (you will want to add those yourself) as well as any cleaning up of memory/variables. Also, please beware of any typos and/or obvious mistakes, as I simply typed this straight into the browser and did not do any compile or runtime checks. I'm sure you'll be able to filter those out on your own.
One thing that I'm curious about is why you've opted for Jannson? I'm guessing because of its support for both Android and iOS? If you're specifically targeting Android, there are lots of other options out there. For example, basic Json support is built into the Android framework, but there's also 3rd party libraries that will enable mapping of Json to Java objects, like GSON and Jackson.
I am currently playing with Spring Android Resttemplate to interact with a java-backed REST API. Actually, I am using android annotations to send http calls to this back-end service and I must say it rocks. Basically, Android annotations allows you to define an interface for the service calls and the http methods to be used for each api call available : it will generate all the boiler-plate code related to low-level stuff like marshalling/unmarshalling, calling the right http method according to the interface definition.
Now, I would like to set some headers to http requests : How can I achieve this knowing that I only have a reference to the Service interface defining all the calls ?
I can also have reference to the RestTemplate object but it seems there is now way of setting the headers.
any help would really be appreciated
thanks
The way I approached it is by creating an instance of ApiClient in the application class and set a custom REST template.
In my case I was using Jackson for JSON message conversion:
RestTemplate restTemplate = new RestTemplate(fac);
MappingJacksonHttpMessageConverter converter =
new MappingJacksonHttpMessageConverter();
converter.getObjectMapper().configure(Feature.UNWRAP_ROOT_VALUE, true);
restTemplate
.getMessageConverters()
.add(converter);
mClient.setRestTemplate(restTemplate);
My request factory fac then looks like this:
ClientHttpRequestFactory fac = new HttpComponentsClientHttpRequestFactory() {
#Override
protected HttpUriRequest createHttpRequest(HttpMethod httpMethod, URI uri) {
HttpUriRequest uriRequest = super.createHttpRequest(httpMethod, uri);
// Add request headers
uriRequest.addHeader(
"Content-Type",
MediaType.APPLICATION_JSON_VALUE);
return uriRequest;
}
#Override
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod)
throws IOException {
if (Config.DEBUG_REQUESTS) {
Log.d(TAG, uri);
}
return super.createRequest(uri, httpMethod);
}
};
WARNING
Although this works on all Android devices in our office, I've recently discovered that headers don't appear to be added with all devices! I'm not sure why this is (or which devices specifically), but I'm looking in to it and will try to update this answer when I've found a resolution.