I have an Android application that makes some requests on the server and also for sending data via web service, using the Volley library.
The data sent by the application are received by an API, and when there is confirmation, the API returns a specific value.
My problem is that I'm not getting this specific return from the API. How do I get this return, not only the server response 200 return that is received by library default?
You need to override parseNetworkResponse(NetworkResponse response)
Exemple :
#Override
protected Response<Bitmap> parseNetworkResponse(NetworkResponse response) {
// Serialize all decode on a global lock to reduce concurrent heap usage.
try {
return doParse(response); //your parser function
} catch (OutOfMemoryError e) {
//..Catch
}
}
Take a look to the doc.
Hope it helps,
Related
I am syncing lat-longs from local database to the server and change the status of rows in local database table if the lat-longs are successfully synced with the server, when user presses the button.
Problem
When button is pressed I hit the API for syncing lat-long to the server.
Some long-long is missing if the internet is slow (I want to send all lat-longs in exact sequence. If miss any lat-long, I try again to send the missing).
If all lat-longs are successfully synced only then EndRide Api is called.
This is the code when the button is pressed.
try {
cursor = db.getUnsyncedLatLngs(engIdForDB);
if (cursor.moveToFirst()) {
do {
//calling the method to save the unsynced name to MySQL
saveLatLngs(cursor.getInt(cursor.getColumnIndex(NewDatabaseForInRideData.COLUMN_ID)), cursor.getDouble(cursor.getColumnIndex(NewDatabaseForInRideData.Latitude)), cursor.getDouble(cursor.getColumnIndex(NewDatabaseForInRideData.Longitude)), engIdForDB);
} while (cursor.moveToNext());
}
} catch (Exception e) {
e.printStackTrace();
}
//Problem driverEndRideAsync is called even if some LatLng skiped to upload.
driverEndRideAsync(activity, abc, abc, 0, abc);
And for uploading lat-long to the server
private void saveLatLngs(final int id, final double lati, final double longi, String engId) {
RestClient.getApiService().update_data(abc, abc, lati, longi, String.valueOf(123), String.valueOf(123), String.valueOf(123), new Callback<String>() {
#Override
public void success(String s, Response response) {
try {
JSONObject jObj;
jObj = new JSONObject(s);
int flag = jObj.getInt("flag");
if (ApiResponseFlags.SOMETHING_WENT_WRONG.getOrdinal() == flag) {
db.updateNameStatus(id, NAME_NOT_SYNCED_WITH_SERVER, engId);
} else {
db.updateNameStatus(id, NAME_SYNCED_WITH_SERVER, engId);
}
} catch (JSONException e) {
e.printStackTrace();
}
android.util.Log.i("update_in_ride_data", " Success =" + response);
}
#Override
public void failure(RetrofitError error) {
android.util.Log.i("update_in_ride_data", " Error =" + error);
}
});
}
You have several problems in your implementation.
You are saving your lat-long fetched from your database table by calling an external API to your server inside a while loop. This is quite a bad implementation as this is creating a lot of AsyncTask in the background when you are trying to save each lat-long with an API service call.
The cleaner implementation requires development in your backend server which should take the lat-long as a batch (i.e. a bunch of lat-long will be saved at a time). In this implementation you will be able to save your lat-long by calling the API service once, instead of having it called multiple times for each of your entries.
Move the driverEndRideAsync(activity, abc, abc, 0, abc); function call inside your try block, so that it will not execute if you get an exception from that block while you are sending the lat-long data to your server using the API service.
If you are keeping this exact implementation in your server side, then I would suggest you to have a background service which will check if there is any data available to be synced with server in your database table after a certain time. In that case, you will have your data synced even if you get an exception while you are syncing your data with your server, because eventually the background service will detect un-synced data and will sync them with the server application.
Hope that helps.
i am creating appointment using below code give "500 Internal Server Error"
i added all fields check it
Appointment objappointment = Appointment.build()
.setSubject("Android sub")
.setDescription("dis from device")
.setRegardingObjectId(new EntityReference("account", UUID.fromString("0717b8e2-d00a-e611-8115-c4346bdd11d1")))
.setOwnerId(new EntityReference("systemuser", UUID.fromString("3edb272d-2da7-4c89-9350-2f4bd4e1762b")))
.setStateCode(new OptionSetValue(0))
.setNew_Latitude(23.7845)
.setNew_Longitude(73.6574)
.setNew_City("Surat")
.setActualStart(mDate.getTime())
.setActualEnd(mDate1.getTime())
.setNew_ZipPostalCode("380060")
.setNew_Street1("Street1")
.setNew_Street2("Street3")
.setNew_street3("Street3")
.setNew_StateProvince("Gujarayt")
.setNew_CountryRegion("India")
.setNew_Latitude(23.7845)
.setNew_Longitude(73.6574)
.setStatusCode(new OptionSetValue(0))
.setPriorityCode(new OptionSetValue(2));
try {
RestOrganizationServiceProxy restService = new RestOrganizationServiceProxy(mOrgService);
restService.Create(objappointment,new Callback<UUID>() {
#Override
public void success(UUID uuid, Response response) {
log("sucess", uuid.toString());
}
#Override
public void failure(RetrofitError error) {
displayError(error.toString());
log("error", error.toString());
}
});
}
catch(Exception ex) {
displayError(ex.getMessage());
log("msg",ex.toString());
}
another entity create successfully using above code just got error in "Appoinment"
Could you get more details of the exception? 500 could be any exception. At least you know the request hit the server and it's failing on the CRM server side. Maybe a plugin or similar is raising the exception.
I think you have to pass the objectid to whom the annotation will be linked to (Account, Contact, or whatever...)
Is that on-premise or online CRM? If OnPremise you could enable includeExceptionDetailInFaults property in the web.config to at least get more details of the exception....
I recently started to use Volley lib from Google for my network requests. One of my requests get error 301 for redirect, so my question is that can volley handle redirect somehow automatically or do I have to handle it manually in parseNetworkError or use some kind of RetryPolicyhere?
Thanks.
Replace your url like that url.replace("http", "https");
for example:
if your url looking like that : "http://graph.facebook......." than
it should be like : "https://graph.facebook......."
it works for me
I fixed it catching the http status 301 or 302, reading redirect url and setting it to request then throwing expection which triggers retry.
Edit: Here are the main keys in volley lib which i modified:
Added method public void setUrl(final String url) for class Request
In class BasicNetwork is added check for redirection after // Handle cache validation, if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY) || statusCode == HttpStatus.SC_MOVED_TEMPORARILY), there I read the redirect url with responseHeaders.get("location"), call setUrl with request object and throw error
Error get's catched and it calls attemptRetryOnException
You also need to have RetryPolicy set for the Request (see DefaultRetryPolicy for this)
If you dont want to modify the Volley lib you can catch the 301 and manually re-send the request.
In your GsonRequest class implement deliverError and create a new Request object with the new Location url from the header and insert that to the request queue.
Something like this:
#Override
public void deliverError(final VolleyError error) {
Log.d(TAG, "deliverError");
final int status = error.networkResponse.statusCode;
// Handle 30x
if(HttpURLConnection.HTTP_MOVED_PERM == status || status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_SEE_OTHER) {
final String location = error.networkResponse.headers.get("Location");
Log.d(TAG, "Location: " + location);
final GsonRequest<T> request = new GsonRequest<T>(method, location, jsonRequest, this.requestContentType, this.clazz, this.ttl, this.listener, this.errorListener);
// Construct a request clone and change the url to redirect location.
RequestManager.getRequestQueue().add(request);
}
}
This way you can keep updating Volley and not have to worry about things breaking.
Like many others, I was simply confused about why Volley wasn't following redirects automatically. By looking at the source code I found that while Volley will set the redirect URL correctly on its own, it won't actually follow it unless the request's retry policy specifies to "retry" at least once. Inexplicably, the default retry policy sets maxNumRetries to 0. So the fix is to set a retry policy with 1 retry (10s timeout and 1x back-off copied from default):
request.setRetryPolicy(new DefaultRetryPolicy(10000, 1, 1.0f))
For reference, here is the source code:
/**
* Constructs a new retry policy.
* #param initialTimeoutMs The initial timeout for the policy.
* #param maxNumRetries The maximum number of retries.
* #param backoffMultiplier Backoff multiplier for the policy.
*/
public DefaultRetryPolicy(int initialTimeoutMs, int maxNumRetries, float backoffMultiplier) {
mCurrentTimeoutMs = initialTimeoutMs;
mMaxNumRetries = maxNumRetries;
mBackoffMultiplier = backoffMultiplier;
}
Alternatively, you can create a custom implementation of RetryPolicy that only "retries" in the event of a 301 or 302.
Hope this helps someone!
End up doing a merge of what most #niko and #slott answered:
// Request impl class
// ...
#Override
public void deliverError(VolleyError error) {
super.deliverError(error);
Log.e(TAG, error.getMessage(), error);
final int status = error.networkResponse.statusCode;
// Handle 30x
if (status == HttpURLConnection.HTTP_MOVED_PERM ||
status == HttpURLConnection.HTTP_MOVED_TEMP ||
status == HttpURLConnection.HTTP_SEE_OTHER) {
final String location = error.networkResponse.headers.get("Location");
if (BuildConfig.DEBUG) {
Log.d(TAG, "Location: " + location);
}
// TODO: create new request with new location
// TODO: enqueue new request
}
}
#Override
public String getUrl() {
String url = super.getUrl();
if (!url.startsWith("http://") && !url.startsWith("https://")) {
url = "http://" + url; // use http by default
}
return url;
}
It worked well overriding StringRequest methods.
Hope it can help someone.
Volley supports redirection without any patches, no need for a separate fork
Explanation:
Volley internally uses HttpClient which by default follows 301/302 unless specified otherwise
From: http://hc.apache.org/httpcomponents-client-4.2.x/tutorial/html/httpagent.html
ClientPNames.HANDLE_REDIRECTS='http.protocol.handle-redirects': defines whether redirects should be handled automatically. This parameter expects a value of type java.lang.Boolean. If this parameter is not set HttpClient will handle redirects automatically.
ok, im a bit late to the game here, but i've recently been trying to achieve this same aspect, so https://stackoverflow.com/a/17483037/2423312 is the best one, given that you are willing to fork volley and maintain it and the answer here : https://stackoverflow.com/a/27566737/2423312 - I'm not sure how this even worked.This one is spot on though : https://stackoverflow.com/a/28454312/2423312. But its actually adding a new request object to the NetworkDipatcher's queue, so you'll have to notify the caller as well somehow, there is one dirty way where you can do this by not modifying the request object + changing the field "mURL", PLEASE NOTE THAT THIS IS DEPENDENT ON YOUR IMPLEMENTATION OF VOLLEY'S RetryPolicy.java INTERFACE AND HOW YOUR CLASSES EXTENDING Request.java CLASS ARE, here you go : welcome REFLECTION
Class volleyRequestClass = request.getClass().getSuperclass();
Field urlField = volleyRequestClass.getDeclaredField("mUrl");
urlField.setAccessible(true);
urlField.set(request, newRedirectURL);
Personally I'd prefer cloning volley though. Plus looks like volley's example BasicNetwork class was designed to fail at redirects : https://github.com/google/volley/blob/ddfb86659df59e7293df9277da216d73c34aa800/src/test/java/com/android/volley/toolbox/BasicNetworkTest.java#L156 so i guess they arent leaning too much on redirects, feel free to suggest/edit. Always looking for good way..
I am using volley:1.1.1 with https url though the request was having some issue. On digging deeper i found that my request method was getting changed from POST to GET due to redirect (permanent redirect 301). I am using using nginx and in server block i was having a rewrite rule that was causing the issue.
So in short everything seems good with latest version of volley. My utility function here-
public void makePostRequest(String url, JSONObject body, final AjaxCallback ajaxCallback) {
try {
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST,
url, body, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d(LOG, response.toString());
ajaxCallback.onSuccess(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e(LOG, error.toString());
ajaxCallback.onError(error);
}
});
singleton.getRequestQueue().add(jsonObjectRequest);
} catch(Exception e) {
Log.d(LOG, "Exception makePostRequest");
e.printStackTrace();
}
}
// separate file
public interface AjaxCallback {
void onSuccess(JSONObject response);
void onError(VolleyError error);
}
I am trying to get responses from a JSON-RPC Service on Android, I'm currently developing on 3.0 Honeycomb.
This is the library I am using:
http://code.google.com/p/android-json-rpc/
and I am using this JSON-RPC service page for testing:
http://www.raboof.com/projects/jayrock/demo.ashx
The connection seems to work, but I keep getting this Exception
org.alexd.jsonrpc.JSONRPCException: Invalid JSON response
I've tried different methods and survey pages, but I always get the same Exception. Where am I going wrong?
The relevant code is below. AsyncTask is used because since 3.0 Android doesn't allow network connections in the main stream. Thanks in advance.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
JSONHandler task = new JSONHandler();
task.execute(new String[] {"http://www.raboof.com/projects/jayrock/demo.ashx"});
}
private class JSONHandler extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
for (String url : urls) {
JSONRPCClient client = JSONRPCClient.create(url);
client.setConnectionTimeout(2000);
client.setSoTimeout(2000);
try {
client.call("counter");
} catch (JSONRPCException e) {
e.printStackTrace(); //Invalid JSON Response caught here
}
}
return null;
}
}
I have tested your system using the last version of the library. It work great. You need to us callInt("counter") and it will be ok.
There is the code I used:
public JSONRPCClient client = JSONRPCClient.create("http://www.raboof.com/projects/jayrock/demo.ashx", JSONRPCClient.Versions.VERSION_2);
try{
int resInt = client.callInt("counter");
} catch (JSONException e) {
Log.i("JSON-RPC Client", e.toString());
}
I hope this can help.
PS: with this new version, you use parameters send as an array, or using a JSONObject to send named parameters. This is only possible if using the version 2.0 of the JSON-RPC protocol.
This is the only JSON-RPC client I've been able to get to work with Zend_Json_Server on Android (and I've tried a few).
Make sure to set the version to 2.0 also, as this client doesn't work unless your server is explicitly using the 2.0 spec:
$server = new Zend_Json_Server();
$server->setClass('My_Class');
$server->getRequest()->setVersion("2.0");
if ('GET' == $_SERVER['REQUEST_METHOD']) {
// Indicate the URL endpoint, and the JSON-RPC version used:
$server->setTarget('/ajax.php')
->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);
// Grab the SMD
$smd = $server->getServiceMap();
// Return the SMD to the client
header('Content-Type: application/json');
echo $smd;
return;
}
$server->handle();
Well Ive looked for hours and hours after an answer but havent really found anything that I could use.
I want to be able to send/upload files (images, videos, documents, audio) to a webservice. I want to do this from an android device (version 2.2).
I need to be able to send this to a tailormade wcf for my needs, I need to send information with the file in order to verify the user who wants to upload.
Also worth mentioning is I use a restful wcf .net webservice which I prefer to continue to use if possible. Atleast I need to be able to use wcf .net as webservice for the communication.
All solutions Ive seen concentrate on the android part and never on the service part. I need both. :)
This blog post
http://reecon.wordpress.com/2010/04/25/uploading-files-to-http-server-using-post-android-sdk/
describes how you can upload files with HTTP POST - which you must use from Android if you want to upload files to a WCF service wired up with webHttpBinding.
Extra metadata can be sent as HTTP headers.
--larsw
Ion.with(getActivity())
.load(URL)
.setMultipartFile("upload", "image/jpeg", fileToUpload)
.asString()
.setCallback(new FutureCallback<String>() {
#Override
public void onCompleted(Exception arg0, String result) {
hideProgressDialog();
if(result!=null){
CoreFragment.this.resultCallBack.returnResult(result.toString());
} else {
showErrorToast("Error");
}
}
});
and wcf is
public string upload(Stream stream)
{
MultipartParser parser = new MultipartParser(stream);
if (parser.Success)
{
try
{
string strServerpath = #"C:\IISWebsite\DOTNET\BGGTS\Files\AttendanceProof\" + parser.Filename;
File.WriteAllBytes(strServerpath, parser.FileContents);
}
catch (Exception ex)
{
return "Failed";
}
}
return "Success";
}