-
-
Save steveliles/11116937 to your computer and use it in GitHub Desktop.
package com.sjl.util; | |
import android.app.Activity; | |
import android.app.Application; | |
import android.content.Context; | |
import android.os.Bundle; | |
import android.os.Handler; | |
import android.util.Log; | |
import java.util.List; | |
import java.util.concurrent.CopyOnWriteArrayList; | |
/** | |
* Usage: | |
* | |
* 1. Get the Foreground Singleton, passing a Context or Application object unless you | |
* are sure that the Singleton has definitely already been initialised elsewhere. | |
* | |
* 2.a) Perform a direct, synchronous check: Foreground.isForeground() / .isBackground() | |
* | |
* or | |
* | |
* 2.b) Register to be notified (useful in Service or other non-UI components): | |
* | |
* Foreground.Listener myListener = new Foreground.Listener(){ | |
* public void onBecameForeground(){ | |
* // ... whatever you want to do | |
* } | |
* public void onBecameBackground(){ | |
* // ... whatever you want to do | |
* } | |
* } | |
* | |
* public void onCreate(){ | |
* super.onCreate(); | |
* Foreground.get(this).addListener(listener); | |
* } | |
* | |
* public void onDestroy(){ | |
* super.onCreate(); | |
* Foreground.get(this).removeListener(listener); | |
* } | |
*/ | |
public class Foreground implements Application.ActivityLifecycleCallbacks { | |
public static final long CHECK_DELAY = 500; | |
public static final String TAG = Foreground.class.getName(); | |
public interface Listener { | |
public void onBecameForeground(); | |
public void onBecameBackground(); | |
} | |
private static Foreground instance; | |
private boolean foreground = false, paused = true; | |
private Handler handler = new Handler(); | |
private List<Listener> listeners = new CopyOnWriteArrayList<Listener>(); | |
private Runnable check; | |
/** | |
* Its not strictly necessary to use this method - _usually_ invoking | |
* get with a Context gives us a path to retrieve the Application and | |
* initialise, but sometimes (e.g. in test harness) the ApplicationContext | |
* is != the Application, and the docs make no guarantees. | |
* | |
* @param application | |
* @return an initialised Foreground instance | |
*/ | |
public static Foreground init(Application application){ | |
if (instance == null) { | |
instance = new Foreground(); | |
application.registerActivityLifecycleCallbacks(instance); | |
} | |
return instance; | |
} | |
public static Foreground get(Application application){ | |
if (instance == null) { | |
init(application); | |
} | |
return instance; | |
} | |
public static Foreground get(Context ctx){ | |
if (instance == null) { | |
Context appCtx = ctx.getApplicationContext(); | |
if (appCtx instanceof Application) { | |
init((Application)appCtx); | |
} | |
throw new IllegalStateException( | |
"Foreground is not initialised and " + | |
"cannot obtain the Application object"); | |
} | |
return instance; | |
} | |
public static Foreground get(){ | |
if (instance == null) { | |
throw new IllegalStateException( | |
"Foreground is not initialised - invoke " + | |
"at least once with parameterised init/get"); | |
} | |
return instance; | |
} | |
public boolean isForeground(){ | |
return foreground; | |
} | |
public boolean isBackground(){ | |
return !foreground; | |
} | |
public void addListener(Listener listener){ | |
listeners.add(listener); | |
} | |
public void removeListener(Listener listener){ | |
listeners.remove(listener); | |
} | |
@Override | |
public void onActivityResumed(Activity activity) { | |
paused = false; | |
boolean wasBackground = !foreground; | |
foreground = true; | |
if (check != null) | |
handler.removeCallbacks(check); | |
if (wasBackground){ | |
Log.i(TAG, "went foreground"); | |
for (Listener l : listeners) { | |
try { | |
l.onBecameForeground(); | |
} catch (Exception exc) { | |
Log.e(TAG, "Listener threw exception!", exc); | |
} | |
} | |
} else { | |
Log.i(TAG, "still foreground"); | |
} | |
} | |
@Override | |
public void onActivityPaused(Activity activity) { | |
paused = true; | |
if (check != null) | |
handler.removeCallbacks(check); | |
handler.postDelayed(check = new Runnable(){ | |
@Override | |
public void run() { | |
if (foreground && paused) { | |
foreground = false; | |
Log.i(TAG, "went background"); | |
for (Listener l : listeners) { | |
try { | |
l.onBecameBackground(); | |
} catch (Exception exc) { | |
Log.e(TAG, "Listener threw exception!", exc); | |
} | |
} | |
} else { | |
Log.i(TAG, "still foreground"); | |
} | |
} | |
}, CHECK_DELAY); | |
} | |
@Override | |
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {} | |
@Override | |
public void onActivityStarted(Activity activity) {} | |
@Override | |
public void onActivityStopped(Activity activity) {} | |
@Override | |
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {} | |
@Override | |
public void onActivityDestroyed(Activity activity) {} | |
} |
How to implement it in my app
Really useful. Thank you!
- download that file and add your project.
- create
Application
class see here - insert
Foreground.init(this);
toonCreate() of Application class
- call
Foreground.get().isForeground()
where you want.
You have to change private boolean foreground = false, paused = true;
to private boolean foreground = true, paused = false;
,
otherwise this wont work first time after you open app and put it to background.
Good job, mate! Thank you!
Good job. Thanks!
Doesn't work for hybrid applications such: Cordova, Unity, Nativescript, react Native
Thank you for you hard work. I had a nightmare trying to flag when I went Background to Foreground with crashes on resume with fragments.
This helps massively.
good , thanks
🙌
Fantastic
thanks a lot
@steveliles Thanks a lot! I have a question, If I use this source code in my commercial application then, Is there any license like a MIT, Apache something? Plz, let me know :)
I think we have some issues, When I request Permissions on my device, it's onBecameForeground and onBecameBackground
public class App extends Application implements Foreground.Listener {
@Override
public void onCreate(){
super.onCreate();
//ForeGround & Background
Foreground.init(this).addListener(this);
}
@Override
public void onBecameForeground() {
Log.d("Application","onBecameForeground");
}
@Override
public void onBecameBackground() {
Log.d("Application","onBecameBackground");
}
}
I think you can simplify it like this
public class AppLifecycleListener implements Application.ActivityLifecycleCallbacks {
private int numStarted;
private boolean isForeground;
@Override
public void onActivityStarted(Activity activity) {
if (numStarted == 0) {
isForeground = true;
}
numStarted++;
}
@Override
public void onActivityStopped(Activity activity) {
numStarted--;
if (numStarted == 0) {
isForeground = false;
}
}
}
you saved my day
Thanks @j796160836 for the solution, I had no idea why it was falling over :)
Forget that and just use ProcessLifecycleOwner from the Android Architecture Components. It's dead simple to use and it also handles when a permission dialog is displayed
class MyApplication : Application(), LifecycleObserver {
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onAppForegrounded() {
Log.d(TAG, "In foreground")
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onAppBackgrounded() {
Log.d(TAG, "In background")
}
}
It actually works. Great job!
Thanks lot
@hegazy Thank you!
@steveliles I leave this commit here because GitHub gist cannot send pull request.
Please check it out, thanks.