OnResume from specific activity - android

Im integrating TapResearch in my Android app. As mentioned here in the documentation https://www.tapresearch.com/docs/android-integration-guide that the to show the survey I need to use TapResearch.getInstance().showSurvey();. This method open an activity from the library.
In the documentation there is a listener onSurveyModalClosed() so I can put anything once the activity is finished, but this listener does not work.
Since onSurveyModalClosed() does not function. In the MainActivity I want the app to do something OnResume from TapResearch Activity.
#Override
protected void onResume() {
If the resume happens upon returning from TapResearch Activity {
Do something.
}
}
I think this is the activity path import
com.tapr.internal.activities.survey.SurveyActivity;

This may not be the best answer available but a workaround as this is the only thing I found for myself.
Whenever a specific activity is launched, I set a boolean variable as True in OnCreate() of that launched activity using TinyDB (sample code below), and when returning back to MainAcitivity, I check whether the variable is true and if true, then a specific code is executed.
In OnCreate() of launched activity:
TinyDB tinydb = new TinyDB(this);
tinydb.putBoolean("isMyActivity",true);
And in OnResume() of MainActivity:
#Override
protected void onResume() {
if(tinydb.getBoolean("isMyActivity")) {
yourMethod();
}
super.onResume();
}
You can use SharedPreferences to store the boolean or a public static boolean variable. I use TinyDB for many things. This works great.

Related

How to check activity has been destroyed or no more running

I am working on an android app and have an activity. I have written a code in my activity that will start a new activity after getting response from server, this code is getting executed even after I press back button on my activity.
So, I want to check that if my current activity is not active anymore, then the code should not run.
How can I check that activity is not running or in existence any more.
Please help me if anyone know how to do this.
Thanks a lot in advanced.
Activity is still in memory that's why your code is executed to finish it completed call finish() after starting another activity.
To check if current activity is there or not you have to override onDestroy() method which is called everytime when your activity is completely destroyed.
For checking activity is running or not follow this question
just call finish() method when you starts a new Activity
like
Intent intent = new Intent(this, NextActivity.class);
startActivity(intent);
finish();//this activity has been finish and the code will not execute
you can check if Activity is destroyed or not.
override this method
public void onDestroy() {
super.onDestroy();
Log.d("Activity name,"destroyed");
}
Try like this
class MyActivity extends Activity {
static boolean isActive = false;
#Override
public void onStart() {
super.onStart();
isActive = true;
}
#Override
public void onStop() {
super.onStop();
isActive = false;
}
}
Check here : Proper way to know whether an Activity has been destroyed
The question have your answer and as the solution provided just use the SharedPrefrence to store the variable.

Android - How to know when app has been resumed after being in background

I'm trying to determine when my app is being resumed after the user closed it, in any way, pressing home button, back button or switching to another app.
What I need to do is to set a boolean when the app goes in background, so, when it is resumed, I know that it was in background before and I can act accordingly.
I tried to use onResume and onPause methods in activities to know when the app goes in background and it is then resumed, but as only one activity can be alive at at time, I had no success. When an activity is paused, this doesn't mean that the app went to background, because another activity could have been launched, but the onResume event of that activity will trigger only after the previous one has paused.
I've also tried to list all the apps in foreground, but with no success, if I put my app in background resuming another app, my app always results to be in the foreground.
I read that since Android 4 there is a new method to know when the app is in foreground, but I need my app to be compatible with Android 3.0 devices too.
Here is the code I tried putting in every single activity (MyApp is my Application name):
#Override
protected void onResume() {
super.onResume();
MyApp.isPaused = false;
}
#Override
protected void onPause() {
super.onPause();
MyApp.isPaused = true;
}
This is also my attempt to list all the apps in foreground:
ActivityManager activityManager = (ActivityManager)((Activity) currentContext).getSystemService( ACTIVITY_SERVICE );
List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
for(RunningAppProcessInfo appProcess : appProcesses){
if(appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND){
if(appProcess.processName.equals("com.xxx.myapp")) {
Log.i("MyApp", "it's in foreground");
}
Log.i("MyApp", appProcess.processName);
}
}
This class provides a singleton to determine "the activity in background" status. It uses a timer with a threshold(i.e. 0.3s) to determine the activity is went to background or not.
One thing has to point out is that if the user resumes to the activity within the threshold (i.e. 0.3s), this test will be failed.
If you have a better solution, please share with us :)
Ref: https://gist.github.com/steveliles/11116937
You are absolutely correct :) Because only one activity can be alive at a time so you need something which remains alive through out the application life cycle :) like Application instance itself or you can also make use of shared preference for that matter. But seriously using shared prefference for checking lifecycle is wrong choice if you ask me.
If I was in your position I would have gone for Application class :) Here is code if you want to do the same :)
import android.app.Application;
/**
* Created by sandeepbhandari on 3/3/16.
*/
public class AppService extends Application{
private static AppService sInstance;
public static boolean isGoingToBackGround=false;
#Override
public void onCreate() {
super.onCreate();
sInstance = this;
}
public static AppService getInstance() {
return sInstance;
}
}
In all your activities onPause just set
AppService service = AppService.getInstance();
service.isGoingToBackGround =true;
And in onResume check the same variablethats all :) and yeah if you want to use your application class rather than default Application you have to make change to manifest.xml
<application
android:name=".AppService"
Thats all :)
Override onTrimMemory(int level) in your Application. Might not be the prettiest way, but it has worked for me.
You will get
TRIM_MEMORY_BACKGROUND = 40;
when your application went into the Background.
You can make Application class inside your project to save state of your project. When any activity goes to pause call on pause respectively while on resume call on resume method and save state of the inside this class. Even if one activity goes on pause another on resume your class will know exact state of the application. Or another way you can save applicaton state in shared preference in each activity can change its value.
i trust there is no need for u to post a code... that being said...
start by logging every implemented methods onCreate(), onPause(), onDestroy(), and other well reputed Activity methods...
but back button does not just pause it kills, thus onCreate is called most
and check onStart() too.
public class CustomApplication extends Application {
private static boolean activityVisible;
#Override
public void onCreate() {
super.onCreate();
}
public static boolean isActivityVisible() {
return activityVisible;
}
public static void activityResumed() {
activityVisible = true;
}
public static void activityPaused() {
activityVisible = false;
}
}
and in your all activities set
#Override
protected void onResume() {
super.onResume();
CustomApplication.activityResumed();
}
#Override
protected void onPause() {
super.onPause();
CustomApplication.activityPaused();
}
and in your manifest
<application
android:name=".CustomApplication"

