how to know when shared preference is done writing - android

I have two activities. Activity A has a button which starts activity B. When you hit the back button in activity B it restarts activity A. Also when the back button is hit it goes to the onStop method for activity B and in this point I update shared preferences for the user. Basically I'm storing player data on the shared preferences but the problem is when activity A is restarted I also load the same shared preferences but it doesn't show the updated data that I saved while activity B was stopped. I reload the app and it shows the up to date data. So it seems that while it is being saved while activity B is being stopped there isn't enough time for when it is loaded while activity A is being restarted. So how can I tell whether the shared preferences have finished being written to or not? Basically I want to load the shared preferences once I know for sure the shared preferences has been updated, is that possible?
I am using commit method:
#Override
protected void onStop()
{
Long dist = (long)treadmill_.Mod.distance_;
Long newdist = dist + PlayerInfoManager.getInstance().getDistanceTraveled();
PlayerInfoManager.getInstance().setDistanceTraveled(newdist);
float fastestSaved = PlayerInfoManager.getInstance().getFastestSpeedAcheived();
float fastestInSess = treadmill_.Mod.fastestSpeed;
if(fastestSaved<fastestInSess)
PlayerInfoManager.getInstance().setFastestSpeedAcheived(fastestInSess);
Long time = (long)treadmill_.Mod.time_;
Long newTime = time + PlayerInfoManager.getInstance().getTotalTimeRan();
PlayerInfoManager.getInstance().setTotalTimeRan(newTime);
Log.e("OnStop", "at Run, run, run");
super.onStop();
}
In PlayerInfoManager.getinstance().setDistanceTraveled(newdist):
public void setDistanceTraveled(Long distanceTraveled)
{
DistanceTraveled = distanceTraveled;
Editor edit = SP.edit();
edit.putLong("DistanceTraveled", distanceTraveled);
edit.commit();
}
SP is the sharedPreference instance:
private SharedPreferences SP;
For activity A when it restarts:
#Override
protected void onRestart() {
super.onRestart();
LoadStats();
Log.e("onrestart", " ");
}
public void LoadStats()
{
PIM.loadAll();
Dis.setText(Long.toString(PIM.getDistanceTraveled()));
FastestSpeed.setText(Float.toString(PIM.getFastestSpeedAcheived()));
TotalTime.setText(Long.toString(PIM.getTotalTimeRan()));
KeepItUp.setText(Long.toString(PIM.getLongestTimeInKeepItUp()));
}
public void loadAll()
{// load all saved player data from sharedpreferences
DistanceTraveled = SP.getLong("DistanceTraveled", 0L);
FastestSpeedAcheived = SP.getFloat("FastestSpeed", 0.0f);
TotalTimeRan = SP.getLong("TotalTime", 0L);
LongestTimeInKeepItUp = SP.getLong("KeepItUp", 0L);
}

using .commit() method will make sure your data has been saved.
see the android doc for sharedPreferences.
see the commit and apply method

Use onPause instead since this occurs before onStop
From the documentation
Called when the system is about to start resuming a previous activity. This is typically used to commit unsaved changes to persistent data, stop animations and other things that may be consuming CPU, etc. Implementations of this method must be very quick because the next activity will not be resumed until this method returns.
You might want to see the description of an Activity's lifecycle.

Related

How to retain the task of the activity even when closing the app Android

I have a switch button in my android app I intend to switch it on but after I exit the app by removing it on my background task when I opened again the app it goes back to normal and switch goes back to off again. i=I want to retain or save the activity which I have been left. How am I going to retain the task of my activity basically the fragment itself? Am I going to use On pause?
#Override
public void onPause() {
super.onPause();
}
You can accomplish this using shared preferences. For example, in onCreate, load the switch state from shared preferences (with a default for the first time)
SharedPreferences prefs = getSharedPreferences("MyUniquePrefsName", Context.MODE_PRIVATE);
switchState = prefs.getBoolean("MyBoolean", false); // switchState being a boolean class member
// then set the switch to switchState
When the user updates the switch, change the stored value of switchState and in onPause save the updated state to the shared preferences
#Override
public void onPause() {
super.onPause();
SharedPreferences.Editor ed = getSharedPreferences("MyUniquePrefsName", Context.MODE_PRIVATE).edit();
ed.putBoolean("MyBoolean", switchState);
ed.apply();
}

