How do I manage request codes android with more readability? - java

I wish to find a better way of handling responses than the method I was taught by the company that I worked for.
I was taught to use a generic HttpClient, that used volley to send the requests. The client had a static method that would be given a generic listener, ResponseListener, which would make the callback to the context when a volley response came through. The ResponseListener would keep track of all the request "type"s . That is the code given to the client so that the context can differentiate between requests.
Is there any other way of keeping track of all the request codes without having to keep one big directory type interface file? It becomes quite overwhelming to look at when you get past 100 requests. Then you write wrapper functions for the codes in the client, and it too gets messy.
HttpClient
public static void doRequestString(final ResponseListener listener, final int type, final String url, final JSONObject postData) {
// Request a string response
StringRequest request = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// Result handling
listener.onRequestDone(type, response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// Error handling
System.out.println("Something went wrong!");
error.printStackTrace();
}
});
request.setTag(context);
VolleyClient.getInstance(context).getRequestQueue().add(request);
}
Listener
public interface ResponseListener
{
int HELLO_REQUEST = 0;
int GOODBYE_REQUEST = 1;
// every other request numbered here, so they don't conflict
void onRequestDone(int type, String response);
}
Context
public void onRequestDone(int type, String response)
{
switch(type) {
case Response.Listener.HELLO_REQUEST:
handleHello();
break;
case Response.Listener.GOODBYE_REQUEST:
handleGoodbye();
break;
}
}

Well, there are not that many options, to be honest. You are dealing with your responses in a centralised manner right now. Another option would be stripping the request type as having a listener per request. The main disadvantage here is that you will get your code full of listeners.
I would suggest you try and combine the two approaches in a way that suites your use case. Maybe create an intermediate service layer, divide your functionality by some of their property (for example logically - all user requests grouped together, etc), expose a single listener per service and manage the request codes there. This way you can have a bit of modularity.

Related

Get Request Body from a Java 11 HttpRequest [duplicate]

In a test, I'd like to look inside the body of a HttpRequest. I'd like to get the body as a string. It seems that the only way to do that, is to subscribe to the BodyPublisher but how does that work?
This is an interesting question. Where do you get your HttpRequest from? The easiest way would be to obtain the body directly from the code that creates the HttpRequest. If that's not possible then the next thing would be to clone that request and wraps its body publisher in your own implementation of BodyPublisher before sending the request through the HttpClient. It should be relatively easy (if tedious) to write a subclass of HttpRequest that wraps an other instance of HttpRequest and delegates every calls to the wrapped instance, but overrides HttpRequest::bodyPublisher to do something like:
return request.bodyPublisher().map(this::wrapBodyPublisher);
Otherwise, you might also try to subscribe to the request body publisher and obtain the body bytes from it - but be aware that not all implementations of BodyPublisher may support multiple subscribers (whether concurrent or sequential).
To illustrate my suggestion above: something like below may work, depending on the concrete implementation of the body publisher, and provided that you can guard against concurrent subscriptions to the body publisher. That is - in a controlled test environment where you know all the parties, then it might be workable. Don't use anything this in production:
public class HttpRequestBody {
// adapt Flow.Subscriber<List<ByteBuffer>> to Flow.Subscriber<ByteBuffer>
static final class StringSubscriber implements Flow.Subscriber<ByteBuffer> {
final BodySubscriber<String> wrapped;
StringSubscriber(BodySubscriber<String> wrapped) {
this.wrapped = wrapped;
}
#Override
public void onSubscribe(Flow.Subscription subscription) {
wrapped.onSubscribe(subscription);
}
#Override
public void onNext(ByteBuffer item) { wrapped.onNext(List.of(item)); }
#Override
public void onError(Throwable throwable) { wrapped.onError(throwable); }
#Override
public void onComplete() { wrapped.onComplete(); }
}
public static void main(String[] args) throws Exception {
var request = HttpRequest.newBuilder(new URI("http://example.com/blah"))
.POST(BodyPublishers.ofString("Lorem ipsum dolor sit amet"))
.build();
// you must be very sure that nobody else is concurrently
// subscribed to the body publisher when executing this code,
// otherwise one of the subscribers is likely to fail.
String reqbody = request.bodyPublisher().map(p -> {
var bodySubscriber = BodySubscribers.ofString(StandardCharsets.UTF_8);
var flowSubscriber = new StringSubscriber(bodySubscriber);
p.subscribe(flowSubscriber);
return bodySubscriber.getBody().toCompletableFuture().join();
}).get();
System.out.println(reqbody);
}
}

How to get POJO from a volley callback, and use/return it in the calling function?

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.

How do I effectively use an event bus?

Right now I am exploring some options for an android learning project.
I am trying to communicate with my rails api (also a learning project).
After doing some research, I think I have settled on a scheme that uses retrofit and otto.
What I end up with is this.
When I want to make a call to my rails server (in this case to do a signup) I do this in the activity.
mBus.post(new SignupRequestEvent(new UserRequestParams(mName,mEmail,mPassword,mPasswordConfirmation )));
and then in the same activity I have this.
#Subscribe
public void onSignupCompleted(SignupCompletedEvent event) {
System.out.println(String.format("in onSignupCompleted, got token = %s ", event.getParams().getToken()));
}
The problem here is that, as it stands, every api request type and it corresponding response type would be a unique event type and require it's own class, which seems like a lot of boiler plate type of code.
For example to handle sign in and sign out I would need these two classes:
public class SignupRequestEvent {
protected UserRequestParams mSignupParams;
public SignupRequestEvent(UserRequestParams signupParams) {
mSignupParams = signupParams;
}
public UserRequestParams getParams() {
return mSignupParams;
}
}
public class SignupCompletedEvent {
private SignupCompletedParams mSignupCompletedParams;
public SignupCompletedParams getParams() {
return mSignupCompletedParams;
}
public SignupCompletedEvent(SignupCompletedParams signupCompletedParams) {
mSignupCompletedParams = signupCompletedParams;
}
}
And I think most of the event classes would be pretty much identical.
I am thinking I should just have 2 events for api calls , one for requests and one for responses, but then each method that receives an api response event would need to check if it is a response to the desired request.
This option would mean something like this:
ApiRequestEvent apiRequestEvent = new ApiRequestEvent();
apiRequestEvent.setAction("SIGNUP");
apiRequestEvent.setParameters(new UserRequestParams(mName,mEmail,mPassword,mPasswordConfirmation ));
mBus.post(apiRequestEvent);
and then to handle the response something like this:
#Subscribe
public void onSignupCompleted(ApiResponseAvailable event) {
if (event.getResponseTo != "SIGNUP") return;
System.out.println(String.format("in onSignupCompleted, got token = %s ", event.getParams().getToken()));
Maybe there is a way to use generics?
Can someone explain how to effectively use an event bus when there are a set of events that can be grouped together like this?
You're overthinking it - just go ahead and create a message object for each event.

Best way to organize AsyncTask

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"));

GWT request factory - Fire request inside of success method of another request

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();

Categories