I have the following situation :
final String value = null;
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
#Override
public void onSuccess(String response) {
value = response;
}
});
System.out.println(value);
I am running this code from my main class.
Now I need to be able to use the variable (String Response) from the over ridden class in my main class.
How am i meant to go about getting this variable, as clearly what i have doesnt work.
ps, suggest an edit for the name, I didnt know what to call it.
Your problem doesn't have to do with classes; it's that you're using asynchronous code synchronously. Anything you want to do with the string response must be within the onSuccess handler (or a function called by it).
Related
I'm implementing a simple mobile app with user accounts. Additionally, it must be structured in a layered architecture that cleanly separates presentation, logic and access to the database.
I'm currently able to send and get data from a server, using the volley library. However, this data is only available inside the onResponse method of the Response.Listener<String> passed as a parameter in the constructor of stringRequest object, later used to perform the request. I want to use the data that I get in the response to construct a User object that I could use all over my app, and keep the layered architecture as much as possible.
This is an example of the kind of method I've been aiming for:
public ResponseType insertUser (final Context context, final String id, final String name, final String password) {
//using a wrapper object because have to declare object as final to use
//inside inner class, so use field to assign value
final ResponseWrapper wrapper = new ResponseWrapper();
StringRequest stringRequest = new StringRequest(Request.Method.POST, BuildConfig.ip,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
wrapper.response = response.equals("") ?
ResponseWrapper.SUCCESS :
ResponseWrapper.DB_ERROR;
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
wrapper.response = ResponseWrapper.CONNECTION_ERROR;
}
}){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> params = new HashMap<String,String>();
params.put("id",id);
params.put("name",name);
params.put("password",password);
return params;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(context);
requestQueue.add(stringRequest);
//waiting for callback to modify field
while(wrapper.response == null);
return wrapper.response;
}
I've tried setting a field of an external object inside onResponse, waiting for the field to be changed to continue execution, to no avail. The code compiles and performs the request, but the field is kept unchanged. My research has suggested to me that this is something to be expected when dealing with asynchronous code.
Most examples I've read limit their scope to using Toast to show the response in the screen. A couple change activities inside the method, but this goes against the layer separation that I'm trying to achieve by performing presentation actions inside the database access layer (and potentially performing business logic too, as my app becomes more complex).
So, how can I get an object from inside the callback? (For example the String containing the response, or an enum indicating the result of an operation).
If this isn't possible or advisable, how could I structure the code to keep the separation of concerns?
My thanks in advance for any suggestion that could steer me in the right direction.
I want to update let's say a TextView's content after and Async call to my server using loopj's android-async-http library. So my "client" code:
public class AsyncClient {
private static final String BASE_URL = "http://my.server.com";
private static AsyncHttpClient client = new AsyncHttpClient();
public static void get(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
client.get(getAbsoluteUrl(url), params, responseHandler);
}
private static String getAbsoluteUrl(String relativeUrl) {
return BASE_URL + relativeUrl;
}
}
My client's request method is:
class AsyncClientRequests {
public void getData() throws JSONException {
AsyncClient.get("/data", null, new JsonHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
// Update UI according to response <<<<-----
}
});
}
}
My question is, how can I update my TextView if I don't have any Activity instance in the "getData" method? I can't use findViewById() method, to get the TextView and set it's text.
My only idea is to make an Observer for it with a static list of the Observed Activities.
After this, make my activity observed in the onCreate() (unobserved in the onDestroy) and after the async call use the static methods (which i can reach from the onSuccess method, maybe make my observer a singleton too) to notify the object of getting updated.
I don't think btw this is an acceptable method, because of the conflicts in the static list of observed objects. (not sure if it can happen, im really new in the android world :) )
Can you suggest me something better approach, or more "android like", or i should go with this and hope it will work?
I am a relatively new Android developer and am working on an application right now that makes a lot of calls to a RESTful web service.
I am making each call in an asyncTask but in some files, the amount of different async tasks I have approaches 15. Right now I have them all as private classes inside my activity class. How can I organize them better(i.e. put them in separate files) while still being able to update the UI.. I was thinking of passing the context into the constructor of each asyncTask but I was just wondering if there was a best practice/better way.
Thanks!
Instead of using so many classes for different types of asynctask , I suggest you use this library
you can have a look at here
http://loopj.com/android-async-http/
your code will become very very less , instead of declaring so may asynctask seperately writing bulk of code , you can just use 4 lines of code
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
#Override
public void onSuccess(String response) {
System.out.println(response);
}
});
I is very efficient in geting the response very quickly.
I hope this will help you out. :)
Passing in the Activity as a constructor parameter sounds like a good plan to me. Basically the same is happening when you declare them as an inner class.
But keep in mind, that there are some drawbacks for using AsyncTasks to load data. Once started, they will continue to run even when the activity is already closed and hold a reference to your activity (it can therefore not be garbage collected).
You may want to look into other concepts like loaders.
Consider using a library to simplify your code base. I wrote droidQuery which, among other things, can be used to simplify AsyncTasks. For example, to get JSON data from example.com, and to have access to context afterwards, you can do this:
$.ajax(new AjaxOptions().url("http://www.example.com")
.context(this)
.type("GET")
.dataType("json")
.success(new Function() {
#Override
public void invoke($ droidQuery, Object... params) {
JSONObject json = (JSONObject) params[0];
Context context = droidQuery.context();
//TODO:
}
})
.error(new Function() {
#Override
public void invoke($ droidQuery, Object... params) {
AjaxError error = (AjaxError) params[0];
Log.e("Ajax", "Error " + error.status + ": " + error.reason);
}
}));
For lots of different requests that you call a lot, you can also create instances of AjaxOptions for later use, which have different URLs, types, dataTypes, etc:
Map<String, AjaxOptions> requests = new HashMap<String, AjaxOptions>();
//add the example above:
requests.put("example", new AjaxOptions().url("http://www.example.com")
.context(this)
.type("GET")
.dataType("json")
.success(new Function() {
#Override
public void invoke($ droidQuery, Object... params) {
JSONObject json = (JSONObject) params[0];
Context context = droidQuery.context();
//TODO:
}
})
.error(new Function() {
#Override
public void invoke($ droidQuery, Object... params) {
AjaxError error = (AjaxError) params[0];
Log.e("Ajax", "Error " + error.status + ": " + error.reason);
}
}));
Then later, just perform this task by calling:
$.ajax(requests.get("example"));
I am trying to nest two request factory calls in each other. I retrieve a post object and in the success-method i use the same object again (just for testing purposes, I get the same behavior for other request like for example persisting).
The problem is: Only the first request reaches the server.
I don't get any error message. If I debug the code, everything works until the second request is fired. Nothing happens then. The method on the backend is not called, the frontend shows no error, even if I implement the "onFailure"-method for the receiver of the second request.
public class RequestFactoryFindTest extends GWTTestCase{
/**
* must refer to a valid module that sources this class.
*/
public String getModuleName() {
return "com.Test.MyTest";
}
public void test(){
final ClientFactory clientFactory = GWT.create(ClientFactoryImpl.class);
final MyRequestFactory requestFactory = clientFactory.getRequestFactory();
final PostRequest request = requestFactory.postRequest();
request.findPost(1l).fire(new Receiver<PostProxy>() {
#Override
public void onSuccess(PostProxy response) {
final ClientFactory clientFactory = GWT.create(ClientFactoryImpl.class);
final MyRequestFactory requestFactory = clientFactory.getRequestFactory();
final PostRequest request = requestFactory.postRequest();
System.out.println("outer success");
request.findPost(1l).fire(new Receiver<PostProxy>() {
#Override
public void onSuccess(PostProxy response) {
System.out.println("inner success");
}
});
}
});
}
}
Can someone explain this?
Edit:
I tried a lot of stuff like to fire an event on the event bus, catch the event and do my inner request factory call there. But nothing worked. I think this is some Issue with the GWTTestcase in combination with RequestFactory.
I also changed my code, so i use only one clientFactory.
Try to create an event in the first onSuccess method. When your event is handled, you could send another request to the server.
Check out How to use the GWT EventBus to use the eventbus.
Thomas Broyer statement is also right. You should only use one RequestFactory and one ClientFactory!
This may be a problem when you are constructing your second client factory as per Thomas Broyer. You should probably go into your ClientFactory.java interface and at the top add the the single client factory instance. Also put a GWT.log("ON SUCCESS") at the top of your onSuccess(PostProxy response) to make sure it is getting there.
public interface ClientFactory {
public static final ClientFactory INSTANCE = GWT.create(ClientFactory.class);
...
Then you can simple do somehting like the following
final PostRequest request = ClientFactory.INSTANCE.getRequestFactory().postRequest();
So I have this GWT code that handles RPC requests maintain states(ready, waiting, error etc).
And I would like to check if the class change its states correctly after each call, set response variables etc.
Now how should I proceed to test that without making actual requests to the server(that could run into errors in the server it self).
I think I could mock the request callback class somehow but it is invisible to the test.
I'm lost, help!
Sample of the code below(I'll post the whole thing later in case anyone wants).
public class RPCHandler
{
public RPCHandler(String method,String[] argumentsName,
String[][] argumentsValues)
{
this.method = method;
this.argumentsName = argumentsName;
this.argumentsValues = argumentsValues;
}
/**
* Method that creates a RPC request using JSON in a POST
*
*/
public void rpcRequest(){
if(currentState == HandlerState.WAITING_RESPONSE)return;
currentState = HandlerState.WAITING_RESPONSE;
// Append watch list stock symbols to query URL.
url = URL.encode(url);
url += "action=";
url += method;
// Send request to server and catch any errors.
RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, url);
String requestData = parseToJSON(argumentsName, argumentsValues);
try{
Request request = builder.sendRequest(requestData, new RequestCallback()
{
public void onError(Request request, Throwable exception)
{
setRPCException(new Exception("Error while saving. Action="+method));
setCurrentState(HandlerState.ON_ERROR);
}
//Few other error, response received hander methods after this point.
}
}
It looks like you're trying to mock out the actual transport so you should build a mock of the RequestBuilder class. In JMockit, you could write:
public class MockRequestBuilder
{
public void $init( int method, String url)
{
/* check values and/or store for later */
}
public Request sendRequest( String data, RequestCallback callback )
{
/* check values and/or store for later */
}
}
You'll need to fill in the details of the what you want the mock to do. Also, you can isolate the callback testing if you moved the callback to a named class instance inside of your outer class:
public class MyGWTClass
{
protected static class RpcCallback extends RequestCallback
{
public void onError(...) { ... }
}
}
By moving the callback object into a class and using a factory method, you can create tests that only check the callback.