Counting how many times my Android app has been opened - java

I am developing an android app and I want to know how many times it has been opened. Is there a way to do this?

The problem with using onCreate in an Activity is that this will increment the counter even on orientation changes. Using onCreate in an Application also has a downside in that your counter will only be incremented when after the VM has closed - so even if the app exits and reopens this will not necessarily increment.
The truth is there is no fool-proof method for handling this sort of count, however I have come up with a very good way of doing this, that is about as close to 100% accurate as possible. It requires work in both an Application class and your main Activity class, and relies on timestamps to differentiate between orientation changes and actual app launches. To start, add the following Application class:
/**
* Application class used for correctly counting the number of times an app has been opened.
* #author Phil Brown
* #see Stack Overflow
*
*/
public class CounterApplication extends Application
{
private long lastConfigChange;
/** #param buffer the number of milliseconds required after an orientation change to still be considered the same event*/
public boolean wasLastConfigChangeRecent(int buffer)
{
return (new Date().getTime() - lastConfigChange <= buffer);
}
#Override
public void onCreate()
{
lastConfigChange = new Date().getTime();
}
#Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
lastConfigChange = new Date().getTime();
}
}
You should add this Application to your AndroidManifest.xml by specifying the name application attribute:
android:name="path.to.CounterApplication"
Now, in your main Activity, add the following in onCreate:
//note that you can use getPreferences(MODE_PRIVATE), but this is easier to use from Fragments.
SharedPreferences prefs = getSharedPreferences(getPackageName(), MODE_PRIVATE);
int appOpenedCount = prefs.getInt("app_opened_count", 1);
if (!((CounterApplication) getApplication()).wasLastConfigChangeRecent(10000))//within 10 seconds - a huge buffer
{
appOpenedCount += 1;
prefs.edit().putInt("app_opened_count", appOpenedCount).commit();
}
//now say you want to do something every 10th time they open the app:
boolean shouldDoThing = (appOpenedCount % 10 == 0);
if (shouldDoThing)
{
doThing();
appOpenedCount += 1;
//this ensures that the thing does not happen again on an orientation change.
prefs.edit().putInt("app_opened_count", appOpenedCount).commit();
}

Just, declare:
private SharedPreferences prefs;
private SharedPreferences.Editor editor;
private int totalCount;
Initialize in onCreate(...) :
prefs = getPreferences(Context.MODE_PRIVATE);
editor = prefs.edit();
Print or count wherever you want (any where in onCreate or any specific click as you specified)
totalCount = prefs.getInt("counter", 0);
totalCount++;
editor.putInt("counter", totalCount);
editor.commit();
Now print totalcount where you want to count eg.:
System.out.println("Total Application counter Reach to :"+totalCount);

In your Application or Activity's onCreate() method, increment a counter stored in persistent storage such as SharedPreferences.

You can use shared preferences. Every time the app is opened, retrieve the preferences, increment the count, then store it right away. The only issue is that if a user deletes the app along with all preferences, then the count will be erased too. Here is an example of committing to the preferences. Use getPreferences to retrieve them at the startup of the app.
SharedPreferences prefs=getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor=prefs.edit();
editor.putString("pref 1", "some text");
editor.commit();

1. For a simple approach, keep a text file where you increment the value by 1, after reading it. Keep the count increment on OnCreate() method of Activity
2. You can use SharedPreference.
3. Well DataBase can also be used...but i think that too over-kill for this....

One way:
Keep a property in preferences and on launching activity update preference count by '1', but you may not be able to see this increased value because it stays on phone.
Otherway
Call a service to your server (if you have any) to increment the visit count.

Using SharedPreference or the Database.
during OnCreate add 1 to the numberofTimes counter and commit.
OnCreate (Bundle bundle){
mPref = getPreferences();
int c = mPref.getInt("numRun",0);
c++;
mPref.edit().putInt("numRun",c).commit();
//do other stuff...
}
OnCreate is called regardless of you start the app or you resume the app, but isFinishing() returns true if and only iff the user (or you) called finish() on the app (and it was not being destroyed by the manager)
This way you only increment when you are doing fresh start.
the onFinishing() Method inside of a OnPause method to check to see if the activity is being finish() or just being paused.
#Override
protected void OnPause(){
if(!onFinishing()){
c = mPref.getInt("numRun",0);
c--;
mPref.edit().putInt("numRun",c).commit();
}
//Other pause stuff.
}

As I have said in another answer, I think the following is the best solution:
private static boolean valueOfLaunchCountModified = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
if(!valueOfCountModified){
preferences = getPreferences(MODE_PRIVATE);
launchCount= preferences.getInt("launchCount", 0);
if(preferences.edit().putInt("launchCount", ++launchCount).commit()){
valueOfCountModified = true;
}
}
if(launchCount == 5 && valueOfCountModified){
//Do whatever you want
}
}
If we remember the definition of a static variable, we will discover that is perfect for us:
They are associated with the class, rather than with any object. Every instance of the class shares a class variable.
When onPause method or an orientation change is executed the value of valueOfLaunchCountModified doesn't change; however, if the app process is destroyed, the value of valueOfLaunchCountModified changes to false.