Android activity refreshes flow

I have an activity A, it has a button to open B, which inserts a record. A can then refresh the view inside onActivityResult. This is a normal flow.
However, B can accept share intent to insert a record also. How can A know when this action is done from B to refresh the view just like the normal flow? (of course, I assume act A already running on background task)
I can, of course, detect the change using onResume inside A, but i wish to know if it is a proper method.
thank you
You can use onResume to refresh the view for activity A. Because other method would be using broadcastReceiver and broadcastIntent and that would create unnecessary load.
You can use sharedPreference to store if data has been changed in Activity B and then in onResume of Activity A fetch that shared Preference and refresh the view
#Override
protected void onResume() {
super.onResume();
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
boolean isChanged = sharedPreferences.getBoolean("isChanged",false);
if(isChanged){
//refresh your views
//clear the shared prefernce
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit();
editor.putBoolean("isChanged",false);
editor.apply();
}
}
Remember you have set that shared preference in ActivityB while loading data
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit();
editor.putBoolean("isChanged",true);
editor.apply();

Perform a task only at start of an Android application

In my app I want a string to be passed to the server only at the startup of application.
I have used SharedPreferences to check if the string is sent or not.
this code runs at star of MainActivity
pref=getPreferences(MODE_PRIVATE);
Sent=pref.getString("ID_SENT", "");
if(Sent.equals(""))
{
SharedPreferences.Editor editor=pref.edit();
editor.putString("ID_SENT","NO");
editor.commit();
Sent=pref.getString("ID_SENT","");
}
Now after the string is sent to the server in onPostExecute of AsyncTask this code is used to set the variable ID_SENT to YES:
Sent=pref.getString("ID_SENT", "");
if(Sent.equals("NO"))
{
SharedPreferences.Editor editor=pref.edit();
editor.putString("ID_SENT","YES");
editor.commit();
}
Now the problem is when I close the app and start the app again it doesn't send the string to server because it finds ID_SENT set to YES.
So is there any way so that I can set ID_SENT to no as the back button is pressed while on MainActivity?
EDIT:
I set launch mode of MainActivity to singleTop. So now activity resumes whenever I press home button from another activities. And the string is not sent everytime because MainActivity is only resumed.
So is there any way so that I can set ID_SENT to no as the back button is pressed while on MainActivity?
Yes,
#Override
public void onBackPressed()
{
// do your save logic here
}
Or you could override onDestroy(), this may be safer in case Android destroys the Activity to reclaim memory

Whether my private date could be saved when process killed my activity in android?

I have to give a dialog when my activity is launched at first time.
So I do that in my
public void onCreate(Bundle savedInstanceState)
and use
protected void onSaveInstanceState (Bundle outState)
to save the time of my launch. I notice that OS create a new "Bundle outState" instead of using the old one. And I can not debug the the date when re Oncreate.
My question:
The date I saved in onSaveInstanceState , could be really read by Oncreate? And how to debug?
Could I just use a private member vary to save the state and without being deleted by OS when the process is killed by OS.
Thank you for your help.
Bundle cannot be used to carry the data across application restarts.
You'd better save your data to the more permanent storage, like SharedPreferences, put this code in onCreate():
SharedPreferences prefs;
prefs = getSharedPreferences( "preferences", Context.MODE_PRIVATE);
long last_run_time = prefs.getLong( 'last_run', 0 );
if( last_run_time == 0 ) { // zero means your app has never been run
// display dialog, this is the first time!
....
// this saves current system time to prevent your dialog being seen again
prefs.edit().putLong( 'last_run', system.currentTimeMillis() ).commit();
}

Application Launch Count