which Operation will perform first in onStart or onCreate in Android

I want to perform one data base Operation once. I want to do this when My Activity is Visible. Where shall I puty my LoadDatabase() function
LoadDatabase();
this is my oncreate of activity
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.retrospectscan);
}
this is my onStart
#Override
protected void onStart()
{
super.onStart();
}
Where Shall I put my LoadDatabase Code ? So that It will operated only if activity is fully Visible.
If Any other Approach is there please help me.
The complete activity lifecycle is here:
Though loading from database may be lengthy task , you can try doing it in AsyncTask or in onStart.
You can also use it on onResume. This depends on your application use.
user2737044
use Application context and load your database in application context create().
2nd thing is that, In activity onCreate() call first then it will call onstart().

onSharedPreferenceChanged not fired if change occurs in separate activity?

I've implemented onSharedPreferenceChanged in my main activity.
If I change the preferences in the main activity, my event fires.
If I change the preferences through my preferences screen (PreferenceActivity) my event does NOT fire when preferences are changed (because it's a separate activity and separate reference to sharedPreferences?)
Does anybody have a recommendation of how I should go about overcoming this situation?
Thanks!
EDIT1: I tried adding the event handler right in my preference activity but it never fires. The following method gets called during onCreate of my preference activity. When I change values, it never prints the message (msg() is a wrapper for Log.d).
private void registerChangeListener () {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
sp.registerOnSharedPreferenceChangeListener(new OnSharedPreferenceChangeListener () {
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
msg (" ***** Shared Preference Update ***** ");
Intent i = new Intent();
i.putExtra("KEY", key);
i.setAction("com.gtosoft.dash.settingschanged");
sendBroadcast(i);
// TODO: fire off the event
}
});
}
The OnSharedPreferenceChangeListener gets garbage collected in your case if you use an anonymous class.
To solve that problem use the following code in PreferenceActivity to register and unregister a change listener:
public class MyActivity extends PreferenceActivity implements
OnSharedPreferenceChangeListener {
#Override
protected void onResume() {
super.onResume();
// Set up a listener whenever a key changes
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
#Override
protected void onPause() {
super.onPause();
// Unregister the listener whenever a key changes
getPreferenceScreen().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this);
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,String key)
{
// do stuff
}
Furthermore be aware that the listener only gets called if the actual value changes. Setting the same value again will not fire the listener.
see also SharedPreferences.onSharedPreferenceChangeListener not being called consistently
This happen because garbage collector. its works only one time. then the reference is collected as garbage. so create instance field for listener.
private OnSharedPreferenceChangeListener listner;
listner = new SharedPreferences.OnSharedPreferenceChangeListener() {
#Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
//implementation goes here
}
};
prefs.registerOnSharedPreferenceChangeListener(listner);
I arrived here, like many others, because my listener won't be fired when I changed my boolean from true to false, or viceversa.
After much reading, and refactoring, switching contexts/inner classes/privates/static/ and the like, I realized my (stupid) error:
The onSharedPreferenceChanged is only called if something changes. Only. Ever.
During my tests, I was so dumb to click on the same button all the time, thus assigning the same boolean value to the preference all the time, so it did not ever change.
Hope this helps somebody!!
One other way of avoiding the problem is to make your activity the listener class. Since there is only one override method with a distinctive name you can do this:
public class MainActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
...
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
{
...
}
}
Note the original question spoke of a MainActivity listening to setting changes in a PreferenceActivity. The asker then added an "EDIT1" and changed the question to listening in the PreferenceActivity itself. That is easier than the former and seems to be what all the answers assume. But what if you still want the former scenario?
Well, it will work too, but do not use OnResume() and OnPause() to register and unregister the listener. Doing so will cause the listener to be ineffectual because the user leaves the MainActivity when they use the PreferenceActivity (which makes sense when you think about it). So it will work, but then your MainActivity will still be listening in the background even when the user is not using it. Kind of a waste of resources isn't it? So there is another solution that seems to work, simply add a method to OnResume() to re-read all preferences. That way when a user finishes editing preferences in a PreferenceActivity, the MainActivity will pick them up when the user returns to it and you don't need a listener at all.
Someone please let me know if they see a problem with this approach.
Why don't you just add a onSharedPreferenceChanged in the rest of the activities where the preferences could change?
The garbage collector erases that... you should consider using an Application context instead...or just add the code when app launchs... and then add the the listener with application context...
Consider keeping PreferencesChangeListener inside Android App class instance. Although it's NOT a clean solution storing reference inside App should stop GC from garbage collecting your listener and you should still be able to receive DB change updates. Remember that preference manager does not store a strong reference to the listener! (WeakHashMap)
/**
* Main application class
*/
class MyApp : Application(), KoinComponent {
var preferenceManager: SharedPreferences? = null
var prefChangeListener: MySharedPrefChangeListener? = null
override fun onCreate() {
super.onCreate()
preferenceManager = PreferenceManager.getDefaultSharedPreferences(this)
prefChangeListener = MySharedPrefChangeListener()
preferenceManager?.registerOnSharedPreferenceChangeListener(prefChangeListener)
}
}
and
class MySharedPrefChangeListener : SharedPreferences.OnSharedPreferenceChangeListener {
/**
* Called when a shared preference is changed, added, or removed.
*/
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
if (sharedPreferences == null)
return
if (sharedPreferences.contains(key)) {
// action to perform
}
}
}
While reading Word readable data shared by first app,we should
Replace
getSharedPreferences("PREF_NAME", Context.MODE_PRIVATE);
with
getSharedPreferences("PREF_NAME", Context.MODE_MULTI_PROCESS);
in second app to get updated value in second app.

