I just recently started learning how to build android apps, and encountered a problem:
I want, when users leave the app (go to the homescreen, multitask), and they return, that the app calls a certain method. How can I do that?
This problem is more tricky than it may look like. When you return to app after leaving it, then is called method onResume of activity which was active when app was interrupted. But same happens when you go from one activity to another (onResume of second activity is called). If you just call method from onResume, it will be called every time onResume of any activity is called.
Take a look at this solution...
First, you have BaseActivity which is extended by all activities that need to call that method:
abstract public class BaseActivity extends Activity implements IName {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
protected void onResume() {
if (AppClass.getPausedActivity() != null) {
if (this.getClassName().equals(AppClass.getPausedActivity()))
//call specific method
}
AppClass.setPausedActivity("");
super.onResume();
}
#Override
protected void onPause() {
AppClass.setPausedActivity(this.getClassName());
super.onPause();
}
#Override
abstract public String getClassName();
}
As you can see it implements interface IName:
public interface IName
{
String getClassName();
}
BaseActivity in onPause (when it is interrupted) calls setPausedActivity method of AppClass which remembers last activity name that was interrupted. In onResume (when app and activity is continued) we compare name of current activity and last paused activity.
So, when app is interrupted, these names will be same because you paused one activity and you got back to the same one. When you call activity from some other activity these names will not be same and method will not be called.
Here is code for AppClass:
public class AppClass extends Application {
public static String pausedActivity;
public static String getPausedActivity() {
return pausedActivity;
}
public static void setPausedActivity(String _pausedActivity) {
pausedActivity = _pausedActivity;
}
}
Also, here is example of activity that extends BaseActivity:
public class MainActivity extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
}
//here you set name of current activity
#Override
public String getClassName() {
return "MainActivity";
}
}
You are bound to the Activity lifecycle. You will need to implement corresponding logic to figure out if the user has been in your app before (i.e. using SharedPreferences).
Related
I think this question may simple but I didn't find any solution for this,
I there any way in Android that if any one of an activity calls onPause() I need to show Toast message or any notification kind of thing need to show. Generally I want to get notified when activity calls onPause() but I need it in one place since I may have some 15 activity I don't want to add it in all the activity.
ex:If I have activity when any one of the activity calls onPause I need to get notified but that notification code should be in one place and we should not add any line of code onPause() Is it possible to do this.
Thanks.
Create a baseActivity, which has for example :
open class BaseActivity : AppCompatActivity() {
override fun onPause() {
super.onPause()
Toast.makeText(this, "notified", Toast.LENGTH_SHORT).show()
}
}
Then you can extends this in your activities and handle the on pause call in BaseActivity
If your minSdkVersion >= 14, you can use Application.ActivityLifecycleCallbacks: ActivityLifecycleCallbacks
You have to define a custom Application class and you can register for this callbacks afterwards:
public class MyApplication extends Application {
private class LifecycleCallbacks implements Application.ActivityLifecycleCallbacks {
#Override
public void onActivityCreated(final Activity activity, final Bundle savedInstanceState) {
//nothing to do
}
#Override
public void onActivityDestroyed(final Activity activity) {
//nothing to do
}
#Override
public void onActivityPaused(final Activity activity) {
// TODO Do your stuff, e.g. show toast.
}
#Override
public void onActivityResumed(final Activity activity) {
//nothing to do
}
#Override
public void onActivitySaveInstanceState(final Activity activity, final Bundle outState) {
//nothing to do
}
#Override
public void onActivityStarted(final Activity activity) {
}
#Override
public void onActivityStopped(final Activity activity) {
}
}
private final LifecycleCallbacks callbacks;
public void onCreate() {
super.onCreate();
callbacks = new LifecycleCallbacks();
application.registerActivityLifecycleCallbacks(callbacks);
}
}
Create a BaseActivity which contain all the methods you want to use in all other activities.
Then extend every activity with BaseActivity to call onPause() method.
I was wondering, during activity re-creation, or fragment re-creation or service re-creation, is there a possibility, that the same instance of class being re-used?
For example
//public class HomeFragment extends Activity {
//public class HomeFragment extends Service {
public class HomeFragment extends Fragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Can instrumentSearchMonitor has possibility to become null right here, due to onDestroy?
instrumentSearchMonitor.doSomething();
}
#Override
public void onDestroy() {
super.onDestroy();
instrumentSearchMonitor = null;
}
private InstrumentSearchMonitor instrumentSearchMonitor = new InstrumentSearchMonitor();
}
For the above case, is there a possibility that onCreate will encounter a null object, due to nullify action in onDestroy?
My testing is, after onDestroy is being called, the next call of onCreate will happen on the different class instance.
I was wondering, is there any possibility, that the next call of onCreate, will happen on the same class instance?
Once onDestroy() has been called, the fragment is going to be completely removed and can not be reused.
This can be seen in the Fragment lifecycle:
https://i.stack.imgur.com/fRxIQ.png
In the image you can seee that onDestroyView() can be called, and then it goes back to onCreateView(), but once onDestroy() is called, you're safe to null/delete whatever you want in that class instance.
Put your code above onDestroy
#Override
public void onDestroy() {
instrumentSearchMonitor = null;
super.onDestroy();
}
I would like to know if there's a way to differentiate when the onResume() method of an activity is called from the same app or a different application.
For example I would like to differentiate when my main activity's onResume() is called when I return to the app from Whatsapp or another activity of my app.
I know there's a way to do it with GET_TASKS permission but that method is deprecated and not recommended.
Thank you
It appears you want to know when app comes from the background to foreground in each Activity. This can be achieved using a class that extends the Application class and implements the ActivityLifecycleCallbacks interface. Firstly, here's the code for this class:
public class MyApplication extends Application implements ActivityLifecycleCallbacks {
public boolean appInBackground;
private Handler mHandler;
...
#Override
public void onActivityResumed(Activity activity) {
Log.i("Activity Resumed", activity.getLocalClassName());
mHandler.cancelCallbacksAndMessages(null);
appInBackground = false;
}
#Override
public void onActivityPaused(Activity activity) {
Log.i("Activity Paused", activity.getLocalClassName());
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
appInBackground = true;
}
}, 5000);
}
...
}
If you notice in above code we are basically giving the app a grace period of 5 seconds to switch from one activity to other. If it exceeds more than that, it means the app was in background. The above class will need to registered in the <application> tag of your manifest file under android:name:"" property as android:name:"MyApplication".
To use this in your activity, override the onPause():
private boolean resumedFromBg;
#Override
protected void onPause() {
super.onPause();
resumedFromBg = ((MyApplication) getApplication()).appInBackground;
}
Let me know if you run into any issues~
I have a very simple preferences setup in which a PreferenceFragment is added to an Activity. The Activity is also an OnSharedPreferenceChangeListener, since I want to update the summary of a particular preference whenever that preference is updated. Here's the Activity:
public class PrefsActivity extends Activity implements OnSharedPreferenceChangeListener {
private static final String PREF_KEY = "key goes here";
private PrefsFragment pf;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pf = new PrefsFragment();
getFragmentManager().beginTransaction().replace(android.R.id.content, pf).commit();
// pf.getPreferenceScreen() throws a NullPointerException here
}
#Override
protected void onPause() {
super.onPause();
PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this);
}
#Override
protected void onResume() {
super.onResume();
updateSummary();
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
}
#Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (key.equals(PREF_KEY)) {
updateSummary();
}
}
private void updateSummary() {
Preference p = pf.getPreferenceScreen().findPreference(PREF_KEY);
p.setSummary("Some string containing the updated value");
}
}
The PreferenceFragment is equally simple:
public class PrefsFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
// At this point getPreferenceScreen() returns correctly
}
}
Here's the thing: Calling getPreferenceScreen() on the PreferenceFragment, immediately after it's been instantiated and added to the Activity in onCreate of PrefsActivity, throws a NullPointerException. It seems that getPreferenceScreen() starts returning a PreferenceScreen object in onCreate() of PrefsFragment, immediately after the call to addPreferencesFromResource() returns.
So my question is this: Since getPreferenceScreen() throws an NPE immediately after the PreferenceFragment has been added to the Activity, is the onCreate() of the PreferenceFragment called asynchronously/in a different thread? Otherwise I would have expected getPreferenceScreen() to return normally immediately after getFragmentManager().beginTransaction().replace(android.R.id.content, pf).commit().
is the onCreate() of the PreferenceFragment called asynchronously/in a
different thread?
No, it is run synchronously on the main thread. That means it has to wait until the Activitys onCreate exits before it gets to run. The FragmentManager schedules the Fragment callbacks, but they are not executed until the current callback (onCreate of the activity) is complete.
You have a few other places to access your PreferenceScreen. OnStart is called when the UI is ready, so the Fragment will be ready. onResume is called after onStart and is probably the best place to put something since it is invoked after coming back from a pause, too.
Is there a way to register for an activity's events? I'm specifically interested in the onStart / onStop events, and I don't want to add special operations in the activity for that.
One way to get events from the lifecycle of other activities is to register your class as an Application.ActivityLifecycleCallbacks with the main Application instance and filter events for the Activity you're interested in.
This is a short example (you may want to register the callbacks from another method/class other than MainActivity.onCreate or you'll miss that message ;) and you may have a dependency there that you don't want)
On the activity you want to spy:
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Register a spy for this activity
getApplication().registerActivityLifecycleCallbacks(new ActivitySpy(this));
}
}
Then the Spy code looks something like:
public class ActivitySpy implements ActivityLifecycleCallbacks {
private final Activity mActivity;
public ActivitySpy(Activity activity) {
mActivity = activity;
}
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
if (mActivity == activity)
Log.i("SPY", "Activity Created");
}
#Override
public void onActivityDestroyed(Activity activity) {
if (mActivity == activity)
Log.i("SPY", "Activity Destroyed");
}
// (...) Other overrides
}
You can also register the spy from another place if you have a reference to the Activity you want to follow.
I hope this helps :)
EDIT: I forgot to mention, this will only work on API Level 14 and above...