I am working on an application, wherein after say 5 times the app is opened by a user, at 6th attempt the app should ask for feedback from user. I tried using Activity OnStart,OnResume, but its not working out since even after leaving and re-entering activity these methods are called. Also as per android functionality, I cannot quit app so that I can find it out from the first activity called. How do I find how many times the app was launched?
I hope this is not confusing.
Edit
Alternatively is there a way, wherein I can always resume my app from the first activity( or welcome page for eg.), once user presses home to quit the app.
This is actually quite simple. 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 isFinishing() 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(!isFinishing()){
c = mPref.getInt("numRun",0);
c--;
mPref.edit().putInt("numRun",c).commit();
}
//Other pause stuff.
}
This covers all your scenarios:
1. user starts app/activity (+1)-> finishes app, exit with finish()
2. user starts app (+1) -> pause (-1) -> returns (+1)-> finish
3. user starts app (+1) -> pause (-1) -> android kills process (0) -> user returns to app (+1) -> user finish.
every scenario you only increment the "times run" counter once per "run" of the activity
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 e.g.:
System.out.println("Total Application counter Reach to :"+totalCount);
if you have a starting activity for app launch then you can implement it in following ways
1. Database:- through database you can save your application launch count and retrieve it on create of activity.
Static Variable:- static variable also retain values during application start and end
Application Preference:-you can store value in application preference and use it
problem with 2 and 3 approach is that if you switch off and on again your phone you will loose data. but if you still want to use 2 or 3 approach then 2 approach is very simple and
sample code for 3rd approach here
well you have to extends Application class and create a subclass from that
public class MyApp extends Application{
int visitCount;
onCreate(){
visitCount=0;
}
and you can mention it in your menifest file like
<application name="MyApp">
.....
</application>
and in onCreate of your activity you can get it by
MyApp myApp=(MyApp)getApplicationContext();
Edit1:
subclass your activity and override method
public class myActivity extends Activity{
#Override
onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
counterFlag=true;
}
}
it is get called when user press home button
and again override onResume() and check whether your counter flag is enabled or not
and create all your activity by subclassing your MyActivity
also if any other activity has exit point on click of back button then you can override
#Override
public void back_pressed(){
}
and do your task accordingly
I think this would be the best option in order to cover all scenarios:
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){
//Do whatever you want
}
}
}
}
If we remember the definition of a static variable ("...They are associated with the class, rather than with any object. Every instance of the class shares a class variable...") we will discover that is perfect for us.
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.
If you only want to count "true" invocations then extend Application and place counter logic into Application#onCreate. This could be a simple preference
I prefer to use onResume to track launch count since it’s getting called in every scenario (refer to Android Activity Lifecycle) when the activity is shown.
onResume could be called quite frequently depending on usage pattern, so instead of tracking launch count, it would be better to track launch session (as in only 1 launch count would be tracked per hour).
#Synchronized fun appSessionCount(sharedPref: SharedPreferences): Boolean {
val now = LocalDateTime.now(ZoneOffset.UTC)
val firstSeconds = sharedPref.getLong(KEY_FIRST_LAUNCH_DATE, 0)
if (firstSeconds == 0L) {
sharedPref.edit {
putLong(KEY_FIRST_LAUNCH_DATE, now.atZone(ZoneOffset.UTC).toEpochSecond())
}
}
val seconds = sharedPref.getLong(KEY_LAST_SESSION_DATE, 0)
val lastDate = if (seconds > 0) LocalDateTime.ofInstant(Instant.ofEpochSecond(seconds), ZoneOffset.UTC) else null
var count = sharedPref.getLong(KEY_SESSION_COUNT, 0)
// first time or 1 hour ago
if (lastDate == null || Duration.between(lastDate, now).toHours() >= 1) {
sharedPref.edit {
putLong(KEY_SESSION_COUNT, count + 1)
putLong(KEY_LAST_SESSION_DATE, now.atZone(ZoneOffset.UTC).toEpochSecond())
}
return true
}
return false
}
I run the code at onResume of my main activity.
class MainActivity : AppCompatActivity() {
lateinit var sharedPref: SharedPreferences
override fun onCreate(savedInstanceState: Bundle?) {
sharedPref = getSharedPreferences("LuaApp", Context.MODE_PRIVATE)
}
override fun onResume() {
super.onResume()
appSessionCount(sharedPref)
}
}
https://code.luasoftware.com/tutorials/android/android-track-app-launch-count/

Categories

Resources