SharedPreferences.onSharedPreferenceChangeListener not being called consistently

I'm registering a preference change listener like this (in the onCreate() of my main activity):
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefs.registerOnSharedPreferenceChangeListener(
new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(
SharedPreferences prefs, String key) {
System.out.println(key);
}
});
The trouble is, the listener is not always called. It works for the first few times a preference is changed, and then it is no longer called until I uninstall and reinstall the app. No amount of restarting the application seems to fix it.
I found a mailing list thread reporting the same problem, but no one really answered him. What am I doing wrong?
This is a sneaky one. SharedPreferences keeps listeners in a WeakHashMap. This means that you cannot use an anonymous inner class as a listener, as it will become the target of garbage collection as soon as you leave the current scope. It will work at first, but eventually, will get garbage collected, removed from the WeakHashMap and stop working.
Keep a reference to the listener in a field of your class and you will be OK, provided your class instance is not destroyed.
i.e. instead of:
prefs.registerOnSharedPreferenceChangeListener(
new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
// Implementation
}
});
do this:
// Use instance field for listener
// It will not be gc'd as long as this instance is kept referenced
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
// Implementation
}
};
prefs.registerOnSharedPreferenceChangeListener(listener);
The reason unregistering in the onDestroy method fixes the problem is because to do that you had to save the listener in a field, therefore preventing the issue. It's the saving the listener in a field that fixes the problem, not the unregistering in onDestroy.
UPDATE: The Android docs have been updated with warnings about this behavior. So, oddball behavior remains. But now it's documented.
this accepted answer is ok, as for me it is creating new instance each time the activity resumes
so how about keeping the reference to the listener within the activity
OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener(){
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
// your stuff
}
};
and in your onResume and onPause
#Override
public void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(listener);
}
#Override
public void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(listener);
}
this will very similar to what you are doing except we are maintaining a hard reference.
The accepted answer creates a SharedPreferenceChangeListener every time onResume is called. #Samuel solves it by making SharedPreferenceListener a member of the Activity class. But there's a third and a more straightforward solution that Google also uses in this codelab. Make your activity class implement the OnSharedPreferenceChangeListener interface and override onSharedPreferenceChanged in the Activity, effectively making the Activity itself a SharedPreferenceListener.
public class MainActivity extends Activity implements SharedPreferences.OnSharedPreferenceChangeListener {
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
}
#Override
protected void onStart() {
super.onStart();
PreferenceManager.getDefaultSharedPreferences(this)
.registerOnSharedPreferenceChangeListener(this);
}
#Override
protected void onStop() {
super.onStop();
PreferenceManager.getDefaultSharedPreferences(this)
.unregisterOnSharedPreferenceChangeListener(this);
}
}
As this is the most detailed page for the topic I want to add my 50ct.
I had the problem that OnSharedPreferenceChangeListener wasn't called. My SharedPreferences are retrieved at the start of the main Activity by:
prefs = PreferenceManager.getDefaultSharedPreferences(this);
My PreferenceActivity code is short and does nothing except showing the preferences:
public class Preferences extends PreferenceActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// load the XML preferences file
addPreferencesFromResource(R.xml.preferences);
}
}
Every time the menu button is pressed I create the PreferenceActivity from the main Activity:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
//start Preference activity to show preferences on screen
startActivity(new Intent(this, Preferences.class));
//hook into sharedPreferences. THIS NEEDS TO BE DONE AFTER CREATING THE ACTIVITY!!!
prefs.registerOnSharedPreferenceChangeListener(this);
return false;
}
Note that registering the OnSharedPreferenceChangeListener needs to be done AFTER creating the PreferenceActivity in this case, else the Handler in the main Activity won't be called!!! It took me some sweet time to realize that...
Kotlin Code for register SharedPreferenceChangeListener it detect when change will happening on the saved key :
PreferenceManager.getDefaultSharedPreferences(this)
.registerOnSharedPreferenceChangeListener { sharedPreferences, key ->
if(key=="language") {
//Do Something
}
}
you can put this code in onStart() , or somewhere else..
*Consider that you must use
if(key=="YourKey")
or your codes inside "//Do Something " block will be run wrongly for every change that will happening in any other key in sharedPreferences
So, I don't know if this would really help anyone though, it solved my issue.
Even though I had implemented the OnSharedPreferenceChangeListener as stated by the accepted answer. Still, I had an inconsistency with the listener being called.
I came here to understand that the Android just sends it for garbage collection after some time. So, I looked over at my code.
To my shame, I had not declared the listener GLOBALLY but instead inside the onCreateView. And that was because I listened to the Android Studio telling me to convert the listener to a local variable.
It make sense that the listeners are kept in WeakHashMap.Because most of the time, developers prefer to writing the code like this.
PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).registerOnSharedPreferenceChangeListener(
new OnSharedPreferenceChangeListener() {
#Override
public void onSharedPreferenceChanged(
SharedPreferences sharedPreferences, String key) {
Log.i(LOGTAG, "testOnSharedPreferenceChangedWrong key =" + key);
}
});
This may seem not bad. But if the OnSharedPreferenceChangeListeners' container was not WeakHashMap, it would be very bad.If the above code was written in an Activity . Since you are using non-static (anonymous) inner class which will implicitly holds the reference of the enclosing instance. This will cause memory leak.
What's more, If you keep the listener as a field, you could use registerOnSharedPreferenceChangeListener at the start and call unregisterOnSharedPreferenceChangeListener in the end. But you can not access a local variable in a method out of it's scope. So you just have the opportunity to register but no chance to unregister the listener. Thus using WeakHashMap will resolve the problem. This is the way I recommend.
If you make the listener instance as a static field, It will avoid the memory leak caused by non-static inner class. But as the listeners could be multiple, It should be instance-related. This will reduce the cost of handling the onSharedPreferenceChanged callback.
While reading Word readable data shared by first app,we should
Replace
getSharedPreferences("PREF_NAME", Context.MODE_PRIVATE);
with
getSharedPreferences("PREF_NAME", Context.MODE_MULTI_PROCESS);
in second app to get updated value in second app.
But still it is not working...

Categories

Resources