我试图写一个应用程序,做一些具体的时候,它被带回前台后一段时间。是否有一种方法可以检测应用程序是被发送到后台还是被带到前台?
当前回答
这似乎是Android中最复杂的问题之一,因为(在撰写本文时)Android没有iOS中等效的applicationDidEnterBackground()或applicationwillenter前台()回调。我使用了一个由@jenzz组合的AppState库。
[AppState]是一个基于RxJava的简单的响应式Android库,用于监控应用程序状态的变化。每当应用程序进入后台并返回前台时,它都会通知订阅者。
事实证明,这正是我所需要的,特别是因为我的应用程序有多个活动,所以简单地检查onStart()或onStop()对一个活动不会削减它。
首先,我将这些依赖项添加到gradle:
dependencies {
compile 'com.jenzz.appstate:appstate:3.0.1'
compile 'com.jenzz.appstate:adapter-rxjava2:3.0.1'
}
然后,将这些行添加到代码中适当的位置就很简单了:
//Note that this uses RxJava 2.x adapter. Check the referenced github site for other ways of using observable
Observable<AppState> appState = RxAppStateMonitor.monitor(myApplication);
//where myApplication is a subclass of android.app.Application
appState.subscribe(new Consumer<AppState>() {
@Override
public void accept(@io.reactivex.annotations.NonNull AppState appState) throws Exception {
switch (appState) {
case FOREGROUND:
Log.i("info","App entered foreground");
break;
case BACKGROUND:
Log.i("info","App entered background");
break;
}
}
});
根据你订阅可观察对象的方式,你可能不得不取消订阅以避免内存泄漏。更多信息再次在github页面。
其他回答
My app needs to "reboot" after return from background - show a series of activities, according to client solicitations. After extensive search on how to manage the background/foreground transitions (treated very differently between iOS and Android), I crossed this question. Found very useful help here, specially from the most voted answer and the one flagged as correct. However, simply reinstantiate the root activity EVERY TIME the app enters foreground looked too annoying, when you think about UX. The solution that worked for me, and the one I think's most adequated - based on the Youtube and Twitter apps functionality - was to combine the answers from @GirishNair and @d60402: Calling the timer when the app's trimming memory, as follows:
@Override
public void onTrimMemory(int level) {
if (stateOfLifeCycle.equals("Stop")) {
startActivityTransitionTimer();
}
super.onTrimMemory(level);
}
我的定时器限制设置为30秒-我正在考虑增加一点。
private final long MAX_ACTIVITY_TRANSITION_TIME = 30000;
当app进入前台,重新启动,或者app被销毁时,调用方法取消定时器。
在应用程序扩展:
@Override
public void onActivityCreated(Activity activity, Bundle arg1) {
stopActivityTransitionTimer();
stateOfLifeCycle = "Create";
}
@Override
public void onActivityDestroyed(Activity activity) {
stopActivityTransitionTimer();
stateOfLifeCycle = "Destroy";
}
在活动上(最好是在一个基础活动上,由其他活动继承):
@Override
protected void onStart() {
super.onStart();
if (App.wasInBackground) {
stopActivityTransitionTimer();
}
}
在我的情况下,当应用程序在最大时间后进入前台时,会创建一个新任务,因此stopActivityTransitionTimer()在onActivityCreated()或onActivityDestroyed()上被调用,在应用程序扩展类中-转向不必要调用活动中的方法。 希望能有所帮助。
我们用这个方法。它看起来太简单了,但它在我们的应用程序中经过了良好的测试,实际上在所有情况下都运行得非常好,包括通过“home”按钮进入主屏幕,通过“返回”按钮,或在屏幕锁定后返回主屏幕。试一试。
想法是,当在前景,Android总是开始新的活动之前停止前一个。这并不能保证,但这就是它的工作原理。顺便说一句,Flurry似乎使用了同样的逻辑(只是猜测,我没有检查,但它在相同的事件中挂钩)。
public abstract class BaseActivity extends Activity {
private static int sessionDepth = 0;
@Override
protected void onStart() {
super.onStart();
sessionDepth++;
if(sessionDepth == 1){
//app came to foreground;
}
}
@Override
protected void onStop() {
super.onStop();
if (sessionDepth > 0)
sessionDepth--;
if (sessionDepth == 0) {
// app went to background
}
}
}
编辑:根据注释,我们也移动到onStart()在以后的版本的代码。此外,我还添加了超级调用,这是我最初的文章中所没有的,因为这更像是一个概念,而不是一个工作代码。
这是@d60402回答的修改版本:https://stackoverflow.com/a/15573121/4747587
按照上面提到的去做。但是,与其有一个Base Activity,并将其作为每个活动的父活动,并重写onResume()和onPause,不如执行以下操作:
在你的应用程序类中,添加这样一行:
registerActivityLifecycleCallbacks(应用程序。ActivityLifecycleCallbacks回调);
这个回调有所有的活动生命周期方法,你现在可以覆盖onactivityresume()和onActivityPaused()。
看看这个Gist: https://gist.github.com/thsaravana/1fa576b6af9fc8fff20acfb2ac79fa1b
我发现了一个很好的方法来检测应用程序是否进入前台或后台。 这是我的代码。 希望这对你有帮助。
/**
* Custom Application which can detect application state of whether it enter
* background or enter foreground.
*
* @reference http://www.vardhan-justlikethat.blogspot.sg/2014/02/android-solution-to-detect-when-android.html
*/
public abstract class StatusApplication extends Application implements ActivityLifecycleCallbacks {
public static final int STATE_UNKNOWN = 0x00;
public static final int STATE_CREATED = 0x01;
public static final int STATE_STARTED = 0x02;
public static final int STATE_RESUMED = 0x03;
public static final int STATE_PAUSED = 0x04;
public static final int STATE_STOPPED = 0x05;
public static final int STATE_DESTROYED = 0x06;
private static final int FLAG_STATE_FOREGROUND = -1;
private static final int FLAG_STATE_BACKGROUND = -2;
private int mCurrentState = STATE_UNKNOWN;
private int mStateFlag = FLAG_STATE_BACKGROUND;
@Override
public void onCreate() {
super.onCreate();
mCurrentState = STATE_UNKNOWN;
registerActivityLifecycleCallbacks(this);
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
// mCurrentState = STATE_CREATED;
}
@Override
public void onActivityStarted(Activity activity) {
if (mCurrentState == STATE_UNKNOWN || mCurrentState == STATE_STOPPED) {
if (mStateFlag == FLAG_STATE_BACKGROUND) {
applicationWillEnterForeground();
mStateFlag = FLAG_STATE_FOREGROUND;
}
}
mCurrentState = STATE_STARTED;
}
@Override
public void onActivityResumed(Activity activity) {
mCurrentState = STATE_RESUMED;
}
@Override
public void onActivityPaused(Activity activity) {
mCurrentState = STATE_PAUSED;
}
@Override
public void onActivityStopped(Activity activity) {
mCurrentState = STATE_STOPPED;
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
mCurrentState = STATE_DESTROYED;
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
if (mCurrentState == STATE_STOPPED && level >= TRIM_MEMORY_UI_HIDDEN) {
if (mStateFlag == FLAG_STATE_FOREGROUND) {
applicationDidEnterBackground();
mStateFlag = FLAG_STATE_BACKGROUND;
}
}else if (mCurrentState == STATE_DESTROYED && level >= TRIM_MEMORY_UI_HIDDEN) {
if (mStateFlag == FLAG_STATE_FOREGROUND) {
applicationDidDestroyed();
mStateFlag = FLAG_STATE_BACKGROUND;
}
}
}
/**
* The method be called when the application been destroyed. But when the
* device screen off,this method will not invoked.
*/
protected abstract void applicationDidDestroyed();
/**
* The method be called when the application enter background. But when the
* device screen off,this method will not invoked.
*/
protected abstract void applicationDidEnterBackground();
/**
* The method be called when the application enter foreground.
*/
protected abstract void applicationWillEnterForeground();
}
我的解决方案受到@d60402的答案的启发,也依赖于一个时间窗口,但不使用定时器:
public abstract class BaseActivity extends ActionBarActivity {
protected boolean wasInBackground = false;
@Override
protected void onStart() {
super.onStart();
wasInBackground = getApp().isInBackground;
getApp().isInBackground = false;
getApp().lastForegroundTransition = System.currentTimeMillis();
}
@Override
protected void onStop() {
super.onStop();
if( 1500 < System.currentTimeMillis() - getApp().lastForegroundTransition )
getApp().isInBackground = true;
}
protected SingletonApplication getApp(){
return (SingletonApplication)getApplication();
}
}
其中SingletonApplication是Application类的扩展:
public class SingletonApplication extends Application {
public boolean isInBackground = false;
public long lastForegroundTransition = 0;
}
推荐文章
- 如何隐藏动作栏之前的活动被创建,然后再显示它?
- 是否有一种方法以编程方式滚动滚动视图到特定的编辑文本?
- 在Android中将字符串转换为Uri
- 如何在NestedScrollView内使用RecyclerView ?
- 移动到另一个EditText时,软键盘下一步点击Android
- Android应用中的GridView VS GridLayout
- Activity和FragmentActivity的区别
- 右对齐文本在android TextView
- 权限拒绝:start前台需要android.permission.FOREGROUND_SERVICE
- 如何更改android操作栏的标题和图标
- Android Split字符串
- 让一个链接在安卓浏览器启动我的应用程序?
- 如何在Android工作室的外部库中添加一个jar ?
- GridLayout(不是GridView)如何均匀地拉伸所有子元素
- 如何让一个片段删除自己,即它的等效完成()?