Return Multiple Data from AsyncTask - java

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

Related

How to read data and listen to changes from Room database in a Service?

i am storing user information in a local room database. In activities and fragments I use AndroidViewModel and LiveData to listen to changes made to the database and update the UI.
Now I want to analyze all of the past user data to give recommendations for future decisions. My recommendations change on every change to the database made by the user so I need to update my reommendations frequently while doing the same calculations over and over again.
I was thinking about starting a service on app start that listens to database changes via ViewModel and LiveData and updates my recommendations (which are also stored in the same database). But somehow a Service cannot
get a ViewModel via viewModel = ViewModelProviders.of(this).get(DataViewModel.class);
observe a LiveData object as it is not a LifecycleOwner.
Basically I simply need to read all entries from the database, analyze the data and update 5-10 values every time the database content changes.
How and where should I do my calculations if not in a service? Maybe I am trapped in a wrong thought and a service is not the right way to do it so any idea on how to do this is very much appreciated!
observe a LiveData object as it is not a LifecycleOwner
Use observeForever() on the LiveData, manually unregistering via removeObserver() when appropriate (onDestroy() of the service, if not sooner).
Bear in mind that standard service limitations apply here (e.g., services run for ~1 minute on Android 8.0+ unless they are foreground services), so it may be that you need to consider other approaches anyway.
I ended up using a Service and solved my problem as follows:
In the onCreate method of my Application object I bind MyService to it:
serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder iBinder) {
service = ((MyService.MyLocalBinder) iBinder ).getService();
}
#Override
public void onServiceDisconnected(ComponentName name) {
}
};
Intent intent = new Intent(this, MyService.class);
getApplicationContext().bindService(intent, serviceConnection, BIND_AUTO_CREATE);
Binding a Service to the application context should keep the Service alive as long as the application is not destroyed. In MyService I get an instance of ViewModel via AndroidViewModelFactory like this
MyViewModel myViewModel = ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()).create(MyViewModel.class);
and I am able to observe the fetched LiveData from the ViewModel via observeForever like this
Observer<List<Entry>> obsEntries = new Observer<List<Entry>>() {
#Override
public void onChanged(#Nullable List<Entry> entries) {
//perform calculations with entries in here
}
};
viewModel.getEntries().observeForever(obsEntries);
Important: Remove the observer from the LiveData reference in onDestroy of the Service (that is why I keep a local reference to the Observer object):
#Override
public void onDestroy() {
super.onDestroy();
viewModel.getEntries().removeObserver(obsEntries);
}
Thanks everybody!
Nothing to change in Entity.
In DAO, say for e.g.,
#Dao
public interface TimeDao {
// ...
// ...
// for a started Service using startService() in background
#Query("select * from times where name = :bName")
List<TimeEntity> getServiceTimes(String bName);
}
which is not a LiveData
In Database, for e.g.,
#Database(entities = {DataEntity.class, TimeEntity.class}, version = 1)
public abstract class BrRoomDatabase extends RoomDatabase {
public abstract TimeDao iTimeDao();
public static BrRoomDatabase getDatabase(final Context context) {
if (INSTANCE == null) {
// ...
}
return INSTANCE;
}
}
An interface class
public interface SyncServiceSupport {
List<TimeEntity> getTimesEntities(String brName);
}
An implementation class for it.
public class SyncServiceSupportImpl implements SyncServiceSupport {
private TimeDao timeDao;
public SyncServiceSupportImpl(Context context) {
timeDao = BrRoomDatabase.getDatabase(context).iTimeDao();
// getDatabase() from where we get DB instance.
// .. and ..
// public abstract TimeDao iTimeDao(); <= defined abstract type in RoomDatabase abstract class
}
#Override
public List<TimeEntity> getTimesEntities(String name) {
return timeDao.getServiceTimes(name);
}
}
And finally... in the service..
public class SyncService extends Service {
//..
// now, iEntities will have a List of TimeEntity objects from DB ..
// .. retrieved using #Query
private static List<TimeEntity> iEntities = new ArrayList<>();
private static SyncServiceSupportImpl iSyncService;
private static void getFromDB(String brName) {
new AsyncTask<String, Void, Void>() {
#Override
protected Void doInBackground(String... params) {
iEntities = iSyncService.getTimesEntities(params[0]);
return null;
}
#Override
protected void onPostExecute(Void agentsCount) {
}
}.execute(brName);
}
#Override
public void onCreate() {
super.onCreate();
//init service
iSyncService = new SyncServiceSupportImpl(SyncService.this);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// this can be elsewhere also !..
getFromDB(myName);
}
}

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 do I pass a class (not a class instance) to a method?

