Is holding the data loaded in an AsyncTaskLoader a good idea? - android

I am making a simple application that will load some data and display it for editing.
The process could take some time so I decided to use a loader (instead of a service which I usually do) to load said data.
I am using an AsyncTaskLoader like this:
class DataLoader extends AsyncTaskLoader<LoadResult> {
}
where LoadResult is a custom class that looks something like this:
class LoadResult {
Exception error;
List<Entry> entries;
List<Option> options;
List<User> users;
}
I have been reading up on loaders and it seems that the recommended strategy is something along these lines for its implementation:
public class DataLoader extends AsyncTaskLoader<LoadResult> {
LoadResult _result;
boolean _changed = false;
public DataLoader(Context context) {
super(context);
}
#Override
protected void onStartLoading() {
if (_changed) {
_result = null;
forceLoad();
} else {
deliverResult(_result);
}
}
#Override
public LoadResult loadInBackground() {
//load stuff here
_result = ...
_changed = false;
return _result;
}
public void notify_data_changed() {
_changed = true;
}
}
Now this works ok, but I'm worried because the activity that receives the result also has a fragment attached that will contain the data once loaded, and thus if I follow the above mentioned strategy the data will be stored on multiple memory places
On the other hand, whenever OnCreate is called (due to configuration changes for example) if I don't follow the above strategy, the application will reload all data even though there is no updates to it.
What would be a good compromise so that I won't be reloading data all the time?
Is there a better way to do this?

Related

RXJava 2 /RxAndroid 2 vs Observable vs Listener to Observe from different classes

since i would like to start my new app with a clean base im looking for a good way sharing Informations around different classes. For an example i would like to subscribe to an interface which may be used/shared by different classes.
Example for the interface/Observable way:
class SingleTonHolder {
private static _instance = null; // and initalize it using a static method.
private List<MyListener> myListeners new ArrayList<>();
public SingleTonHolder getInstance(){ return _instance }
public void registerListener(MyListener listener) { myListeners.add(listener); }
public void removeListener(MyListener listener) { myListeners.remove(listener); }
public void doSomethingToTheListener(...) { for(MyListener l : myListeners) l.doSomethingToTheListener(..); }
}
ClassOne extends MyListener {
public void onCreate() {
SingleTonHolder.getInstance().registerListener(this);
}
public vond onDestroy() {
SingleTonHolder.getInstance().removeListener(this);
}
}
and another class to listen for changes.
ClassTwo {
MyListener listener = null;
public void onCreate() {
listener = new MyListener( () => { .... });
SingleTonHolder.getInstance().registerListener(listener);
}
public vond onDestroy() {
SingleTonHolder.getInstance().removeListener(listener);
}
}
This does work and looks like the default solution. Everytime another Object calls SingleTonHolder.doSomethingToTheListener() it notify all registered listeners for changes.
Since i would like to try the same solution using RxJava2 and RxAndroid2 which lacks documentation i have tried the following way doing it.
Class CallFactory{
public Obvservable<List<Data>> getDummyData() { return anDummyObservable; }
}
Then ive created a Singleton Class which has a function to modify/observ onec a client subscribes.
public Observable<List<Data>> getData() {
return CallFactory.with(context)
.getDummyData(...)
.map(modifyList -> { /** do some processing **/return modifyList;
})
}
which doesnt work as excepted since every time a client subscribes it "recall" it and the client keeps connected until onCompleted() is called.
My first try to share the informations to all subscribed clients ive created a PublishSubject in my Singleton Class.
private PublishSubject<List<Data>> sharedSubject = PublishSubject.create();
Now i let my clients subscribe to the subjects using a method like
public PublishSubject getSharedSubject() { return this.sharedSubject; }
If i would like to send a Message which should be received by all listening clients then i have created something like
public void setNewData(List<Data> data) {
sharedSubject.onNext(data);
}
I am pretty sure that is not the way it should be, but is rxjava designed to serve such a solution? If i want to share events different then onNext, onError, onComplete, do i need to wrap an Interface in the onNext?
The codes are not tested and just to show how i understood it. Any help would be appreciate.
Yes, RxJava used those 3 basic abstract callbacks onNext<T> onComplete() and onError().
But the important part that I believe you've missed is that, the Observer and Consumer are generic abstractions of an interface. Meaning you'll only have 3 callbacks, but you'll have 3 callbacks PER DATA TYPE.
The main idea on RxJava is to create the streams of data. Meaning you would have a PublishSubject<List<Data>>, a PublishSubject<Foo>, a PublishSubject<Bar>, etc, etc. And then use one of the two interfaces Observer<T> or Consumer<T>. There's no need to create another interface or wrap it in something else. Just use the ones supplied by RxJava and put all the information you need inside the data.
I hope it helps.
Example:
// first class
public static class Foo implements Consumer<Data> {
Disposable d;
public Foo() {
this.d = SingleTonClass.subject.subscribe(this);
}
#Override void accept(Data data) {
.. here the original data
}
}
// second class
public static class Bar implements Consumer<MappedData> {
Disposable d;
public Foo() {
this.d = SingleTonClass.subject
.map( some data transform )
.subscribe(this);
}
#Override void accept(MappedData data) {
.. here the data after the map
}
}
class SingleTonClass {
public static PublishSubject<Data> subject = PublishSubject.create();
// then feel free to fire events in the subject:
public static void onSomethingHappen(){
subject.onNext(new Data(1));
}
public static void onOtherThingHappen(){
subject.onNext(new Data(2));
}
}
all in all, I wouldn't wrap the Rx calls into other things, but simply use them directly where needed.

