I am using google Firebase database in android. I need two fetch two set of data from database - userInfo and assignmentInfo. Then I need to combine them and show the data in a recycler view. What is the best way to approach this? As the fetching of data is async, this is getting messy.
One way i can think of is, check in both async functions success if other has completed. If so, get its data, combine and initialize the adapter. Is this the best way do this?
I have solved this kind of problem when i had to download something from a database before login in the user into the app, with this i fixed this problem.
To use ObservableInteger you can do this
first declare it
private ObservableInteger mObsInt;
then in your onCreate you will have a listener waiting for the values of the mObsInt to change, after those values change you can do anything you want
//Listener
mObsInt = new ObservableInteger();
mObsInt.set(0);
mObsInt.setOnIntegerChangeListener(new OnIntegerChangeListener()
{
#Override
public void onIntegerChanged(int newValue)
{
if (mObsInt.get()==1)
//Do something if the first asyncTask finishes
if (mObsInt.get()==2){
//Do something if the second asyncTask finishes, in this case i just go to another activity when both asyncTasks finish
Intent mainIntent = new Intent().setClass(LoginActivity.this, Principal.class);
startActivity(mainIntent);
finish();
}
}
});
So, how it works
ObservableInteger will be looking for changes in the variable mObsInt, so lets say if mObsInt is equal to 1 it will do something, if is equal to 2 will do another thing, so, to solve this problem with 2 asynctasks is easy, when one of the asynctasks finishes mObsInt will be equal to 1 , if the other asyncTask finishes so mObsInt will be mObsInt++ , and then your mObsInt will be equal to 2, the listener will be waiting for the values, and then do what you want to do when the values match your if statment at the onCreate method
now, just in your asynctasks just put in your onPostExecute() method this line
mObsInt.set(mObsInt.get()+1);
so if the first async finish, mObsint == 1 , if the second finish mObsInt == 2, and then you handle what you want to do in your onCreate method
hope this helps for you, it helped me
You can get more info at this doc : https://developer.android.com/reference/android/databinding/ObservableInt.html
happy coding !
This can be achieved using a simple variable which will be incremented or will be keeping a flag if the both data is available to be merged and returned successfully from Firebase. However, this is neither the best approach and nor will work all the time as it can fail if the both async thread tries to update the flag at the same time. Then with the implementation given above, will work only if you can make the whole operation thread-safe.
If you consider building a thread-safe implementation on your own, that is not so difficult either. You might just consider using a Synchronized function which will update the flag you are keeping to detect if the both data from firebase is fetched.
However, I would suggest to get your implementation done using a LocalBroadcastReceiver. Which is easier to implement and this is an Android solution. Though there might be a several other approaches which are great as well, I think the implementation with BroadcastReceiver will serve your purpose fully.
You can check this answer for checking the implementation of a BroadcastReceiver. When the first part of the data is fetched from firebase, send the broadcast to be received by the BroadcastReceiver in your Activity and set a flag value for example, 1. Then when the second part is received, you will have to set the value to 2 again by just sending the broadcast on getting response from firebase. And then, when the value is found 2, that means the both operations has completed and now you can merge the two lists.
To avoid the overall thread-safe and fail safety coding overhead, you might consider fetching the data from firebase, synchronously. On getting the data for the first part, initiate the fetch operation for the second part for better control over your code.
I have just put some ideas, pick any that suits you. Hope that helps!
The simplest way I use in projects w/o Rx/Coroutines/other stuff. Just create AtomicInteger. Init it with value equals number of async operations. Then in each callback of your async functions call this:
if(counter.decrementAndGet == 0) { your_final_action}.
If you need some help with other ways like I mentioned before, feel free to ask me.
Related
This is a general question regarding android development and the use of co-routines. I am relatively new to developing in android and have created an application using the MVVM architecture model.
I am currently having a problem where I insert into a table and retrieve an ID back in an observer with LiveData.
I then need to use this ID immediately to insert into another table to act as a foreign key.
One table defines the entry and the other the fields associated to that entry.
My issue is that the insertion of the initial ID is happening in the background, so by the time the ID is returned to the activity an error has already been thrown up.
I need some way of:
either waiting for the ID to be returned
or have the insertion run in the foreground (but am unsure how to do
this).
I have seen one solution is to use co-routines but this seems to just be a Kotlin solution.
Does anyone know of a solution that would work in android java to immediately retrieve the ID of insertion in the activity to use for the next insert?
*I am using a room SQL Database.
Ok, correct me if I'm wrong, but what I think you want is a way to chain asynchronous operations together in a synchronous way.
So you have one operation which needs to insert into a table asynchronously, and another operation which needs to use the id from the result of the first operation to insert into another table.
So your second operation requires the first operation to have finished before it runs. But your first operation is running in the background so the question arises; "How do I make sure not to fire the second operation until the first one has finished?".
This is the concept of "chaining" asynchronous calls. Or, in other words, performing asynchronous calls in a synchronous fashion.
Because you need to use Java you won't be able to use Kotlin coroutines (because that's a Kotlin language feature). Fortunately, there are several methods for achieving this in Java.
I personally would recommend the use of RX Java. There are loads of operators for combining asynchronous operations. The one you'd probably want for this use case is called flatMap, which is an operator which blocks on the first operations result before invoking the second operation, with the results of the first one as argument(s).
However, RX is quite a big dependency to add and also has quite a learning curve. So, choosing to use this tool will depend on how prevelant this kind of problem is in your code base.
Another option, is to set up a shared single thread executor which would be used to issue both operations on the same background thread. Because it is a single background thread, as long as you issue the commands into the executor sequentially, they will execute sequentially, but on a background thread. So, assuming your Room DB functions are blocking (i.e. when you issue them, the current thread waits for the operation to complete) then you can have a chained operation like so:
// Create a shared single threaded executor to run both operations on the same background thread
private Executor sharedSingleThreadExecutor = Executors.newSingleThreadExecutor();
private void doThingAThenThingB() {
// Sequentially call thing A on shared background thread
sharedSingleThreadExecutor.execute(() -> {
// Do thing A
doThingA();
});
// Sequentially call thing B on shared background thread
sharedSingleThreadExecutor.execute(() -> {
// Do thing b
doThingB();
});
}
I tried to find an answer online for it, but I couldn't find one which is specific for Firebase implementations.
I can choose between OnCompleteListener and OnSuccessListener for a lot of operations in Firebase, and I'd like to know how can I choose between them?.
I have read the documentation for OnComplete and OnSuccess, but as I can see from Firebase documentations, this one for example, for one specific operation (like get operation in the example), they sometimes use OnSuccessListener and sometimes they use OnCompleteListener.
How can I know which one is better in every situation?
Does it matter? Considering that I'd like to know for every operation if it was succussful or not.
As the name suggests, onSuccess() will fire when a task is completed successfully.
onComplete() will fire when the task is completed, even if it failed.
In the method, you can call Task.isSuccessful() and Task.getException().
In onSuccess() you can be certain that isSuccessful() will return true, and getException() will return null (so there's not much point calling them).
In onComplete() isSuccessful() may be false, and you have the opportunity to deal with the failure, perhaps using getException() to obtain more detail.
If you need to handle failed tasks (and you should!), you have two choices:
Use and OnCompleteListener, and if(task.isSuccessful()) { ... } else {...} -- this puts the success and failure code close together, and may be useful if those routines share state.
Use separate OnSuccessListener and OnFailureListener -- this allows you to write listeners with a bit more cohesion, in that each handler specialises in one thing. Of course, one class may implement both interfaces, giving you another way to have both see the same state.
To add to what slim answered above in my use of Firebase.
I find out that this two listeners (OnCompleteListener and OnSuccessListener)
Have different callback times in writing data to their servers.
The general rule of thumb
If you're relying on a systematic(sequential) way of writing to the servers in order to
perform some logic then use OnCompleteListener
If you're not dependent on a systematic(non-sequential i.e async tasks) way of writing to the servers in order to
perform some logic then use OnSuccessListener
Sometimes you may find that you need to use value of the result say for example getting device token.. only the onSuccess will give InstanceIdResult and not onComplete... so therefore you must use onSuccess...
// Get The Device Token And Put It Into Firebase Instance
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
#Override
public void onSuccess(InstanceIdResult instanceIdResult) {
String DeviceToken = instanceIdResult.getToken();
}
});
I've been trying to find out how to do it, maybe using an IntentService, but I'm not sure that's the correct way for what I want to do.
Can someone at least point me in the right way?
To do stuff in background you can use Service, AsyncTask or simply a Thread.
To do work in a loop, you can use Timer, AlarmManager and ScheduledExecutorService, while the most common one will be Handler.
Each one of the above got its own advantages and disadvantages. Read more about them to find what you need.
I've got two separate methods that will return with some data asynchronously, however I want to them collate that information and send it elsewhere as one call.
The way I see it, I could either:
Make the method that submits the data after its recieved wait until it has recieved both sets of information or, quit after x amount of time if it has been waiting.
OR
Make a the methods that receive data call the submit method, if the other data has been received.
Obviously depends upon implementation, but neither of these feel like brilliant solutions.
Make the method that submits the data after its recieved wait until it has recieved both sets of information
If this method is on the main thread then don't do this unless absolutely necessary. In which case, you want to show some progress dialog.
quit after x amount of time if it has been waiting.
Mostly likely you don't want to do this. It stinks of bad design.
Make a the methods that receive data call the submit method, if the other data has been received.
This you could do and set some flag to know that one is done. What you might want is an interface. If you are using an AsyncTask for your asynchronous work then this answer can help with that
I need to count the number of times the user launches an app. I'm storing the value in a shared preference, and putting the count logic inside onCreate().
Now, since onCreate() is called in a number of different scenarios, not all of which include the user actually launching the application, I'm using the saved instance state bundle to store a flag set in OnSaveInstanceState() -- if the flag is absent, I consider the user started the app manually.
Is this necessary, or is just checking for a null bundle passed to onCreate() enough? In either case, why?
You could call getCategories() on the intent to see if it includes the LAUNCHER catagory.
You could think about this another way... increment the counter every time onDestroy() is called. This way you would be guaranteed that the program is actually out of memory, and the counter will only ever be off by 1 at most.
Just throwing an idea out there, hope it gives you some more of your own!
A null check in onCreate() should work just fine. No need to set a separate flag in onSaveInstanceState(). There is one possible issue though.
Say the user put your application in background (by pressing home key). The application process will eventually get killed. When the user restarts the application, you will receive a proper Bundle object in onCreate() with the flag set. The user can prevent your counter from being incremented by simply backgrounding your application everytime.
If backgrounding could be an issue, you might try something like:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if (getLastNonConfigurationInstance() == null) {
counter++;
}
}
public Object onRetainNonConfigurationInstance() {
return new Object();
}
I have used the above code before and it works on Eclair, FroYo and Gingerbread. It seems getLastNonConfigurationInstance() and onRetainNonConfigurationInstance() have been marked deprecated in Honeycomb, so I am not sure how it will work in case you are targeting Honeycomb.
Inside the onCreate method, include a check to Activity#getCallingActivity. It returns null if the app was not started from another activity.
First off, thank you all for your answers. They all helped some way or another.
That said, after several tries and different approaches, I think there is no actual 100% reliable way of determining when the user has launched the app. None of the activity life-cycle callbacks can really be used tackle the issue, neither individually nor combined.
The closest I got was counting the number of onResume() calls, and then substracting from it in onPause() depending on the return of isFinishing(). This approach, however, doesn't account for the home button, among maybe other things a user can do to hide apps.
I will update this answer if I ever find a way to do this reliably.