I created an app that reads data from Google Books API and display it in a recyclerView.
Sometimes the items in the recyclerView wont show.
In my log I get the following (it is not an error that crashes my app but it shows it):
V/AsyncHttpRH: Progress 538 from 1 (53800%)
W/JsonHttpRH: onFailure(int, Header[], Throwable, JSONObject) was not overriden, but callback was received
cz.msebera.android.httpclient.client.HttpResponseException: Too Many Requests
at com.loopj.android.http.AsyncHttpResponseHandler.sendResponseMessage(AsyncHttpResponseHandler.java:446)
at com.loopj.android.http.AsyncHttpRequest.makeRequest(AsyncHttpRequest.java:160)
at com.loopj.android.http.AsyncHttpRequest.makeRequestWithRetries(AsyncHttpRequest.java:177)
at com.loopj.android.http.AsyncHttpRequest.run(AsyncHttpRequest.java:106)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
What can cause this error?
The way I use it is:
MyBookClient.getInstance().getBooks( discoverBooks.getBookID(), new JsonHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
if (response != null) {
final MyBook books = MyBook.fromJson( response );
}
}
} );
Where:
public class MyBookClient {
private static final String API_BASE_URL = "https://www.googleapis.com/books/v1/volumes/";
private AsyncHttpClient client;
public static MyBookClient instance = new MyBookClient();
public MyBookClient() {
this.client = new AsyncHttpClient();
}
public static MyBookClient getInstance() {
return instance;
}
public void getBooks(final String query, JsonHttpResponseHandler handler) {
try {
client.get( API_BASE_URL + URLEncoder.encode( query, "utf-8" ), handler );
} catch (UnsupportedEncodingException ignored) {
}
}
}
Thank you!
Probably your app is making a lot of request in a short time period, so the best strategy to get rid of the error 429 is implement a strategy of control it:
you can use debouncing or throttling (will depend what fit your situation);
implementing a queue of pendent requests to deliver in a delayed time to avoid the 429 error.
mapping in your app when you REALLY need to make this request, so create a job to verify when the criteria is been contemplated.
In all cases you can do in a asynchronous way, delivering the a job, or an event subscribe implementation to inject the books data on the page or something.
Related
I want to access an online API through an android application. For this purpose I have written easy to access functions to send requests via the android Volley package. However the app immediately displays 0s when I try to assign a value, that I have recieved through sending a request, to a TextView. I realize that this probably is because the function handles the Object as "null" because the response has not yet arrived and that I need to use AsyncTasks to handle this properly but the Developer Guide from Android Studio didn't really help me too much because, to be absolutely 100% honest with you, I'm not a software engineer and I'm absolutely lost at this point.
Here's some code on how I access the API:
org.json.JSONObject makeRequest(String URL, String method, String[] headers){
int reqType;
switch(method.toUpperCase()){
case "GET":
reqType = Request.Method.GET;
break;
case "DELETE":
reqType = Request.Method.DELETE;
break;
default:
return null;
}
Response.Listener<JSONObject> listener = new Response.Listener<JSONObject>(){
#Override
public void onResponse(JSONObject Response){
result = Response;
}
};
Response.ErrorListener err = new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
result = null;
}
};
JsonObjectRequest req = new JsonObjectRequest(reqType, URL, null, listener, err){
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put(headers[0], headers[1]);
return params;
}
};
;
rQ_volley.add(req);
return result;
}
And additionally some code on where I access the method above
JSONArray koordTargetArr = rBuild.makeRequestArr("https://nominatim.openstreetmap.org/search?q="+target+"&format=json&polygon=1&addressdetails=1", "get",headersLonLat);
if(koordTargetArr != null) {
JSONObject koordTargetOBJ = koordTargetArr.getJSONObject(0);
koordTarget = koordTargetOBJ.getString("lon").concat(",").concat(koordTargetOBJ.getString("lat"));
}
else return 0;
I would appreciate any help you could give me on things like where I implement the AsyncTask and how I build one. I have experience in the async library in Node.js if that helps at all.
EDIT:
This is NOT a duplicate of How to use java.net.URLConnection to fire and handle HTTP requests I already know how to send HTTP Requests, I don't know how to use android AsyncTask, HTTP Requests are NOT the topic of this question.
Have you considered using Retrofit?
It will handle, construction and deserialization of all your network needs without needing to use AsyncTask + custom utilities functions.
I want to read arraylist from android into php in order to store in database, but I'm not able to find exact code for it. Can anybody guide me in the direction to solve this problem ?
Here is my java code for creating the arraylist
private void loadCart()
{
productList.clear();
Cursor cursor = dbHelper.getCarProducts();
cursor.moveToFirst();
do {
CartProduct cartProduct = new CartProduct();
cartProduct.setProductName("Name: "+cursor.getString(cursor.getColumnIndex("_Name")));
cartProduct.setProductCost("Cost: "+cursor.getString(cursor.getColumnIndex("_Cost")));
cartProduct.setProductPrice("Price: "+cursor.getString(cursor.getColumnIndex("_Price")));
cartProduct.setProductQuantity("Quantity: "+cursor.getString(cursor.getColumnIndex("_Quantity")));
productList.add(cartProduct);
}while(cursor.moveToNext());
}
I'm using retrofit2 in order to send the arraylist to the server, but as I have seen in other question here I'm not able to get the url for the file_get_contents ?
Here you go...
Step 1: Add retrofit dependency in your gradle.app
compile 'com.squareup.retrofit:retrofit:1.9.0'
Step 2: Make an RestClient class like below.
public class RestClient {
private static final String BASE_URL = DataConstants.TEST_URL; //Place your web service URL here
private ApiInterface apiService;
public RestClient()
{
RequestInterceptor requestInterceptor = new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
request.addHeader("Accept", "application/json");
}
};
RestAdapter restAdapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.FULL)
.setRequestInterceptor(requestInterceptor)
.setEndpoint(BASE_URL)
.build();
apiService = restAdapter.create(ApiInterface.class);
}
public ApiInterface getApiService()
{
return apiService;
}
}
Step 3: Make an Interface for POST URL.
public interface ApiInterface {
#POST("/sendData")
void sendData(#Body JsonObject jsonObject,
Callback<DataModel> dataModelCallback);
}
Step 4: Make an POJO class like below.
public class DataModel{
private String success;
public String getSuccess() {
return success;
}
public void setSuccess(String success) {
this.success = success;
}
}
Step 5: Make an call of webservice from your activity like below.
private void callWebService(String user_id) {
try {//TODO SEND
final Utility utility = new Utility(this);
utility.showProgressDialog();
JsonObject myJsonData = new JsonObject();
myJsonData.addProperty("user_id", user_id);
Gson gsonData = new GsonBuilder().create();
JsonArray dataArray = new JsonArray();
dataArray = gsonData.toJsonTree(productList).getAsJsonArray(); //Here you want to add your array list i.e productList
myJsonData.add("assign_to", jaAssignee);
new RestClient().getApiService().sendData(myJsonData, new Callback<DataModel>() {
#Override
public void success(DataModel dataModel, Response response) {
utility.hideProgressDialog();
try {
String success = dataModel.getSuccess();
if (success.equalsIgnoreCase("Success")) {
//Do what you want to do
}
} catch (Exception e) {
}
}
#Override
public void failure(RetrofitError error) {
utility.hideProgressDialog();
}
});
} catch (Exception e) {
}
}
Hope this will help you!
Send all your data in one go. Create JsonArray and add each object by creating JsonObject. After its done upload all the data in one go. You'll just have to decode that array in php.
Advantage of using this is, you can manage the response in retrofit very well (being it asynchronous)
you can parse json value in php by
<?php
header('Content-type: application/json');
$jsonString = file_get_contents('php://input');
$jsonArray = json_decode($jsonString,true);
print_r($jsonArray);/* print array */
?>
After almost searching for 3+ weeks and n+ hours of frustration, i've finally found an working solution to my problem and sharing it with people so they could benefit from it (as i was blocked from another a/c due to asking too many questions and down votes ) , in order to send your array list to your server we need to use another library and the best fit according to my need is async-http library by loop j and these are the steps to import and use the library in your program :-
1.)import the library into your project by writing this statement in your bulid.gradle(app module):-
compile 'com.loopj.android:android-async-http:1.4.9'
2.)Create the following variables in order to use them in your program:-
AsyncHttpClient (a client to send data to your server)
RequestPrarms (Data sent to your server for parsing and further operations )
String url(Link to your server where actually operations occurs)
3.) Now we use these variables and run the program :-
p
arams.put("OrderSummary", <your array list>);
httpClient.post(APIURL.API_URL,params, new AsyncHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
//your operations on success
}
#Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
Toast.makeText(getApplicationContext(),error.toString(),Toast.LENGTH_LONG).show();
}
});
i hope this clears your doubts somewhat i'm still creating my php side in order to insert data in the database
I have a small java application that does the following:
reads messages (json strings) from a queue and sends it to a sender
sender accumulates the received messages and when it reaches a specific size (lets says 5k) makes a http call and posts those messages
apache http client is used to post the messages and it is asynchronous, meaning I don't wait for the response and respective call back methods are invoked upon completing the post
Here is the pseudo code
Reader class: SomeProcessor.java
public class SomeProcessor extends Processor {
#Override
public void process(Messages m) {
// some processing on m
String jsonMessage = convertToJSON(m);
getSender().send(jsonMessage);
}
}
Base class: Processor.java
public class Processor {
private HttpSender sender = null ;
public Processor() {
setSender(new HttpSender());
}
public HttpEventCollectorSender getSender() {
return sender;
}
public void setSender(HttpEventCollectorSender sender) {
this.sender = sender;
}
}
Sender class: HttpSender.java
public class HttpSender {
private List<String> eventsBatch = new ArrayList<String>(5000);
public synchronized void send(final String message) {
eventsBatch.add(message);
if (eventsBatch.size() >= 5000) {
flush(); // calls http post
}
}
public synchronized void flush() {
if (eventsBatch.size() > 0) {
postEventsAsync(eventsBatch);
}
// since the above call is asynchronous after the post is called, I am assuming I should re-init the list, instead of clear. Is this correct?
eventsBatch = new ArrayList<String>(5000);
}
public void postEventsAsync(final List<String> events) {
startHttpClient(); // make sure http client is started
final String encoding = "utf-8";
// create http request
final HttpPost httpPost = new HttpPost(url);
httpPost.setHeader(AuthorizationHeaderTag, String.format(AuthorizationHeaderScheme, token));
StringEntity entity = new StringEntity(String.join("", events), encoding);
entity.setContentType(HttpContentType);
httpPost.setEntity(entity);
httpClient.execute(httpPost, new FutureCallback<HttpResponse>() {
#Override
public void completed(HttpResponse response) {
// log to console
}
#Override
public void failed(Exception ex) {
// just log to console
}
#Override
public void cancelled() {
}
});
}
}
Overall, I see a very high utilization of memory and noticed that even when processing has been stopped heap is not getting cleared. I looked into the heap dump and I see my "json string" messages represented as char[]. I suspect that something funky is happening with all those String not being GC'ed.
Thoughts?
Update-1: Based on the comments from below, attaching a Heap snapshot where the processing was paused and the heap space is still 4GB
Update-2: GC Report
http://gceasy.io/my-gc-report.jsp?p=c2hhcmVkLzIwMTcvMDcvNS8tLXN0cmVhbWdlc3RfZ2MuemlwLS0xNy03LTMx
Just want to know where do I insert the API key for the server in my code below:
public class GetCurrentJob extends Job {
Context context;
GetFeedback feedback;
protected GetCurrentJob(Context context, GetFeedback fb) {
super(new Params(PRIORITY.HIGH).requireNetwork());
feedback = fb;
this.context = context;
}
#Override
public void onAdded() {
}
#Override
public void onRun() throws Throwable {
//POST feedback to server... require API key. How?
Response<String> response = Ion.with(context)
.load("POST", URLbuilder.getURL())
.setStringBody(feedback.toJson())
.asString()
.withResponse()
.get();
//Toast.makeText(context, "post", Toast.LENGTH_SHORT).show();
if (response.getHeaders().code() != HttpURLConnection.HTTP_OK) {
Log.d("test", "error in request " + String.valueOf(response.getResult()));
return;
}
else
{
Log.d("test", "success" + String.valueOf(response.getResult()));
}
}
#Override
protected void onCancel(int cancelReason, #Nullable Throwable throwable) {
}
#Override
protected RetryConstraint shouldReRunOnThrowable(#NonNull Throwable throwable, int runCount, int maxRunCount) {
return null;
}
}
My URLbuilder class:
public class URLbuilder {
private static final String SERVER = "http://jxapp-s-ticket.cloudapp.net/jxapp_ticket/upload/api/http.php/tickets.json";
public static String getURL(){
return Uri.parse(SERVER).buildUpon().toString();
}
}
Just a little information:
My app takes user feedback and returns the feedback to the server, then the server will generate a ticket to the user.
I am able to generate a response from the server, namely from the log. But the log generates: "error in request Valid API key required".
I need a way to insert the API key but I do not know how (am quite new to Android Studio as well as POST and GET operations)!
Do help if possible! Thanks!
Response<String> response = Ion.with(context)
.load("POST", URLbuilder.getURL())
.setHeader("x-api"," API KEY HERE ")
.setStringBody(feedback.toJson())
.asString()
.withResponse()
.get();
Should anyone encounter the same problem this is how i solved this.
Modified the ion formatting by adding a header with the API key.
All credits to a senior of mine.
Hi folks I'm creating an android application's login/register part using the Android Volley Library. My application was working well, but the UI and logic were at the same class. So, I have separated them into two classes. My app makes requests to my NodeJS server using POST methods and gets JSON response. So I have tried to keep the POST request function in another class.
After separating the classes, I have a problem while waiting for response. Here is the function;
public String doWebRequestLogin(Context context, boolean checkLoginForm, final Map<String,String> json){
result[0] = "FREE";
this.context = context;
if(checkLoginForm){
StringRequest post = new StringRequest(Request.Method.POST, loginUrl, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
Log.d("Login Response: ",response);
data = response;
res = new JSONObject(data);
if (res.getString(KEY_SUCCESS) != null) {
int success = Integer.parseInt(res.getString(KEY_SUCCESS));
if (success == 1) {
result[0] = "LOGGED";
} else if (success == 0) {
result[0] = "LOGIN ERROR";
} else {
result[0] = "INVALID POST";
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("Response Error", error.toString());
result[0] = "INVALID POST";
}
}){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> map = json;
return map;
}
};
VolleyController.getInstance(this.context).getRequestQueue().add(post);
}
return result[0];
}
This function returns result[0] as "FREE" at every time due to response time. How could it wait for the response and set result[0] according to the response? I need to know what happened while making requests.
I'm calling doWebRequestLogin() on the UI within an onclick function
Then you do NOT want to "wait for the response". That will freeze your UI for however long the network I/O takes, and your users will... be unimpressed.
Instead, update your UI in the onResponse() and onErrorResponse() methods.
This sort of asynchronous call, handling the results via callbacks, is core to the event-driven programming model at the heart of Android.
The request is asynchronous and you must not block the main thread waiting for a response. Make the method void and use a callback to handle the response once it's received.
public void doWebRequestLogin(SomeCallback callback, Context context, boolean checkLoginForm, final Map<String,String> json){
[...]
if (res.getString(KEY_SUCCESS) != null) {
int success = Integer.parseInt(res.getString(KEY_SUCCESS));
callback.someMethod(success);
}
}
For the callback:
public interface SomeCallback{
void someMethod(int result); // response received, handle it
}
Callback may also have a return type or be generic, this depends solely on your needs...