Android: count number of app launches - java

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.

Related

update UI after two async operations

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.

Calling finishAffinity() does not destroy android app or activity. Activity's data still persists even when app is restarted

This is a huge Android Programming issue/bug.
Calling finishAffinity() does not shut down my application.
This is evidenced from the fact that:
1. The Android Studio Debugger still says 'Application is running' even after the app disappears from the screen and I'm back to the phones home screen.
2. When 'restarting' the application the values of data members of the inital Activity remain the same as they were before the application supposedly 'shutdown'.
3. If I call System.exit(0) directly after finishAffinity() then the shutdown works properly and data members are reset to their initial default values.
There are even bigger implications to this problem! When I call finish() within ActivityA after starting another ActivityB, if I ever go back to ActivityA then the data members have not been reset to default are still the old values.
This is ALL confusing to me since I've come from C++ where when a class is destroyed then it is ACTUALLY destroyed and all memory associated with it is completely released.
Getting an activity to completely delete itself when switching to a new activity or trying to exit the application seems IMPOSSIBLE.
public class Startup extends AppCompatActivity
{
private static int iStarted = 0;
............
#Override
protected void onActivityResult(int request, int result, Intent data)
{
super.onActivityResult(request, result, data);
if (request == RESULT_EULA_RETURNED)
{
// shutdown
finishAffinity(); // iStarted remains = 1
return;
}
}
..........
#Override
protected void onResume()
{
super.onResume();
// perform startup
// even when restarted this remains = 1
if (iStarted == 0)
{
iStarted = 1; // this will stay = 1 until the application is manually killed via the CLOSE ALL method or via the debugger
}
}
}
finishAffinity() is not used to "shutdown an application". It is used to remove a number of Activitys belonging to a specific application from the current task (which may contain Activitys belonging to multiple applications).
Even if you finish all of the Activitys in your application, the OS process hosting your app does not automatically go away (as it does when you call System.exit()). Android will eventually kill your process when it gets around to it. You have no control over this (and that is intentional).
If you have a debugger attached to the process, this can also prevent the process being killed by Android, as the debugger keeps active objects in the process.
You talk about "data members" not being cleaned up, and you claim that this works differently in C++. Actually, that's not true. Your "data members" are declared static. They aren't instance variables, they are class variables. They exist only once (not in every instance of the class), they are created and initialized when the class is loaded, and they are never destroyed until the class is unloaded (which never happens on Android). C++ has exactly the same behaviour.
You might try using instance variables instead of class variables to solve your problem.
Android has no concept of "shut down my application". There is only the Android Activity life cycle. There is not a connection between the VM's object life cycle on the activity life cycle; Android is free to re-use your Activity object instance across on create / destroy boundaries. In short, you can't assume Android will ever construct a new Activity object to handle a life cycle event.
You'll need to manage your own state. For example, maybe you want to clear them in onCreate() so whenever you activity is re-created they are reset. Note that I don't presume to know what logic you want to apply to the problem, I'm just giving an example.

Start MainActivity when android kill my process

When my app is inactive for some time android kills its process, making all static variables null. destroying activities etc. I want my app to launch MainActivity(activity that is declared as launcher in manifest) instead of activity that was in foreground when my app got minimalized and later killed.
Thanks in advance
The right way to do this would be to store the data you need (that you are storing just on your static vars) on the database and use the memory just as cache.
The not so good hammer time way to do it... is simple. In each onCreate of the Activities that need that info, check if the info is null, and if it is, invoke finish() and startActivity with the one you want.
#override
protected void onCreate(){
super.onCreate();
...
if(Singleton.getInfo() == null){
this.finish();
startActivity(...)
}
}
Or u can go to MainActivity with intent`s if you need pass some information from that activity.
Yet another possibility : As described in Clearing the back stack you can add clearTaskOnLaunch="true" to the root activity :
If this attribute is set to "true" in the root activity of a task, the
stack is cleared down to the root activity whenever the user leaves
the task and returns to it. In other words, it's the opposite of
alwaysRetainTaskState. The user always returns to the task in its
initial state, even after a leaving the task for only a moment.

design patterns for persisting state on android app

For android I am trying persist state if onDestroy() is called. I'm wondering what are common design patterns used to do such a thing so that the actual app functionality is decoupled from the persistence functionality? For example, I have a for loop that iterates through all of the players in the game. This update happens at the end of each round in the game. Would it be possible that the app gets destroyed half way through the update? If that happened, what kind of logic would i need to include to remember which player was updated.
You have two main options for saving state. If you are concerned with instance variables, then override Activity.onSaveInstanceState The answer to this question provides a good sample of how to do this.
For persistent data, you can either store it in SharedPreferences, the SQLite database, or write it to a file. This article should help you get started: http://developer.android.com/reference/android/app/Activity.html#SavingPersistentState
Your app can be killed half way during the update if users switch to another app such as receiving a phone call.
Considering such cases, you may need to persist your state in onPause() instead of onDestroy() since onPause() is the last method which is guaranted to be called when your activity is killed by the system.
And in onPause(), you can start a background service to do the update which can give your process higher priority so that it's less likely to be killed by the system when you are doing the update.
See more details in the Activity lifecycle and the Process document.
Android is not very nice about killing apps. You may or may not get onPause or onDestory. You may or may not be able to receive a hook onShutdown of the VM. Basically your app can die at any time (low memory pressure), user kills it, or etc and you won't get any warning. Basically it is best practice to assume that you can die at ANY time and store or update critical state as soon as you get it.
Basically I would either make a SQLitedatabase or use shared preferences for this.

How can I do some cleanup right before an Android app is quitting?

Is there some sort of onTerminate() method where I can do some cleanup (I want to clear some SharedPreferences) when my Android app is terminating?
I have an Activity that is keeping a running average of a few numbers, that I'm storing in a SharedPreference. I want this average to last while the app is running (the user can move between different activities) so I can't clear it on onDestroy() for that particular activity. I need to be able to clear it once the app is about to quit.
How can I do this?
I've not tried this, but here's what I would do:
As Alex mentioned in the comment to original question, use a Service to share the app-wide state between Activities.
Whenever you move between Activities, bind to the service from the "new" activity, and unbind from the "old" one. Check this to understand how to coordinate activities.
If you follow this properly, you can ensure that at least one Activity is always bound to the Service as long as your app is running; and that all Activities are unbound when the app is no longer running - at which point your service's onDestroy() is called. This is where you perform your cleanup.
So android doesn't really have a concept of an app being "finished". Unfortunently there is nothing synonymous to "onTerminate()". Is there some criteria by which you can decide when to clear your running average?
Use SharedPreference.Editor to remove the preferences, and commit. Here's a link for you: http://developer.android.com/reference/android/content/SharedPreferences.Editor.html

Categories