I'm trying to do something similar to the answer of this question
I'm using Volley rather than Retrofit, and have adapted my code accordingly. For me the callback handlers never actually fire, although the counDownLatch does timeout after the specified number of seconds. I suspect the handlers never fire because the countDownLatch.awaiting is using all the processing on the current thread. Or am I missing something else?
public void queryUmbrellaServer() {
ArrayList<String> identifiers = getHardwareIdentifiers(context);
VolleyLog.DEBUG = true;
CountDownLatch countDownLatch = new CountDownLatch(identifiers.size());
// creating a new variable for our request queue
final RequestQueue[] queue = {Volley.newRequestQueue(context)};
queue[0].start();
for (int i = 0; i < identifiers.size(); i++) {
String url = umbrellaServerUrl + identifiers.get(i) + "/";
Log.i(LOG_TAG, "Inside Loop " + url);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
countDownLatch.countDown();
String serverName = response.getString("mdm_server_url");
String registrationUrl = response.getString("registration_url");
String isDeviceOwner = response.getString("device_owner");
Toast.makeText(context, "Retrieved server name from umbrella server: " + serverName, Toast.LENGTH_LONG).show();
setMdmInfo(serverName, registrationUrl, isDeviceOwner);
Log.i(LOG_TAG, "Successful response");
//queue[0].stop();
results.add(isDeviceOwner.toString());
} catch (JSONException e) {
e.printStackTrace();
Log.d(LOG_TAG, "Error in parsing response");
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
countDownLatch.countDown();
if(error.networkResponse.data!=null) {
String jsonString = new String(error.networkResponse.data);
//Log.d(LOG_TAG, jsonString);
try {
JSONObject jsonObject = new JSONObject(jsonString);
String msg = jsonObject.getString("message");
if (!msg.equals("Device not found")) {
Log.d(LOG_TAG, "Error in retrieving response from server");
//queue[0].stop();
results.add("false");
}
else {
Log.d(LOG_TAG, "No device found");
results.add("false");
}
} catch (JSONException e) {
e.printStackTrace();
Log.d(LOG_TAG, "Error in retrieving response from server");
//queue[0].stop();
results.add("UNSET");
}
}
else {
Log.d(LOG_TAG, "Error in retrieving response from server");
//queue[0].stop();
results.add("UNSET");
}
}
});
// Add the request to the RequestQueue.
queue[0].add(jsonObjectRequest);
}
try {
countDownLatch.await(1L * identifiers.size(), TimeUnit.SECONDS); // join thread with timeout of second for each item
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d(LOG_TAG,"outside loop" + results);
}
I expected the results arrayList should get populated before the countDownLatch countdown completes, but I haven't been able to get any results.
Related
I want to return string value after getting response from web service in Volley and call value in activity.
Below is my code;
Utils.java
public static String getitemCountPrice(String cartId) {
try {
if (Utils.isNetworkAvailable(mContext)) {
HashMap<String, String> params = new HashMap<>();
params.put(CONSTANTS.API_param_cartid, cartId);
params.put(CONSTANTS.API_param_token, Utils.getToken());
JSONObject postdata = new JSONObject(params);
try {
YupITApplication.getJsonWithHTTPPostResponse(params, mContext, 1, (id, jsonResult) -> {
if (jsonResult.getString(mContext.getString(R.string.status)).equalsIgnoreCase(mContext.getString(R.string.success))) {
itemCountPrice = jsonResult.getJSONObject("Data").getString("Count") + ","
+ jsonResult.getJSONObject("Data").getString("TotalPrice");
Log.e("itemCountPrice.............", "" + itemCountPrice);
// Here I get value
} else {
itemCountPrice = "0,0";
}
}, Utils.cartitemcount, postdata);
} catch (Exception e) {
e.printStackTrace();
}
} else {
Toast.makeText(mContext, mContext.getString(R.string.no_server_found), Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
}
return itemCountPrice;
// Here I get null and this is called before web service call
}
MainActivity.java
Utils.getitemCountPrice(cart_id));
Every time I get null from above method
Your return statement will execute right after the making the API call and wouldn't wait for the response because it is written in synchronous way. You can notify the result with help of an interface
interface APIListener{
public void onResponse(String itemPrice);
}
your method would look like this
public static void getitemCountPrice(String cartId, APIListener apiListener) {
try {
if (Utils.isNetworkAvailable(mContext)) {
HashMap<String, String> params = new HashMap<>();
params.put(CONSTANTS.API_param_cartid, cartId);
params.put(CONSTANTS.API_param_token, Utils.getToken());
JSONObject postdata = new JSONObject(params);
try {
YupITApplication.getJsonWithHTTPPostResponse(params, mContext, 1, (id, jsonResult) -> {
if (jsonResult.getString(mContext.getString(R.string.status)).equalsIgnoreCase(mContext.getString(R.string.success))) {
itemCountPrice = jsonResult.getJSONObject("Data").getString("Count") + ","
+ jsonResult.getJSONObject("Data").getString("TotalPrice");
Log.e("itemCountPrice.............", "" + itemCountPrice);
apiListener.onResponse(itemCountPrice);
// Here I get value
} else {
itemCountPrice = "0,0";
apiListener.onResponse(itemCountPrice);
}
}, Utils.cartitemcount, postdata);
} catch (Exception e) {
e.printStackTrace();
}
} else {
Toast.makeText(mContext, mContext.getString(R.string.no_server_found), Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
You are mixing async call with sync call.
When you call method getItemCountPrice, you will actually receive your value from volley call when it will be available from network.
You need to use callback or some futurecall.
You can do it using callback like mentioned:
public static String getitemCountPrice(String cartId, onDataListener pDataListener) {
// some code
YupITApplication.getJsonWithHTTPPostResponse(params, mContext, 1, (id, jsonResult) -> {
if (jsonResult.getString(mContext.getString(R.string.status)).equalsIgnoreCase(mContext.getString(R.string.success))) {
itemCountPrice = jsonResult.getJSONObject("Data").getString("Count") + ","
+ jsonResult.getJSONObject("Data").getString("TotalPrice");
Log.e("itemCountPrice.............", "" + itemCountPrice);
// Here I get value
} else {
itemCountPrice = "0,0";
}
//pass value through callback
pDataListener.onItemCountPriceReceived(itemCountPrice)
}, Utils.cartitemcount, postdata);
// some code
}
Take one interface to pass data back to calling activity
interface OnDataListener{
void onItemCountPriceReceived(String itemCountPrice);
}
YourActivity code will look like this
Utils.getItemCountPrice(cart_id,new OnDataListener(){
#Override
void onItemCountPriceReceived(String itemCountPrice){
//you will get your value here when received from network call
}
})
I am getting a error in my code. The outer request returns a data but the inner loop returns null.
What I am doing here is: I am requesting some data and again using the id that I get from the first request, i use it to send another request. Although I am receiving the first response, I am getting ERRORNull message in the second nested request.
I am sure that the url is correct. I have not been able to find the solution to this problem.
private ArrayList<Item> fetchApiData(){
String url="http://www.gadgetsinnepal.com.np/wp-json/wp/v2/posts/";
JsonArrayRequest jsArrayRequest = new JsonArrayRequest
(Request.Method.GET, url, null, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
try {
// Parsing json array response
// loop through each json object
for (int i = 0; i < response.length(); i++) {
JSONObject item = (JSONObject) response
.get(i);
String id = item.getString("id");
String date = item.getString("date");
JSONObject titleobj = item
.getJSONObject("title");
String title= titleobj.getString("rendered");
String featuredMedia= item.getString("featured_media");
Toast.makeText(getApplicationContext(), "ID :" + id +" Date: "+ date+ " Title "+ title + featuredMedia,
Toast.LENGTH_SHORT).show();
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET,
"http://www.gadgetsinnepal.com/wp-json/wp/v2/media/"+featuredMedia, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject nested_response) {
try {
// Parsing json object response
// response will be a json object
JSONObject guilld = nested_response.getJSONObject("guid");
String featured_img_url = guilld.getString("rendered");
String nestid=nested_response.getString("id");
Toast.makeText(getApplicationContext(),nested_response.toString()+"IMAGE" + nestid,Toast.LENGTH_LONG).show();
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),
"Error: " + e.getMessage(),
Toast.LENGTH_LONG).show();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getApplicationContext(),
"ERROR"+error.getMessage(), Toast.LENGTH_LONG).show();
}
});
MySingleton.getInstance(getApplicationContext()).addToRequestQueue(jsonObjReq);
}
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),
"Error: " + e.getMessage(),
Toast.LENGTH_LONG).show();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// TODO Auto-generated method stub
}
});
MySingleton.getInstance(this).addToRequestQueue(jsArrayRequest);
}
This problem was solved by carefully examining where the error log was giving.
Having unique logs in your methods will make finding the place where the problem occurs easier to find.
In this case we found that something was happening in:
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getApplicationContext(),
"ERROR"+error.getMessage(), Toast.LENGTH_LONG).show();
}
Further investigation showed we got a response code 503 message there.
Reasons for this to happen: lifewire.com/503-service-unavailable-explained-2622940
Increasing the time out of the request seems to prevent this from occurring again.
I have a problem where i am unable to return a string from this method. I was unsuccessful when I tried creating a new variable outside the Response.Listener. This is probably very simple but how do I go about returning a string from this method. The string I want to return is the 'featured_img_url' string.
public String secondServiceCall(String featuredmedia){
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET,
"http://www.gadgetsinnepal.com/wp-json/wp/v2/media/"+featuredmedia, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject nested_response) {
try {
JSONObject guilld = nested_response.getJSONObject("guid");
String featured_img_url = guilld.getString("rendered");
Toast.makeText(getApplicationContext(),"IMAGE :" + featured_img_url,Toast.LENGTH_LONG).show();
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),
"Error: " + e.getMessage(),
Toast.LENGTH_LONG).show();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getApplicationContext(),
"ERROR "+error.getMessage(), Toast.LENGTH_LONG).show();
}
});
MySingleton.getInstance(getApplicationContext()).addToRequestQueue(jsonObjReq);
return featured_img_url;
}
update your code to:
String featured_img_url = null;
public String secondServiceCall(String featuredmedia){
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET,
"http://www.gadgetsinnepal.com/wp-json/wp/v2/media/"+featuredmedia, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject nested_response) {
try {
JSONObject guilld = nested_response.getJSONObject("guid");
featured_img_url = guilld.getString("rendered");
Toast.makeText(getApplicationContext(),"IMAGE :" + featured_img_url,Toast.LENGTH_LONG).show();
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),
"Error: " + e.getMessage(),
Toast.LENGTH_LONG).show();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getApplicationContext(),
"ERROR "+error.getMessage(), Toast.LENGTH_LONG).show();
}
});
MySingleton.getInstance(getApplicationContext()).addToRequestQueue(jsonObjReq);
return featured_img_url;
}
Here, you should simply pass the instance that call this methods to execute the methods from the response.
So change the methods to :
public void secondServiceCall(String featuredmedia, final MyClass caller){
Note that this will return nothing. And the caller instance need to be final to be used in the inner class JsonObjectRequest.
and in the response, you need to pass the value to the instance of MyClass. So add a method in MyClass
public void setFeatureImgUrl(String featuredImgUrl){ ... }
and you just need to call this in the response.
public void onResponse(JSONObject nested_response) {
...
caller.setFeatureImgUrl(feature_img_url);
...
}
Note : This could be done with an Observer pattern but I know that some people doesn't like it. I could add an example of it if needed.
I have an onClickListener that uses Okhttp to asynchronously get some stuff in the background. Here's the OnClickListener:
mGetChartButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String companyName = mSymbolValue.getText().toString();
getRequest(companyName, "chart");
Log.i(TAG, mChartProfile.getSizeDates()+""); // Null exception happens here
}
});
And here is the Okhttp snippet:
OkHttpClient client = new OkHttpClient();
Request request = new Request
.Builder()
.url(completeUrl)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
try {
String jsonData = response.body().string();
Log.v(TAG, jsonData);
if (response.isSuccessful()) {
if (requestType.equals("quote")) {
isValidSearch = getQuote(jsonData);
runOnUiThread(new Runnable() {
#Override
public void run() {
if (isValidSearch) {
updateDisplay();
}
toggleFacts(isValidSearch);
}
});
}
else{
getChartInfo(jsonData);
}
} else {
alertUserAboutError();
}
} catch (IOException e) {
Log.e(TAG, "Exception caught: ", e);
} catch (JSONException e) {
Log.e(TAG, "JSONException caught: ", e);
Toast.makeText(BuyActivity.this, "oops!", Toast.LENGTH_LONG).show();
}catch (ParseException e){
Log.e(TAG, "Unable to parse", e);
}
}
});
// How do I do a thread.join() here?
private void getChartInfo(String jsonData) throws JSONException, ParseException{
JSONObject wholeChartData = new JSONObject(jsonData);
JSONArray dates = wholeChartData.getJSONArray("Dates");
mChartProfile = new ChartProfile();
// ChartProfile contains ArrayList of ChartDate and ArrayList of ChartValue
for (int i = 0; i < dates.length(); i++){
ChartDate chartDate = new ChartDate(dates.getString(i));
mChartProfile.addToDates(chartDate);
}
JSONArray values = close.getJSONArray("values");
for (int i = 0; i < values.length(); i++){
ChartValue chartValue = new ChartValue(values.getDouble(i));
mChartProfile.addToValues(chartValue);
}
}
Right now, I'm getting an error of thread exiting with uncaught exception. And this is caused by a null exception because when calling mChartProfile.getSizeDates(), the values haven't been written in yet. My intuition is that the call to getChartInfo(jsonData) doesn't finish and the main UI thread is already returning from the getRequest() function. Hence, it will continue next line, and try to access an empty array that has not been initialized. Hence, I get a null exception. My solution is to have the main thread wait on the worker thread by calling thread.join() but I am not sure of how to do this through this Okhttp interface. Any help is deeply appreciated.
I am creating an Android chat application wherein I am using WebSockets and on top of that I want to create a custom implementation of Application protocol.
I am stuck in a situation.
Essentially, what I want is a way to know that an event handler method has been called in another class, fire up my own method in my class based on that and then get the result of that event handler method in my class.
How is that possible?
I researched a lot and found something like binding, event emitters, etc. Can someone point me to the right direction and provide some resources from where I can learn this technique?
This is what I have done so far:
public void connect(){
try {
setUpWebSocketHandler(handler);
mConnection.connect(wsuri, handler);
}
catch (WebSocketException e) {
Log.d("exception", e.toString());
}
}
public void setUpWebSocketHandler(WebSocketHandler handler)
{
handler = new WebSocketHandler(){
//first method for websockethandler
#Override
public void onOpen() {
//here i create a json format string to be sent to my server that returns something afterwards
String output = json.toString();
Log.d("OUTPUT+" , output);
Log.d("onOpen", "Status: Connected to " + wsuri);
mConnection.sendTextMessage(output);
}
//second method for websockethandler
#Override
public void onTextMessage(final String payload) {
Log.d("onTextMessage", "Response: " + payload);
JSONObject jsonObj = null;
try {
jsonObj = new JSONObject(payload);
} catch (JSONException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
String type = jsonObj.getString("type");
switch (type) {
case "xxx":
//authEvent
System.out.println("xxx");
break;
case "yyy":
//userOnlineEvent
System.out.println("yyy");
break;
case "zzz":
System.out.println("zzz");
break;
case "userListToken":
userList = getUserList(payload);
break;
default:
System.out.println("DefaultCase");
break;
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//third method for websockethandler
#Override
public void onClose(int code, String reason) {
Log.d("onClose", "Connection lost.");
}
};
}
public String getUserList(final String payload)
{
final Thread connectthread;
connectthread = new Thread(
new Runnable()
{
public void run()
{
try {
//here i create a URL, send post request to it and i get a response with userlist
HttpClient client = new DefaultHttpClient();
HttpGet post = new HttpGet(url);
HttpResponse response = client.execute(post);
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
while ((userList = rd.readLine()) != null) {
System.out.println(userList);
Log.d("HTTP GET RESPONSE", "Response: " + userList);
}
} catch (JSONException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
);
connectthread.start();
try
{
connectthread.join();
}
catch (Exception e)
{
Log.i("error","Error!!");
}
System.out.println("userListToken");
return userList;
}
I have another question. I got the userList using callbacks....The problem now is:
private class ProcessLogin extends AsyncTask<String, Void, String> {
private ProgressDialog pDialog;
String uname,password;
#Override
protected void onPreExecute() {
super.onPreExecute();
uname = txtUsername.getText().toString();
password = txtPassword.getText().toString();
pDialog = new ProgressDialog(LoginActivity.this);
pDialog.setTitle("Contacting Servers");
pDialog.setMessage("Logging in ...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
#Override
protected String doInBackground(String... args) {
String user = null;
ifly.connect();
user = userList;
return user;
}
#Override
protected void onPostExecute(String user) {
try {
if(user != null){
//Intent i = new Intent("com.example.tabmainactivity");
Log.d("Got it", "Response: " + userList);
pDialog.dismiss();
//startService(new Intent(getApplicationContext(),iFlyChatMessage.class));
//startActivity(i);
//finish();
}else{
// username / password doesn't match
pDialog.dismiss();
Toast.makeText(getApplicationContext(),
"Incorrect username/password", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void processMessage(String userList)
{
this.userList = userList;
}
I want the userList in postExecute so that i can send this userList to another activity. How do i stop doinbackground() to wait for callback to finish. If I use thread.sleep, the whole process stops, not even connect works.
Thanks
You can declare an interface somewhere, make your event handler accept an instance of this interface, then create an anonymous class implementing this interface while passing that instance in your handler's registration with event source.
Something like below:
public class MyClass{
...
...
component.addXXXListener(new EventHandler(new MyInterface() {
#Override
public void doSomething() {
callMethod();
}
}));
...
...
public void callMethod() {
...
...
}
I hope you got the point.
I'm not sure that I understood you correctly.
You should use callback object.
Something like:
public interface MessageProcesor{
public void processMessage(String message);
}
Your activity should implement this interface.
And you should have MessageProcesor field in your "client" class.
Your code should look something like this:
private MessageProcesor callback;
public void setUpWebSocketHandler(WebSocketHandler handler)
{
handler = new WebSocketHandler(){
//first method for websockethandler
#Override
public void onOpen() {
//here i create a json format string to be sent to my server that returns something afterwards
String output = json.toString();
Log.d("OUTPUT+" , output);
Log.d("onOpen", "Status: Connected to " + wsuri);
mConnection.sendTextMessage(output);
}
//second method for websockethandler
#Override
public void onTextMessage(final String payload) {
Log.d("onTextMessage", "Response: " + payload);
JSONObject jsonObj = null;
try {
jsonObj = new JSONObject(payload);
} catch (JSONException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
String type = jsonObj.getString("type");
switch (type) {
case "xxx":
//authEvent
System.out.println("xxx");
break;
case "yyy":
//userOnlineEvent
System.out.println("yyy");
break;
case "zzz":
System.out.println("zzz");
break;
case "userListToken":
userList = getUserList(payload);
callback.processMessage(userList);
break;
default:
System.out.println("DefaultCase");
break;
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//third method for websockethandler
#Override
public void onClose(int code, String reason) {
Log.d("onClose", "Connection lost.");
}
};
}
public String getUserList(final String payload)
{
final Thread connectthread;
connectthread = new Thread(
new Runnable()
{
public void run()
{
try {
//here i create a URL, send post request to it and i get a response with userlist
HttpClient client = new DefaultHttpClient();
HttpGet post = new HttpGet(url);
HttpResponse response = client.execute(post);
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
while ((userList = rd.readLine()) != null) {
System.out.println(userList);
Log.d("HTTP GET RESPONSE", "Response: " + userList);
}
} catch (JSONException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
);
connectthread.start();
try
{
connectthread.join();
}
catch (Exception e)
{
Log.i("error","Error!!");
}
System.out.println("userListToken");
return userList;
}
You can pass "callback" as constructor param or via setter method.
Hope this helps.