Mock callbacks and listener with Mockito

I'm trying to test one class which makes a method call and wait from response throug a listener.
These are the interfaces inside the interactor. When I call fetch, then one of the listener fuctions is called back.
interface Interactor {
void fetch(int offset, int size);
}
interface InteractorListener {
void onReady(List<Result> results);
void onError();
}
public class MyInteractor implements Interactor{
private ImageInteractorListener listener;
public MyInteractor() {}
public onAttach(ImageInteractorListener listener) {
this.listener = listener;
}
public void fetch(int offset, int size) {
// Make asyncrhonous task
// and manage the response in the next method
}
public void onAsyncroouTaskResponse() {
if (someChecks) {
listener.onReady(List<Result> results);
} else {
listener.onError();
}
}
}
public class MyClass implements ImageInteractorListener {
public MyClass() {
MyInteractor interactor = new Interactor();
interactor.onAttach(this);
interactor.fetch(1,1);
}
#Override
void onReady(List<Result> results) {
// doThings
}
#override
void onError() {
// doThings
}
}
This is how my classes are maked. I need to test MyClass, so I need to mock Interactor callback
I have tried different sollutions with different problems, so right now I don't have a final code or error. But no one works..
Thank you.
Assuming that you're testing MyClass you can just manually call your callback
// Test that errors are handled
// Given
Interactor interactor = mock(Interactor.class);
MyClass myClass = new MyClass(interactor);
// When
interactor.fetch(0, 0); // this call is optional, I just added it for clarity
myClass.onError();
// Then
// verify something
Dimitry's approach is good, I'd personally not call fetch, since your onAsyncroouTaskResponse() is public, I'd call that and then verify(yourmock).onError() or similar to make sure it was called.
Another approach I make sometimes, is create a "TestableSubject" that is just a class extends YourOriginalClass where you override certain methods and keep a count of the number of times it was called, or similar. Sometimes, due to the nature of some classes, you can't mock them all (final, abstract stuff, private, etc.).
If what you want (and perhaps should) test is that upon completion of your asynchronous task, your call back is called (regardless of the outcome), then I'd skip the fetch part, you can test that fetch fires the job in another test, but I think here you are more interested in the later part.

Retrieve data only once for two activities using Firebase

