Problem
The idea is very simple. Whenever an user comes back to my app from the Recents I want to show a simple dialog prompting with the password.
I know how to prompt the dialog with password, but my problem is how do I understand that the user has entered my app from the recents. If I put the prompt in the onResume in every activity, then it will get triggered everytime even if the user doesn't enter from the Recents menu.
There are lots of activities and fragments in my app. So, I would love to have a more generic or application level solution.
Implement Application.ActivityLifecycleCallbacks, that will provide all activity callback in your application class.
public class AppController extends Application implements
Application.ActivityLifecycleCallbacks
{
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
#Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
}
You could try with this flag FLAG_ACTIVITY_LAUNCHER_FROM _HISTORY:
if((getIntent().getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY )!=0){
Log.d(TAG, "Called from history");
//clear flag from history
Intent intent = getIntent().setFlags( getIntent().getFlags() & (~ Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY));
setIntent(intent);
}
Source : Android - detecting application launch from home or history
When "A" Activity is start from recent, this flag is present.
Now this flag will be also present if "A" activity call "B" activity and on "B" user press back.
So you have to check flag and when you detect it you have clear intent by removing this flag, source: Remove a Paint Flag in Android
Try below sample
/**
* TODO : After update to API level 14 (Android 4.0),
* We should implement Application.ActivityLifecycleCallbacks
*/
public class GlobalApplication extends android.app.Application
{
private boolean inForeground = true;
private int resumed = 0;
private int paused = 0;
public void onActivityResumed( Activity activity )
{
++resumed;
if( !inForeground )
{
// Don't check for foreground or background right away
// finishing an activity and starting a new one will trigger to many
// foreground <---> background switches
//
// In half a second call foregroundOrBackground
}
}
public void onActivityPaused( Activity activity )
{
++paused;
if( inForeground )
{
// Don't check for foreground or background right away
// finishing an activity and starting a new one will trigger to many
// foreground <---> background switches
//
// In half a second call foregroundOrBackground
}
}
public void foregroundOrBackground()
{
if( paused >= resumed && inForeground )
{
inForeground = false;
}
else if( resumed > paused && !inForeground )
{
inForeground = true;
}
}
}
Put below code in your all activities.
public class BaseActivity extends android.app.Activity
{
private GlobalApplication globalApplication;
#Override
protected void onCreate()
{
globalApplication = (GlobalApplication) getApplication();
}
#Override
protected void onResume()
{
super.onResume();
globalApplication.onActivityResumed(this);
}
#Override
protected void onPause()
{
super.onPause();
globalApplication.onActivityPaused(this);
}
#Override
public void onDestroy()
{
super.onDestroy();
}
}
I would suggest using LifecycleObserver. If your Application class implements this interface it marks a class as a LifecycleObserver, it does not have any methods, instead, it relies on OnLifecycleEvent annotated methods. The usage is simple:
public class AndroidApplication extends Application implements LifecycleObserver {
#OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onAppStart() {
//enter code here
}
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onAppStop() {
//enter code here
}
...etc
}
With Lifecycle.Event you can access all lifecycle states through Enum. It is part of androidx.
Related
Is there any universal method that is called when app goes in background ? I dont want to perform the action when the activity is changes just want to perform it when app goes in background i.e.home_screen appears.
You can achieve this by using ActivityLifeCycleCallbacks:
public class LifeCycleCallbacks implements Application.ActivityLifecycleCallbacks {
/**
* Keeps a count of the activities started.
*/
private int mActivitiesStarted;
/**
* Keeps a count of the activities stopped.
*/
private int mActivitiesStopped;
#Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
#Override
public void onActivityStarted(Activity activity) {
if (mActivitiesStarted == mActivitiesStopped) {
// This is the session start
}
++mActivitiesStarted;
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
++mActivitiesStopped;
if ((mActivitiesStarted > 0) && (mActivitiesStarted == mActivitiesStopped)) {
/* This is session end. We can do things that we need to do when the app
* session ends, i.e. send tracking info, etc. */
}
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
}
Finally, register your LifeCycleCallbacks class with your Application class in onCreate:
registerActivityLifecycleCallbacks(new LifeCycleCallbacks());
I need to know when the user close the App, not when the user press on the "home" button, but when the user close the App at the "recent applications menu".
At those two cases the App go to the onPause method. Is there any way to tell them apart?
I`m asking because, I want to delete the user from my database on one situation, and not at the other.
you can try combining multiple callbacks from the activity lifecycle.
onUserLeaveHint() can be realy usefull to get know if the activity is in background or foreground
isFinishing(): can bu used to know if the activity is been closed by a finish() call or if is the system shutting down the activity to free resources
you can try using a Service for that, in this service override onTrimMemory method
#Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
switch (level) {
case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
//app was closed
break;
}
}
check more about services
I'm not sure, but maybe ActivityLifecycleCallbacks can help you. It need to test.
Example:
public class YourApplication extends Application {
#Override
public void onCreate() {
lifecycleListener = new ActivityLifecycleListener();
registerActivityLifecycleCallbacks(lifecycleListener);
}
public class ActivityLifecycleListener implements Application.ActivityLifecycleCallbacks {
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
}
}
I want to record state of application when it is resumed/created from different point of entry.
app is opened from app drawer
app is opened from notification
app is opened from open apps (Long home press)
app is resumed from other screen
I know it can be traced by generating a base activity and overriding resume/pause events, but I have bulk of activity present in app. so is there any short method to get the state of application?
I thought about creating a service and continuously checking current running tasks, but I can only use this approach if I found a way to run the service only when my activity is in visible state. (for that to bind service in each activity is not practical for me)
Your suggested solution sounds good to me:
public class YourBaseActivity extends Activity {
#Override
protected void onResume() {
super.onResume();
ActivityManager mgr = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = mgr.getRunningTasks(1);
tasks.get(0).topActivity.getClassName();
//Do what you need to do with it...
}
}
And let all your activities extends this one instead of Activity should work for you
EDIT
Another way to do it:
Create your own application class and implement Application.ActivityLifecycleCallbacks, a working example of the code:
public class ApplicationTest extends Application implements Application.ActivityLifecycleCallbacks {
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
Log.d("testing", "onActivityResumed");
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
}
}
And reference this class in your manifest:
<application
...
android:name="com.example.testing.ApplicationTest" >
I'm trying to call a method when a user launch my application (no matter it is a fresh launch, or a return to it after hiding by home buttton)
For iOS, we can put the method in "applicationDidBecomeActive" in AppDelegate.m, so the method will be called when app launches.
However, for Android, if we put the method in onResume() in the 1st activity, not only app launch will call the method, backing to the the 1st activity from other activities in the same app will also call the method. I don't want this happen, I just want the method to be called when app launches.
I've asked it in the past but seems no answer on Android.
Any solutions? Thanks a lot.
You can implement your own Application class. MyApplication extends Application and set it as your Application in the manifest file AndroidManifest.xml.
<application
android:name="MyApplication"
.
.
. >
</application>
In MyApplication Class, implement onCreate() and onTerminate() methods.
onCreate() method called when the application is starting, before any activity, service, or receiver objects (excluding content providers) have been created.
See the docs for Application.
There is no method that is called only when the app returns from background, but you could implement something that you could implement something like this to see if the app started from background or it was first started. Create a general activity that will be extended by all the other activities and override onStart():
public abstract class CustomActivity extends FragmentActivity {
public static int ACTIVITIES_RUNNING = 0;
#Override
protected void onStart() {
super.onStart();
if (ACTIVITIES_RUNNING == 0) {
//app came from background
//start whatever you want
}
Const.ACTIVITIES_RUNNING++;
}
}
First create singleton for counting activities in foreground
public class ActivitiesCounter {
public interface ApplicationLaunchListener{
public void onLaunch();
}
private int mCounter = 0;
private ApplicationLaunchListener mListener;
private static ActivitiesCounter mInstance = new ActivitiesCounter();
public static ActivitiesCounter getInstance(){
return mInstance;
}
public void increase(){
if(mCounter == 0){
if(mListener != null){
mListener.onLaunch();
}
}
mCounter++;
}
public void decrease(){
mCounter--;
}
public void setApplicationLaunchListener(ApplicationLaunchListener listener){
mListener = listener;
}
}
Then activity:
public class MyActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ActivitiesCounter.getInstance().setApplicationLaunchListener(new ActivitiesCounter.ApplicationLaunchListener() {
#Override
public void onLaunch() {
Toast.makeText(MyActivity.this, "launched", Toast.LENGTH_LONG).show();
}
});
findViewById(R.id.btn_activity_b).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MyActivity.this, ActivityB.class);
startActivity(intent);
}
});
}
#Override
protected void onStart() {
super.onStart();
ActivitiesCounter.getInstance().increase();
}
#Override
protected void onStop() {
ActivitiesCounter.getInstance().decrease();
super.onStop();
}
}
Activity B also should increase and decrease counter
public class ActivityB extends Activity {
#Override
protected void onStart() {
super.onStart();
ActivitiesCounter.getInstance().increase();
}
#Override
protected void onStop() {
ActivitiesCounter.getInstance().decrease();
super.onStop();
}
}
It's better create BaseActivity (with onStart, onStop) for all activities in your app (then, you don't need override onStart, onStop every time)
You can define a superclass for all your activities and track the state of the app. If all activities are in stopped state - app in the background, otherwise - in the foreground. In onStart() and onStop() methods of your super activity you can increment and decrement the number of visible activites. Then in onStart() check if there was any currently visible activites. If no - app becomes active and you can call your method:
public class SuperActivity extends Activity {
private static int mVisibleActivitiesCount;
#Override
public void onStart(){
super.onStart();
if (mVisibleActivitiesCount == 0) {
onAppBecomesActive();
}
mVisibleActivitiesCount++;
}
#Override
public void onStop(){
super.onStart();
mVisibleActivitiesCount--;
}
private void onAppBecomesActive() {
// Do some staff
}
}
Open the androidManifest.xml from the Manifests Folder
Choose the Activity you want to open when app start
Add these codes to that Activity
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
Remember to removes this code from the activity in which its already present(usually MainActivity)
I have an Android application which sends some data to a webservice. I need to send this data as soon as the application is closed or sent to background.. But how do I accomplish this?
My current solution is to run it on the OnPause() on my home activity, but I need this to run no matter which activity the user is on when closing the app.. Is this possible or do I have to add the OnPause method to all activities?
Check this solution first https://stackoverflow.com/a/5862048/1037294 before you decide to use the code below!
To check if your application is sent to background, you can call this code on onPause() or onStop() on every activity in your application:
/**
* Checks if the application is being sent in the background (i.e behind
* another application's Activity).
*
* #param context the context
* #return <code>true</code> if another application will be above this one.
*/
public static boolean isApplicationSentToBackground(final Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(context.getPackageName())) {
return true;
}
}
return false;
}
For this to work you should include this in your AndroidManifest.xml
<uses-permission android:name="android.permission.GET_TASKS" />
This is the method that I used and it seems to work pretty well:
I have a top level Application class of my own that extends Application as such
public class MyApplication extends Application implements Application.ActivityLifecycleCallbacks {
You also need to register this Application object in your manifest file:
<application android:label="#string/app_name" android:icon="#drawable/ic_launcher" android:name=".MyApplication">
Notice how I also implement the ActivityLifeCycleCallbacks interface. This interface has the following methods:
public static interface ActivityLifecycleCallbacks {
void onActivityCreated(android.app.Activity activity, android.os.Bundle bundle);
void onActivityStarted(android.app.Activity activity);
void onActivityResumed(android.app.Activity activity);
void onActivityPaused(android.app.Activity activity);
void onActivityStopped(android.app.Activity activity);
void onActivitySaveInstanceState(android.app.Activity activity, android.os.Bundle bundle);
void onActivityDestroyed(android.app.Activity activity);
}
You need to implement those methods and then register for these events in your applications onCreate() as follows
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
This will then call the callback (the MyApplication object) whenever an activity lifecycle method happens such as onCreate(), onPause etc.
In your onActivityPaused() you can then check if the app was backgrounded or not by calling #peceps method : isApplicationSentToBackground(...)
This is what my code looks like then...
/**
* Application.ActivityLifecycleCallbacks methods
*/
#Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
try {
boolean foreground = new ForegroundCheckTask().execute(getApplicationContext()).get();
if(!foreground) {
//App is in Background - do what you want
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
Create a new class to go the Foreground checking (which is an async. task). See check android application is in foreground or not? for more.
class ForegroundCheckTask extends AsyncTask<Context, Void, Boolean> {
#Override
protected Boolean doInBackground(Context... params) {
final Context context = params[0];
return isAppOnForeground(context);
}
private boolean isAppOnForeground(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
if (appProcesses == null) {
return false;
}
final String packageName = context.getPackageName();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
return true;
}
}
return false;
}
}
Edit
This answer only serves for one purpose, that is, running a code in onPause() for all activities. It doesn't let you run a code when your app is sent to background.
Original Answer
Make an Activity named YourBasicActivity and override its onPause() method and extend every Activity from YourBasicActivity
Maybe this can be helpfull, tell me if it worked for you.
only when you return from background the value of activities would be 0 (zero)
the rest of the times would be a number higher than 0(zero) when the onRestart()
is executed.
public class FatherClass extends Activity {
private static int activities = 0;
public void onCreate(Bundle savedInstanceState, String clase) {
super.onCreate(savedInstanceState);
}
protected void onRestart()
{
super.onRestart();
if(activities == 0){
Log.i("APP","BACK FROM BACKGROUND");
}
}
protected void onStop(){
super.onStop();
activities = activities - 1;
}
protected void onStart(){
super.onStart();
activities = activities + 1;
}
}
All of your classes must extend from this class for this to work.
Explanation: The onStart is executed one the activity is "visible" and the onStop when the activity is "not visible". So when your APP (it says APP not activity) goes to background all the activities are "not visible" so they execute the onStop method, so the idea behind this is to ADD ONE each time an activity es started, and SUBTRACT ONE each time an activity es hided, so if the value of the variable "activities" is zero that means that all the activities that where started in some point are now not visible, so when you APP returns from background and executes the onRestart method on the activity in "front" you can check whether comes from background or is just restarting an activity.
you can use onAppForegroundStateChange() method which call when app is open and closed.this method is only called when your app comes in foreground/background.
onAppForegroundStateChange() method is better then you used onPause() method because onPause method is also called every time when you go to other activity.
you can use this method like that
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
AppForegroundStateManager.getInstance().addListener(this);
}
#Override
public void onAppForegroundStateChange(AppForegroundStateManager.AppForegroundState newState) {
if (AppForegroundStateManager.AppForegroundState.IN_FOREGROUND == newState) {
// App just entered the foreground. Do something here!
} else {
// App just entered the background. Do something here!
}
}
}
override the onStop() method of your Home activity and run the code there.
I think you need to run your own thread which will check whether all running activities in background or destroyed.
MyBasicActivity extends Activity
{
private static ArrayList<MyBasicActivity> activities=new ArrayList<MyBasicActivities);
private boolean started;
public void onCreate()
{
activities.add(this);
}
public void onDestroy()
{
activities.remove(this);
}
public void onStart()
{
this.started=true;
}
public void onPause()
{
this.started=false;
}
public boolean isStarted()
{
return started;
}
}
MyThread implements Runnable
{
private ArrayList<MyBasicActivity> activities;
public MyThread(ArrayList<MyBasicActivity> activities)
{
this.activities=activities;
}
void run()
{
while(!stopped)
{
boolean inBackground=true;
for(MyBasicActivity activity:activities)
{
if(activity.isStarted())
{
inBackground=false;
break;
}
}
if(inBackground)
//run your code here;
sleep(10000); //10 secs
}
}
}
If you are trying to submit/save data the user input, there are better ways to go about it than doing it when he tries to close the app. There are many ways to close an app. The user could even turn down the phone. So it's hard to take precautions against all of them.
I'd suggest you submit the data everytime the user stops writing, every any number of seconds or when he presses a button for example if your call to the webservice is too slow.
This way it's more safeproof and it's easier to implement.