Related

Java Android Badge Drawable not working properly after configuration change

I have a Bottom Navigation view with a badge drawable that shows new chats.
This badges are updated upon a listener to Firebase database, where I store the notification counter. When this value change, the badge is updated. Moreover if the counter is equal to zero, the badge is set not visible.
Everything works fine except if I change some configuration using the device Settings (such as language or removing permissions). In fact, if I do that and go back to the app, the activity is re-created (sometimes without destroying it) and badge reloaded. But the setVisibility seems not working. Even if the counter is zero the badge is visible. Plus is not update anymore when the listener is triggered.
The code works, I checked with some logs if the listener is triggered and if the lines which include setVisibility are run. It just seems to have random behaviour.
If the activity is destroyed and recreated again, it works.
Any help will be appreciated!
this is how I initialize the badge
bottomNav = findViewById(R.id.bottom_navigation);
badge_chat = bottomNav.getOrCreateBadge(R.id.nav_chat);
badge_chat.setVisible(false);
this is the listener code
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
int badge_counter = dataSnapshot.getValue(int.class);
boolean visibility;
if (badge_counter == 0) {
visibility = false;
} else {
visibility = true;
}
badge_chat.setNumber(badge_counter);
badge_chat.setVisible(visibility);
}
One way I've managed to resolve this is to create/remove badge whenever it needs to be visible/hidden. In your case, something like this should work:
if (badge_counter == 0) {
getBadge(R.id.nav_chat)?.isVisible = false
removeBadge(R.id.nav_chat)
} else {
getOrCreateBadge(R.id.nav_chat).apply{
isVisible = true
number = badge_counter
}
}
note: the answer is in Kotlin.

*Novice trying to learn Quiz app* trouble storing and showing the score in another activity

Been searching the whole world wide web and haven't been able to find a solution to get this to work.
There is 15 questions in total.
Each question include an audio clip, and you get 4 buttons choices.
3 wrong choices which will give you + 0 score.
1 right choice which give you + 1 score.
after you finished all 15 questions you can click "Show score"
And here I want to make a TextView which shows you how many questions out of 15 you got right.
It sounds pretty simple to make this to work,
But I've tried multiple codes with SharedPreferences, Editors, Arrays etc...
First sample code is from pressing the right answer on the first question.
Second sample code is for the show score after finishing the quiz.
final Button answerC = (Button) findViewById(R.id.answerC);
answerC.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SharedPreferences prefs = getSharedPreferences("mresult", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putInt("result", + 1);
editor.apply();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_easy_result);
SharedPreferences prefs = getSharedPreferences("mResult", Context.MODE_PRIVATE);
int myResult = prefs.getInt("result", 0);
In order to send data from one Activity to another Activity you have a few options depending on your circumstances. Although, for my answer - I'm going to assume that it's easy for you to navigate to another activity at a moments notice.
With what you're doing, you must understand that data in activities are completely mutable and can be voided by androids garbage collection at any time - you must develop your applications with this in mind and not rely on data constantly being available within your classes.
With the little information you've provided it seems as if you have a main activity in which you're storing data about the user's score and you want to change the user's activity and display that on the other screen.
I would advise that you create a Score object of some sort and allow it to implement the interface Serializable
You can then simply write the following to start the other activity
Intent toShowScoreActivity = new Intent(currentActivity, ShowScoreActivity.class);
Bundle bundle = new Bundle();
Score score = new Score(1);
bundle.putSerializable("score", scoreSerialized);
toShowScoreActivity.putExtras(bundle);
activity.startActivity(toShowScoreActivity);
then, when the other activity is started, you can reference the Serialized Score object by doing the following:
Score score = (Score) getIntent().getExtras().getSerializable("score")
Here's the mock up, over simplified, Score.java
package Testing;
import java.io.Serializable;
public class Score implements Serializable {
private final int score;
public Score(int score) {
this.score = score;
}
public int getScore() {
return score;
}
}
I would definitely recommend reading up more about android's guide to app architecture and conventional management of the Activity life cycle over at the following links
- https://developer.android.com/jetpack/docs/guide
- https://developer.android.com/guide/components/activities/activity-lifecycle
- https://www.programcreek.com/java-api-examples/?class=android.app.Activity&method=getIntent

Garbage value getting produced in textView

I have two activities : lets say A and B
A has a button which opens B using intent concept.
Through B I am saving data in database using SQLite concept.
A is the main activity which has a textView which is showing some value !
code:
Using SharedPreferences to store int value and display in MainActivity A
c=sp.getInt(Salaryflag, 0);
str=Integer.toString(c);
tv.setText(str);
Now I am using some algorithm to calculate sum() in one row in the database a store its value in an int variable
Now in onResume I am using this concept to change the value of the A textView ! :
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
ItemsDataBase xyx=new ItemsDataBase(this);
xyx.open();
int lola;
lola=xyx.getSum();
xyx.close();
c=c-lola;
str=Integer.toString(c);
tv.setText(str);
}
Now what I want is that when I go back from second Acitvity B to A it should immediately show the changes.
But actually It is showing some garbage value and when I restart the app after closing then it shows the desired changes in the textView
How to remove this logical error ?
Garbage value:
After closing the app and reopening it:
You should write c=sp.getInt(Salaryflag, 0); in your on resume too as you are assigning c-lola to c.
When you are restarting the activity, line c=sp.getInt(Salaryflag, 0) is getting executed first so it displaying perfactly.
When you coming from B to A , the onResume() of A gets called so you have to initialize/assign variable c in onResume() as well.

