I am trying to pass a JSON object to a web service through Asynctask. I call a collectStatistics method in the MainActivity. This method collects some statistics of the mobile device and combines them together in a JSON object. JSON object is then passed to Asynctask.
JSONObject jsonProperties = new JSONObject();
try {
jsonProperties.put("_device" , _device);
jsonProperties.put("_model", _model);
jsonProperties.put("_product", _product);
} catch (JSONException e) {
e.printStackTrace();
}
if (jsonProperties.length() > 0)
{
//call to async class
//String.valueOf(jsonProperties)
//new SendJsonProperties().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, jsonProperties); //instead of execute
Toast.makeText(context,jsonProperties.toString(),Toast.LENGTH_LONG).show();
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
new SendJsonProperties().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, jsonProperties);
Log.i("msg","calling asynctask");
} else {
new SendJsonProperties().execute(jsonProperties);
Log.i("msg","NOT calling asynctask");
}
}
The Asynctask receives JSON parameter
class SendJsonProperties extends AsyncTask <JSONObject,String,String>
I call a web service caller method in doInBackground
protected String doInBackground(JSONObject... params)
{
//(...) elippsis make the input array
Log.i("msg", "do in bkgnd");
WebServicesCaller webServicesCaller = new WebServicesCaller();
result = webServicesCaller.storeStatistics(params[0]);
return null;
}
But I get this error
java.lang.RuntimeException: Cannot serialize: {"_product":"ms013gxx","_model":"SM-G7102","_device":"ms013g"}
I cannot figure out the problem in serialization. Any help will be much appreciated. Thanks in advance.
You have to make Model POJO class of your JSONObject parameters.
Use this link to create POJO class according to JSON REsponse.
http://www.jsonschema2pojo.org/
I was trying to send a JSON object to a web method which takes a string parameter
public string storeStatistics(string jsonObj)
So I changed
jsonProp.setType(JSONObject.class);
request.addProperty(jsonProp, obj);
to
jsonProp.type = PropertyInfo.STRING_CLASS;
request.addProperty(jsonProp, obj.toString());
Related
I am pretty new with the concept of asynctask and i have an asynctask that gets me a json from an api with parameter an then(postexecute) puts the content inside textviews to be shown(they are set visible after setting the text), the thing is i am trying to validate that the json isnt actually empty, and with my code i actually do that, but if the parameter i use is correct, the validation still detects that its empty, if i try to get it again(by pressing the button that triggers the asynctask) after 2 or three tries it will actually get it tho, i think its because i am doing it on the background, here is the asynctask
private class ConsultarDatos extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
// params comes from the execute() call: params[0] is the url.
try {
return downloadUrl(urls[0]);
} catch (IOException e) {
return "Unable to retrieve web page. URL may be invalid.";
}
}
// onPostExecute displays the results of the AsyncTask.
#Override
protected void onPostExecute(String result) {
JSONArray ja = null;
try {
ja = new JSONArray(result);
txtNombre.setText(ja.getString(0) +" " + ja.getString(1));
txtCategoria.setText(ja.getString(2));
txtDNI.setText(ja.getString(3));
txtEstado.setText(ja.getString(4));
//working=false;
} catch (JSONException e) {
e.printStackTrace();
}
}
}
and here is what i am trying to do
btnGenerar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
new ConsultarDatos().execute("https://api-adress/file.php?DNI=" + etDNI.getText().toString());
//while(working)
//{
//}
if (txtCategoria.getText()!="") {
btnGenerar.setVisibility(View.INVISIBLE);
etDNI.setVisibility(View.INVISIBLE);
txtCategoria.setVisibility(View.VISIBLE);
txtDNI.setVisibility(View.VISIBLE);
txtEstado.setVisibility(View.VISIBLE);
txtNombre.setVisibility(View.VISIBLE);
imgTarjeta.setVisibility(View.VISIBLE);
}
else
{
Toast.makeText(getApplicationContext(),"DNI Incorrecto",Toast.LENGTH_LONG).show();
}
}
});
as i commented i tried to do a while that would wait until the textsviews are all set but that just crashed my app
I resolved it, just moved the the visibility set and validation to the end of the onPostExecute and just to be sure i put the toast in the exception too just so the user gets some feedback
protected void onPostExecute(String result) {
JSONArray ja = null;
try {
ja = new JSONArray(result);
txtNombre.setText(ja.getString(0) +" " + ja.getString(1));
txtCategoria.setText(ja.getString(2));
txtDNI.setText(ja.getString(3));
txtEstado.setText(ja.getString(4));
if (txtCategoria.getText()!="") {
btnGenerar.setVisibility(View.INVISIBLE);
etDNI.setVisibility(View.INVISIBLE);
txtCategoria.setVisibility(View.VISIBLE);
txtDNI.setVisibility(View.VISIBLE);
txtEstado.setVisibility(View.VISIBLE);
txtNombre.setVisibility(View.VISIBLE);
imgTarjeta.setVisibility(View.VISIBLE);
}
else
{
Toast.makeText(getApplicationContext(),"DNI Incorrecto",Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),"DNI Incorrecto",Toast.LENGTH_LONG).show();
}
}
Use something like https://www.getpostman.com/ to see what the result of your API call is. Right now it seems like you don't know what you're getting back, and how consistently it comes back. You need to validate that your server is sending you back valid data.
Using a json library to parse the JSON response, such as GSON or Moshi would help you out as well. Right now you're trying to get the values based on arbitrary numbers. You could be having an exception from just one field missing, but there's not enough info to tell. Gson is fairly easy to set up in my experience: https://github.com/google/gson
I have two global variables currentTemp and currentHum that are set when Volley's onResponse method is called. My code looks like this:
// Request a string response from the provided URL.
private JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, WEATHER_URL, null, new Response.Listener<JSONObject>() {
public void onResponse(JSONObject response) {
try {
JSONObject main = new JSONObject(response.getString("main"));
currentTemp = main.getString("temp");
currentHum = main.getString("humidity");
Log.i("RES", "Temp: " + main.getString("temp") + " Hum: " + main.getString("humidity"));
} catch (JSONException e) {
e.printStackTrace();
}
}}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(appContext, "An error occurred while retrieving weather info", Toast.LENGTH_LONG).show();
Log.e("ERR", "ERROR RET WEATHER DATA");
}
});
// Call the OpenWeatherMap API and get data such as temperature and humidity
private String getWeatherInfo(String key) {
// Add the request to the RequestQueue to invoke the API
queue.add(jsonObjectRequest);
// Access variables set by Volley's onResponse here.
switch (key) {
case "temp":
return String.valueOf(Float.parseFloat(currentTemp) - 273.15);
case "hum":
return currentHum;
default:
return " ";
}
}
I want to be able to access the values of the global variables set by the onResponse method in the getWeatherInfo method that invoked it. Then pass the values to a switch statement for processing. How do I do it without getting empty values for currentTemp and currentHum?
This work is meant to be done with use of an interface. If you don't know about an interface callbacks then please go through this answer. Which will help you understand interface, and plus point that this will guide you for handling volley response.
Also this is not recommended to take global variables to set any response, rather you can pass your whole JsonObject from volley class. and parse it where you make a call. You can use Gson for parsing the response to your Model or ArrayList.
As I'm using Retrofit, I've designed all the POJOs and it was working flawlessly. API is designed in such a way that it will send the required data if the data is of current date or of future dates but not for past dates. In the response, I'll get a JSON response contains a combination of JSON objects and an array as a value of a JSON object and POJOs are according to that. Now if there is no record for present and future dates then I'll receive a string instead of an array and that leads to API error java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING. So what I wanna know if there is any way that I can determine - what I'm receiving an array or a string? and how to update POJO according to that to avoid that error.
JSON response when server has no data
{
"Result_Code": "ND",
"Result_Status": "Success",
"Result_Message": "No record found in database.",
"Result_Output": "",
"updatedDate": "20-07-2017 10:44:37"
}
JOSN response will be same when server has data but with one difference
{
"Result_Code": "ND",
"Result_Status": "Success",
"Result_Message": "record found in database.",
"Result_Output": [{multiple elements},
{multiple elements},
{multiple elements}....],
"updatedDate": "20-07-2017 10:44:37"
}
Pojo class named ResponseModel
public class ResponseModel {
private String Result_Code;
private String Result_Status;
private String Result_Message;
private Object Result_Output;
private String updatedDate;
...
}
using Object you can morph as below
call.enqueue(new Callback<ResponseModel>()
{
#Override
public void onResponse(Response<ResponseModel> response, Retrofit retrofit)
{
parseData(); // get other data from ResponseModel Class
if (response.getResultOutput() instanceof List<POJO>)
{
doSomething();
}
else if (response.getResultOutput() instanceof String)
{
doSomething();
}
else //must be error object
{
doSomething();
}
}
#Override
public void onFailure(Throwable t)
{
///Handle failure
}
});
using instanceof you check desired Object type
Where List<POJO> used for multiple elements Model
*check updated solution for parsing ArrayList from response object
hopefully it might be work as you want
catch your json in debug mode and generate pojo class with link below. then compare your class and see difference
http://www.jsonschema2pojo.org/
you can try this method.
try {
callArrayPojo();
} catch (IllegalStateException e) {
callStringPojo();
} catch (Exception e) {
//other}
or you can get ResultMessage generic type
...
private String Result_Code;
private String Result_Status;
private T Result_Message;
...
I am facing an issue calling .net .asmx web service with parameter using android volley library.
Without parameter its working fine.
This my web service
[WebMethod]
private string MN_InsEOMTestScoreDetailsIndividual(string data)
{
ArrayList arrReturnDetails = new ArrayList();
bool bReturn = false;
string errMsg = globalErrMsg;
try
{
Dictionary<string, object> dicData = JsonConvert.DeserializeObject<Dictionary<string, object>>(data);
bReturn = InsEOMTestScoreDetailsIndividual(dicData["eomTSIndvlDetId"].ToString().Trim(), dicData["eomTRDetId"].ToString().Trim(), dicData["eomTSSummDetId"].ToString().Trim(),
dicData["studCode"].ToString().Trim(), dicData["ctrCode"].ToString().Trim(), dicData["batCode"].ToString().Trim(), dicData["phCode"].ToString().Trim(), dicData["pcCode"].ToString().Trim(),
dicData["tmCode"].ToString().Trim(), dicData["testActualDur"].ToString().Trim(),
dicData["testAttemptDur"].ToString().Trim(), dicData["testTtlMks"].ToString().Trim(), dicData["mksObt"].ToString().Trim(), dicData["ttlQues"].ToString().Trim(),
dicData["rAnsCnt"].ToString().Trim(), dicData["wAnsCnt"].ToString().Trim(), dicData["attemptTestDate"].ToString().Trim(),
dicData["isSolViewed"].ToString().Trim(), dicData["quesXML"].ToString().Trim(), out errMsg);
}
catch (Exception ex)
{
ErrorHandler.LogError("WebService:APP_UserActivityDetails", "M_InsEOMTestScoreDetailsIndividual", ex);
}
arrReturnDetails.Add(new
{
b = bReturn,
err = errMsg
});
return JsonConvert.SerializeObject(arrReturnDetails);
}
Your web service is probably a GET web service which you are trying to invoke as POST. That won't work. There are two ways to correct this:
Make sure your web service is of POST type and then add your parameters as a HashMap in the Volley request.
If you want to keep the web service as a GET, then append the parameters manually to the URL string (i.e. don't pass them as key-value pairs in a HashMap).
I want to show Facebook Page's Notes items with those comments and likes using Graph API.
To do that, I'm using the asyncFacebookRunner in Facebook SDK.
Steps are like this:
call asyncFacebookRunner.request to get Note Item with PageId
mAsyncRunner.request(sAPIString, new NotesRequestListener(), null);
Response has come. ( I can't highlight function call. Sorry for inconvenient to find it.)
public class NotesRequestListener implements com.facebook.android.AsyncFacebookRunner.RequestListener
{
/**
* Called when the request to get notes items has been completed.
* Retrieve and parse and display the JSON stream.
*/
#Override
public void onComplete(String response, Object state) {
// TODO Auto-generated method stub
Log.i("My_TAG", "onComplete with response, state");
try
{
// process the response here: executed in background thread
final JSONObject json = new JSONObject(response);
JSONArray arrNotesItems = json.getJSONArray("data");
int l = (arrNotesItems != null ? arrNotesItems.length() : 0);
// !!!!
// This has another request call
// !!!!
final ArrayList<WordsItem> newItems = WordsItem.getWordsItems(arrNotesItems,getActivity());
WordsActivity.this.runOnUiThread(new Runnable() {
public void run() {
wordsItems.clear();
wordsItems.addAll(newItems);
aa.notifyDataSetChanged();
}
}); // runOnUiThread
} // try
catch (JSONException e)
{
Log.i("My_TAG", "JSON Error in response");
} // catch
} // onComplete
... other override methods ...
} // Request Listener
< Another Class >
public static ArrayList<WordsItem> getWordsItems(JSONArray arrJSON, Activity activity) {
ArrayList<WordsItem> wordsItems = new ArrayList<WordsItem>();
int l = (arrJSON != null ? arrJSON.length() : 0);
try {
WordsItem newItem;
for (int i=0; i<l; i++) {
JSONObject jsonObj = arrJSON.getJSONObject(i);
String sTitle = jsonObj.getString("subject");
String sNoteID = jsonObj.getString("id");
... get another fields here ...
newItem = new WordItem(...);
// !!!!
// This has request call for comments
// !!!!
ArrayList<CommentItem> arrComment = getUserComments(sNoteID);
wordsItems.add(newItem);
}
} catch (Exception e) {
e.printStackTrace();
}
return wordsItems;
} // getWordsItems
call another asyncFacebookRunner.request to get comments of item(with NoteID)
in getUserComments
mAsyncRunner.request(sAPIString, new CommentRequestListener(), null);
Before getting comments(OnComplete in CommentRequestListener has not called), getWordsItems returns item array.
So I can't see the comments.
How can I wait to update UI till getting comments?
(It's so ironic to synchronize asynchronized calls.)
Thanks in advance.
Use facebook object which has non-asynchronous request method.
You need not implement listener method.
So, I suggest below means.
use mAsyncRunner.request for first request call.
use mFacebookRunner.request for second request call.
I hope it may help you:-)
Using FQL - Facebook Query Language you can easily get all this information about any particular note info
, Also to get likes on that and comments over it as like examples given in the links.