DRY: a case with AsyncTasks - java

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.

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

How to create my own hot Observable from scratch?

How to create my own hot Observable from scratch?
I would like create my own function, returning observable, returning locations:
public static Observable<Location> locationObservable(Context context, String provider, long minTime, float minDistance) {
This is for Android. It is recommended to use Observable.create() for this purposes, but example shows just passing constant list of integers to each subscriber, which is not hot.
If I do something else here, for example, remember a list of subscribers, then how will I implement unsubscribing and many other features?
I.e. absolutely no idea is what to do inside Observable.OnSubscribe<Integer>() implementation?
Generally to create hot observable you use some kind of Subject: PublishSubject, BehaviorSubject, etc.
See examples for BehaviorSubject here.
class LocationService {
private Subject<Location> subject = BehaviorSubject.create();
Observable<Location> locationObservable(...) {
return subject;
}
void onNewLocationListener(Location newLocation) {
subject.onNext(newLocation);
}
}
It is not recommended to write your own, at least until you are proficient with the existing ones and need a peculiar caching/emission pattern not covered by the default 5 (Async, Behavior, Publish, Replay, Unicast).
I have a 3 part series on the subject (pun intended) if you really want to:
Part 1
Part 2
Part 3
Look at this wonderful example taken directly from Realm's RealmObservableFactory:
#Override
public Observable<Realm> from(Realm realm) {
final RealmConfiguration realmConfig = realm.getConfiguration();
return Observable.create(new Observable.OnSubscribe<Realm>() { // create new observable
#Override
public void call(final Subscriber<? super Realm> subscriber) { // this is executed on `subscribeOn(Scheduler)`
final Realm observableRealm = Realm.getInstance(realmConfig);
final RealmChangeListener<Realm> listener = new RealmChangeListener<Realm>() {
#Override
public void onChange(Realm realm) {
if (!subscriber.isUnsubscribed()) { // always check if subscriber is unsubscribed!
subscriber.onNext(observableRealm);
}
}
};
subscriber.add(Subscriptions.create(new Action0() { // add unsubscription first! thread specified by unsubscribeOn(Scheduler)
#Override
public void call() {
observableRealm.removeChangeListener(listener); // remove listener
observableRealm.close();
}
}));
observableRealm.addChangeListener(listener); // add listener
subscriber.onNext(observableRealm); // initial value
}
});
}
And read the comments, it's a pretty good example.

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!

Return Multiple Data from AsyncTask

I'm trying to organize my app code separating AsyncTask classes from Activity or Fragments.
Surfing this forum I've learned about the "interface and listener" solution:
Interface.java
public interface TaskCompleteListener<T> {
public void onTaskComplete(T result);
}
AsyncTask.java
[...]
#Override
protected void onPostExecute(String JSONResponse) {
// using Gson library I convert JSONResponse string to POJO objects...
listener.onTaskComplete(result);
}
Activity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// start AsyncTask...
}
// Inner class implementing interface
public class LoadTaskCompleteListener implements TaskCompleteListener<Object> {
#Override
public void onTaskComplete(Object result) {
updateUI(result);
}
}
public void updateUI(Object result) {
// here you can manage UI updating, using result object
}
}
UPDATE
DataHelper.java
public class DataHelper {
private AsyncTaskCompleteListener<Object> listener;
public DataHelper(AsyncTaskCompleteListener<Obejct> listener) {
this.listener = listener;
}
// Multiple AsyncTask are defined here...
}
Well, I like this pattern so much, but: what if inside activity (or fragment)
I have multiple requests, with different type of results (single object, array, list)
and different business logic for managing them?
I can't handle that using a single callback. Any ideas? Should I add multiple
callbacks inside the interface? I'm really stuck with this.
I've a single file called DataHelper with multiple AsyncTask inside (something like web getters).
Naturally I can give up with this approach if you suggest any other alternative.
Why not return an array of Objects as a result? Then if you have more than one object inside that array you'll know the order in which you put them so you can use more than one set of results at a time.
public interface TaskCompleteListener<T> {
public void onTaskComplete(T... results);
}
Note that a 'handler' can be used instead of an async task and that each handler may return its message to the message looper with the msg wrapping different data. Easy to handle many data types because its just a message component.
Sample here
See 'process_entity() ' where the messages containing result component are sent by sample code.
Note that the definition of onTaskComplete() accepts as argument a generic type, type T:
onTaskComplete(T result);
this means that you can pass in any object type, single object, array, list, etc.
Regarding on how to handle different results using a single callback, you can use a Bundle to put the result in, associated with a key, and then in updateUI() check for that key and take appropriate actions.
Something like this (pseudocode, not sure if it will compile):
#Override
protected void onPostExecute(String JSONResponse) {
Bundle bundle = new Bundle();
bundle.putString("key_json_response", result); //put the response in a Bundle
listener.onTaskComplete(bundle);
}
// .....
public void updateUI(Object result) {
Bundle bundle = (Bundle)result;
if(bundle.containsKey("key_json_response")){
String json = bundle.getString("key_json_response");
// process json
} else if(bundle.containsKey("key_another_response")){
// process another response
}
}

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

Categories