SharedPreferences String Set data lost after app kill (android emulator)

I am running this on an emulator: 5554:Nexus_5_API_22_x86.
I am trying to learn SharedPreferences and have written a simple test program.
It contains two buttons: one adds a String + random # to a set which will be stored in SharedPreferences, and the other prints the contents of that set.
Whenever I press the square button on the bottom right hand of the screen and press 'x' to close the app window, then relaunch the app, the contents of the set are reset - in other words, printing the set yields nothing.
However, if I exit the app using only the back button, the contents remain - in other words, printing the set yields whatever was in it before.
Java:
...
public class MainActivity extends AppCompatActivity
{
final int PREF_MODE_PRIVATE = 0;
TextView output;
Set<String> testSet;
Random randomGenerator = new Random();
SharedPreferences data;
SharedPreferences.Editor dataEditor;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
output = (TextView) findViewById(R.id.textView); //getting the output textfield
data = getPreferences(PREF_MODE_PRIVATE);
//If first-time setup has not been completed, execute the following block
//I don't want the String Set to be reset to empty every time the app is launched
if(data.getBoolean("initialized", false) == false)
{
//Adding the empty set to storage
testSet = new HashSet<String>();
dataEditor = data.edit();
dataEditor.putStringSet("testSet", testSet); //Add the empty Set to storage
dataEditor.putBoolean("initialized", true); //Set initialized flag to true
dataEditor.apply();
}
}
public void printTestSet(View view)
{
output.setText(""); //Clears the text field
Set<String> toBePrinted = data.getStringSet("testSet", null); //Gets the String Set
//Prints content of the String Set
if(toBePrinted != null)
{
for(String word : toBePrinted)
{
output.append(word + '\n');
}
}
}
public void addToTestSet(View view)
{
//Generate a string followed by a random number and add it to the String Set
int randomInt = randomGenerator.nextInt(1000);
data.getStringSet("testSet", null).add("NEW STRING #" + randomInt);
}
}
The button that prints the String Set calls printTestSet and the one that adds a String to the Set calls addToTestSet.
Upon creation, the app uses a simple boolean to check if it has been initialized the for the first time. If not, it adds an empty String Set to storage and sets the boolean to true. If the boolean is already true (meaning it has already added the empty string set), that step is skipped.
You need to either commit your data either realtime (where you are doing apply) or in application life cycle handler onpause (when your app goes to background). Use option 1 when you have little data or 2 when you have large amount of data to commit.
It looks like you're not saving the shared preferences in addToTestSet.
When you do getStringSet and then add, you need to again save the string Set back into shared prefs like you do in your onCreate() using dataEditor.apply().
Or if you want to be a bit more efficient, you can save your stringSet in the activity's onPause() method to prevent constantly writing to SharedPrefs
When you hit back, your app process isn't being killed, which means when you open it up again the Android system is restoring whatever it can (what was written in textViews, checkboxes that were checked, etc. simple things like that). What you see in the box might not actually be getting populated by SharedPrefs.

Why wont my app save 2 values and then display them the next time the app is open?

I recently learnt about SharedPreferences and now I tried to put it in my code. I have 2 integer values called counter and counterPS. What I want to happen is that the app will save the values every 5 seconds and then when the app is completely closed and completely re opened (phone turned off and on again for example) I want the app to see if the values that were saved (if they even were) are bigger than 0, if so then set the current values to the old saved ones. However I set a number for the values inside the app and waited five seconds for it to save and when i restarted the app completely the values just came up as 0. Why is this and can someone tell me how to fix this?
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
SharedPreferences saving = getSharedPreferences("ShipData", Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = saving.edit();
int counter = saving.getInt("shipCounter", 0);
int counterPS = saving.getInt("shipCounterPS", 0);
if(mShip.getCounter() == 0) {
if (counter > 0) {
mShip.setCounter(counter);
mShip.setCounterPerSec(counterPS);
}
}
//Save values every 5 seconds Below
new TimerClass(5000, 1000)
{
public void OnFinish()
{
editor.putInt("ShipCounter", mShip.getCounter());
editor.putInt("ShipCounterPS", mShip.getCounterPerSec());
editor.commit();
this.start();
}
}.start();
}
How about using handler ( the android way) instead of timer class? does it suit in your case ?
For more info:
http://www.mopri.de/2010/timertask-bad-do-it-the-android-way-use-a-handler/
I am aware that the question was posted a while back. Just replying to it for similar future questions ... Thanks.

Categories

Resources