I have the following code that I want to generify:
// retrieve json data from server and display the data on a card with two lines
private void DisplayClassData(int count, final ArrayList<TwoLineSummaryCardDataObject> tlscdo,
final TwoLineSummaryViewAdapter tlsva) {
final String url = "https://jsaonurl.com/jsondata";
// want to generify this so that I can pass any class. But not just *any* class. Just some of my
// classes that I have set up.
final GsonRequest gsonRequest = new GsonRequest(url, Myclass1.class, null, new Response.Listener<Myclass1>() {
#Override
public void onResponse(Myclass1 myclass1) { // again, this refers back to the line above
tlscdo.clear();
Realm realm = Realm.getInstance(act);
realm.beginTransaction();
// all of my classes will have a getElement() method which will return a list
// of objects. Perhaps I need to make a prototype and use implements???
for (int i = 0; i < myclass1.getElement().size(); i++) {
tlscdo.add(new TwoLineSummaryCardDataObject(myclass1.getElement().get(i)));
realm.copyToRealmOrUpdate(myclass1.getElement().get(i));
}
realm.commitTransaction();
tlsva.notifyDataSetChanged();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
if(volleyError != null) Log.e("MainActivity", volleyError.getMessage());
Toast.makeText(MainActivity.this, "Error in Volley", Toast.LENGTH_SHORT).show();
}
}
);
// Add the request to the queue
Volley.newRequestQueue(this).add(gsonRequest);
VolleyHelper.getInstance(getApplicationContext()).addToRequestQueue(gsonRequest);
}
In my data structure, I have seven classes that are all set up the same. How can I set it up so that I can reuse the code and pass any of the classes to it?
I think you probably want to make a factory class of some kind that you could invoke myFactory.getAllElements(Class<? extends MyBaseClass> clazz) on - assuming you have a MyBaseClass that MyClass1 etc extend.
If you want to pass a class, then, well, pass a Class. Java Class<T> object, that is.
You would need to use the superclass or an interface of your view adapters, and change your method signature as follows:
private <T> void DisplayClassData(
int count
, final ArrayList<T> data
, final BaseViewAdapter va
, Class<T> itemClass
)
Use itemClass to create new instances of the class. Use base view adapter to send notifications as needed. Use itemClass in place of Myclass1.class.
The caller would then call
DisplayClassData(tlsCount, tlscdo, tlsva, TwoLineSummaryCardDataObject.class);
DisplayClassData(esCount, escdo, esva, ExpandedSummaryCardDataObject.class);
... // And so on
You can implement a custom request. Extend the Request<T> class, where <T> represents the type of parsed response.
In the parseNetworkResponse method you can instance one of the seven classes. T should be the parent class of all your seven classes.

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.

How to return List of Object from server in GWT

I am using the tutorial explaining the usage of asyncdataprovider to create the celltable http://www.mytechtip.com/2010/11/gwt-celltable-example-using_8168.html. Tutorial mentioned that you can return the list of object from the server.
// Associate an async data provider to the table
AsyncDataProvider<Contact> provider = new AsyncDataProvider<Contact>() {
#Override
protected void onRangeChanged(HasData<Contact> display) {
final int start = display.getVisibleRange().getStart();
int length = display.getVisibleRange().getLength();
AsyncCallback<List<Contact>> callback = new AsyncCallback<List<Contact>>() {
#Override
public void onFailure(Throwable caught) {
Window.alert(caught.getMessage());
}
#Override
public void onSuccess(List<Contact> result) {
updateRowData(start, result);
}
};
// The remote service that should be implemented
remoteService.fetchPage(start, length, callback);
}
};
Could someone please tell me how can I return a list of object from the server.
I thinkt this tutorial will help you:
http://www.tutorialspoint.com/gwt/gwt_rpc_communication.htm
Another good place to look for information is:
http://www.gwtproject.org/doc/latest/tutorial/RPC.html
Please don't forget you only can pass serializable objects through RPC. So you can't use List types or you should serialize it.

Categories