Update UI on android after async call - java

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?

Related

How to use RxJava or Observables to listen for a variable change in a different class?

I am attempting to do a login for an android app. My problem is that when I call login from Activity.java, the Service.java method uses call.enqueue from Retrofit and it is async. So I am not able to wait and consume the response in the Activity.java method (so that I can handle what happens next).
Therefore, I decided that if I can setup a listener of some sort to capture when the response object changes, that I can handle what happens next in the app.
I have been looking into RxJava but no examples that I have seen work across multiple classes or seem to actually work properly. It would be extremely helpful to have some basic syntax that I could apply to this that would allow me to consume the login response object so that I can handle what happens next in the application. I am not married to RxJava either so if there is a different way to approach this that will let me consume this object, I'm fine with that. Thanks!!
GlobalData.java
public class GlobalData {
public static LoginResponse globalResponse;
}
Activity.java
public class Activity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
// Can I subscribe here and do some logic for when globalResponse changes?!?
}
public void login() {
// create login request object
// ...
// call service method
LoginResponse response = service.loginMethod(request);
// Can I await the async in loginMethod so that I run logic after the call?
}
}
Service.java
public class Service implements ServiceInterface {
#Override
public loginMethod(LoginRequest request) {
// Setup Retrofit for api call
// ...
Call<LoginResponse> call = apiService.login(request);
// async call to get a response from the api for login
call.enqueue(new Callback<LoginResponse>() {
#Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
GlobalData.globalResponse = response.body(); // updates global data variable with the response from login
}
}
}
}
Check the next blogs to know how use Rx and retrofit together
Rxjava & Retrofit: http://www.baeldung.com/retrofit-rxjava
How subscribe an observable object: http://www.vogella.com/tutorials/RxJava/article.html#creating-observables-subscribing-to-them-and-disposing-them
I think with that you can continue with you login flow
public class Activity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
// Can I subscribe here and do some logic for when globalResponse changes?!?
Yes, but only if you use a BehaviorSubject/BehaviorRelay (I vote Relay, see BehaviorRelay).
So you have
public class GlobalData {
private GlobalData() {}
public static LoginResponse globalResponse;
}
But it should be something like
public class GlobalData {
private GlobalData() {}
public static BehaviorRelay<Optional<LoginResponse>> globalResponse = BehaviorRelay.createDefault(Optional.absent());
}
And
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
LoginResponse login = response.body();
if(login != null) {
GlobalData.globalResponse.accept(Optional.of(response.body());
}
}
Bonus points if you hide the Relay and expose a method that writes into it, and another that shows it as Observable<Optional<T>>.
Anyways now you can do
Disposable disposable = GlobalData.globalResponse.subscribe((opt) -> {
if(opt.isPresent()) {
LoginResponse data = opt.get();
// do whatever
}
});

Create generic requests class

I want to make a generic requests class for android
public class Requests {
protected JSONObject postRequest(URL url, Map data) {
return null;
}
protected JSONObject getRequest(URL url) {
return null;
}
}
I know that if I want to do a request I must do a background task (Thread or AsyncTask),
but It´s posible to make a asynctask in both methods?, should I use Threads?, a better idea?
Thanks!

DRY: a case with AsyncTasks

I'm developing an Android app which has a lot of different requests for web services.
Every request is done in a subclass of AsyncTask in this manner:
(new AsyncTask<String, Void, Object1>() {
#Override
protected Object1 doInBackground(String... params) {
// network request and parsing to Object1
Object1 obj = new Object1();
obj1 = Parser.parseObject1(httpClient.execute(...));
return obj1;
}
#Override
protected Object1 onPostExecute(Object1... ret) {
return ret[0];
}
}).execute();
Object1 is a placeholder for different objects (Car, Bicycle, Truck...), each one in a different AsyncTask.
What are my alternatives other than returning the output of httpClient in a String and parsing in the Main Thread (UI Thread)? Avoid parsing in the UI Thread sounds reasonable if it's going to parse a lot of data, am I right?
-= UPDATE =-
Let me rephrase the question: I'm asking for a more intelligent way to develop my application avoiding being repetitive (AsyncTask has a lot of boilerplate code). The way I did was by creating 20+ subclasses of AsyncTask, which clearly is not DRY (do not repeat yourself).
In iOS we have lambda expressions so callbacks done in web requests are very easy and succinct.
You can create classes that contain most of your boilerplate code. E.g.
public class SpecialAsyncTask<T> extends AsyncTask<String, Void, T> {
public interface ResultProvider<T> {
T generateResultInBackground(String... params);
}
public interface ResultConsumer<T> {
void handleResultInForeground(T result);
}
private final ResultProvider<T> mProvider;
private final ResultConsumer<T> mConsumer;
private SpecialAsyncTask(ResultProvider<T> provider, ResultConsumer<T> consumer) {
mProvider = provider;
mConsumer = consumer;
}
#Override
protected T doInBackground(String... params) {
return mProvider.generateResultInBackground(params);
}
#Override
protected void onPostExecute(T result) {
mConsumer.handleResultInForeground(result);
}
public static <T> void execute(ResultProvider<T> provider, ResultConsumer<T> consumer, String... params) {
new SpecialAsyncTask<T>(provider, consumer).execute(params);
}
}
is an example how you could keep Object1 as a generic parameter while being able to specify an object that only needs to implement an interface to handle code that would otherwise have to be inside a new AsyncTask instance.
With a schema like that you could for example define some common code as static content:
class Providers {
public static final ResultProvider<String> HTTP_GETTER = new ResultProvider<String>() {
#Override
public String generateResultInBackground(String... params) {
return MagicHttpLibrary.getContentAsString(params[0]);
}
};
}
And you can just use Providers.HTTP_GETTER as parameter instead of implementing doInBackground. Or create a new class hierarchy of that implement one of those interfaces with different methods to access them (like factories for example)
Use of above example would look for example like below
class User extends Activity implements ResultConsumer<String> {
#Override
protected void onCreate(Bundle savedInstanceState) {
SpecialAsyncTask.execute(Providers.HTTP_GETTER, this , "http://google.com");
SpecialAsyncTask.execute(Providers.HTTP_GETTER, this , "http://yahoo.com");
}
#Override
public void handleResultInForeground(String result) {
Toast.makeText(this, result, Toast.LENGTH_LONG).show();
}
}
and there is more or less no repeated code besides the different method calls. It depends on how you want to use a class and what actually changes in the code to know how to design something like that. Identify the parts that need to be parametrized and move code that repeats into a re-used place (inheritance / composition).
Google's Volley HTTP request library does the request and parsing both in the same worker thread. So, that's a pretty good example to code by.

Get a variable from an anonymous class

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).

Mocking inside a Java class

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.

Categories