I'm new to Android development and currently (trying to) code an application for a school related project.
I have some data stored in a Firebase Database that I retrieve using the onChildEvent() method, and I want to use this data in two Activities, one is a GoogleMap and the other is a List. My problem is, even though I have no particular problem retrieving the data, it seems to me that doing it twice for the same data is not the right way of doing it, but i can't help to find the appropriate solution.
I thought about retrieving the data in one of the activities and passing it to the other using an intent, but since the two activities are not directly linked (no way and no reason of going from one to the other), I don't think this is a good idea.
PS: English isn't my native language, if anything isn't clear, just ask and I'll do my best to reformulate ;)
Like #Dima Rostopira says, you could implement a Singleton, which exists once over the course of an application.
Example with "Location" object:
final class LocationModel {
private Context mContext;
/** List of locations */
private ArrayList<Location> mLocations;
/** Static instance of LocationModel, accessible throughout the scope of the applicaton */
private static final LocationModel sLocationModel = new LocationModel();
private LocationModel() {}
/**
* Returns static instance of LocationModel
*/
public static LocationModel getLocationModel() {
return sLocationModel;
}
/**
* Sets context, allowed once during application
*/
public void setContext(Context context) {
if (mContext != null) {
throw new IllegalStateException("context has already been set");
}
mContext = context.getApplicationContext();
}
/**
* Asynchronously loads locations using callback. "forceReload" parameter can be
* set to true to force querying Firebase, even if data is already loaded.
*/
public void getLocations(OnLocationsLoadedCallback callback, boolean forceReload) {
if (mLocations != null && !forceReload) {
callback.onLocationsLoaded(mLocations);
}
// make a call to "callback.onLocationsLoaded()" with Locations when query is completed
}
/**
* Callback allowing callers to listen for load completion
*/
interface OnLocationsLoadedCallback {
void onLocationsLoaded(ArrayList<Locations> locations);
}
}
Usage inside of an Activity:
MainActivity implements OnLocationsLoadedCallback {
...
public void onCreate(Bundle savedInstanceState) {
...
LocationModel.getLocationModel().getLocations(this);
...
}
#Override
public void onLocationsLoaded(ArrayList<Locations> location) {
// Use loaded locations as needed
}

how to make sure that only one AsyncTask runs in the background

I have a class, DownloadAndSave that extends from AsyncTask. In its doInBackground method, it retrieves data from an http connection and saves the data using OrmLite, but also cleans the old entries from the database. So, something like this:
doInBackground()
{
clearDb();
dataList = fetchDataFromHttp();
saveToDb(dataList);
}
I frequently get a DB exception:
attempt to re-open an already-closed object:SQLiteDatabase
in the clearDb() and saveToDb() functions.
And this is bad since old data from the previous call of DownloadAndSave is mixed with the new data from DownloadAndSave.
In my opinion, I need to make sure that when I start a thread, all of the other treads from the DownloadAndSave class have finished, or in other words I need to run at most one instance of DownloadAndSave at a time. So the question is: how do I make sure that only one instance of DownloadAndSave will run in any point of time?
Option 1. Move above:
clearDb();
dataList = fetchDataFromHttp();
saveToDb(dataList);
in a separate class that synchronizes against the class object:
public class WorkerClass {
private WorkerListener workerListener;
public static interface WorkerListener {
public void publishWorkProgress(String data);
}
public WorkerClass(WorkerListener workerListener) {
this.workerListener = workerListener;
}
public void performWork() {
synchronized (WorkerClass.class) {
clearDb();
publish("Cleared DB");
dataList = fetchDataFromHttp();
publish("Got http data");
saveToDb(dataList);
publish("There! saved!");
}
}
private void publish(String message) {
if(workerListener != null) {
workerListener.publishWorkProgress(message);
}
}
}
While from your activity:
public class SampleActivity extends Activity {
public void doTheThing() {
new MyAsyncTask().execute();
}
private static class MyAsyncTask extends AsyncTask<Void, String, Void> implements WorkerListener {
#Override
protected Void doInBackground(Void... params) {
new WorkerClass(this).performWork();
return null;
}
#Override
public void publishWorkProgress(String data) {
publishProgress(data);
}
}
}
Option 2: Move above code to an IntentService:
public class WorkerIntentService extends IntentService {
public WorkerIntentService() {
super(null);
}
#Override
protected void onHandleIntent(Intent intent) {
clearDb();
dataList = fetchDataFromHttp();
saveToDb(dataList);
}
}
Using an IntentService guarantees that tasks are executed serially.
Since API version 11 (HONEYCOMB) of the Android API, an AsyncTask can be executed on a given Executor. You can use the default SerialExecutor to execute tasks sequentially.
If you use db operation in doInBackground, you should be locked db for one thread.
public void insertToDb(){
SQliteDatabase db;
...
db.beginTransaction();
...//operation
db.yieldIfContendedSafely();
db.setTransactionSuccessful();
db.endTransaction();
}
I believe that the issue you are facing is that you are starting the AsyncTask from an activity. Your activity is extending ORMLiteBaseActivity which opens the helper (and with that the database) onCreate and closes it onDestroy. When you exit the activity and the background task still hasn't finished then when trying to do write to the database you end up with a closed DB.
ORMLite handles synchronizations internally and i have never needed to do synchronized blocks with it. I use it in all my projects that require a database.
Also for the other answers, the error is a closed database and not concurrent write operations, so synchronization doesn't make sense.

Observer pattern - when to

We have been arguing back and forth at my work place about the use of the Observer pattern for one of the problems. I somehow smell "overuse" but am open to ideas. So the requirement is
We have a hierarchy of objects -> an order and multiple line items in the order. When the order is cancelled, all the line items need to cancelled.
To do this, we have created a OrderCancel class which is the Subject in the Observer pattern idiom and LineItemCancel class which is the Observer. We also have a OrderManager class with a cancelOrders(List orders) method which instantiates the OrderCancel and the corresponding LineItemCancel objects and then registers them all in the OrderCancel. The code is as follows.
public class OrderManager {
public void cancelOrders(List<Order> orders){
for(Order order :orders){
OrderCancel orderCancel = new OrderCancel(order);
Listener listener = new LineItemCancel(order);
orderCancel.addListeners(listener);
orderCancel.cancel();
}
}
}
public class OrderCancel implements Subject {
private List<Listener> listeners = new ArrayList<Listener>();
private Order order;
public OrderCancel(Order order) {
this.order = order;
}
#Override
public void addListeners(Listener listener) {
listeners.add(listener);
}
#Override
public void notifyListeners() {
for(Listener listener : listeners){
listener.update();
}
}
public void cancel() {
notifyListeners();
cancelOrder();
}
private void cancelOrder() {
}
}
public class LineItemCancel implements Listener {
private Order order;
public LineItemCancel(Order order) {
this.order = order;
}
#Override
public void update() {
cancelLineItem();
}
private void cancelLineItem() {
}
}
I am convinced this is improper usage. But I am not able to convince the designers of this class. I am trying to figure out myself if this is right as the designer is one of the architects at work.
Looking forward to hear your thoughts.
The Observer pattern is only useful when it reduces coupling. I don't see any reduction of coupling in this example so I would say it is overuse.
I agree w/ #Pace, definitely doesn't reduce coupling, definitely overuse. My question is that in your example, the simplest approach semas to be to have the Order cancel its own LineItems when you cancel it; is there a good reason not to do that for your app?

Resources