我试图写一个应用程序,做一些具体的时候,它被带回前台后一段时间。是否有一种方法可以检测应用程序是被发送到后台还是被带到前台?
当前回答
这些答案似乎不正确。当另一个活动开始和结束时,也会调用这些方法。你能做的是保留一个全局标志(是的,全局不好:),并在每次启动一个新活动时将其设置为true。在每个活动的onCreate中将其设置为false。然后,在onPause中检查这个标志。如果为假,你的应用就会进入后台,或者被杀死。
其他回答
这些答案似乎不正确。当另一个活动开始和结束时,也会调用这些方法。你能做的是保留一个全局标志(是的,全局不好:),并在每次启动一个新活动时将其设置为true。在每个活动的onCreate中将其设置为false。然后,在onPause中检查这个标志。如果为假,你的应用就会进入后台,或者被杀死。
这似乎是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页面。
考虑使用onUserLeaveHint。它只会在应用进入后台时被调用。onPause会有一些极端情况需要处理,因为它可以被用于其他原因;例如,如果用户在你的应用程序中打开另一个活动,比如你的设置页面,你的主活动的onPause方法将被调用,即使它们仍然在你的应用程序中;当你可以简单地使用onUserLeaveHint回调函数来做你所要求的事情时,跟踪正在进行的事情将导致错误。
当调用on UserLeaveHint时,你可以设置一个boolean inBackground标志为true。当onResume被调用时,如果inBackground标志被设置,只假设你回到前台。这是因为onResume也将被调用在你的主要活动,如果用户只是在你的设置菜单,从来没有离开应用程序。
Remember that if the user hits the home button while in your settings screen, onUserLeaveHint will be called in your settings activity, and when they return onResume will be called in your settings activity. If you only have this detection code in your main activity you will miss this use case. To have this code in all your activities without duplicating code, have an abstract activity class which extends Activity, and put your common code in it. Then each activity you have can extend this abstract activity.
例如:
public abstract AbstractActivity extends Activity {
private static boolean inBackground = false;
@Override
public void onResume() {
if (inBackground) {
// You just came from the background
inBackground = false;
}
else {
// You just returned from another activity within your own app
}
}
@Override
public void onUserLeaveHint() {
inBackground = true;
}
}
public abstract MainActivity extends AbstractActivity {
...
}
public abstract SettingsActivity extends AbstractActivity {
...
}
这是我的解决方案。只需在您的主Application类中注册这个ActivityLifecycleCallbacks。在评论中,我提到了一个用户配置文件活动边缘情况。该活动只是一个具有透明边缘的活动。
/**
* This class used Activity lifecycle callbacks to determine when the application goes to the
* background as well as when it is brought to the foreground.
*/
public class Foreground implements Application.ActivityLifecycleCallbacks
{
/**
* How long to wait before checking onStart()/onStop() count to determine if the app has been
* backgrounded.
*/
public static final long BACKGROUND_CHECK_DELAY_MS = 500;
private static Foreground sInstance;
private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
private boolean mIsForeground = false;
private int mCount;
public static void init(final Application application)
{
if (sInstance == null)
{
sInstance = new Foreground();
application.registerActivityLifecycleCallbacks(sInstance);
}
}
public static Foreground getInstance()
{
return sInstance;
}
public boolean isForeground()
{
return mIsForeground;
}
public boolean isBackground()
{
return !mIsForeground;
}
@Override
public void onActivityStarted(final Activity activity)
{
mCount++;
// Remove posted Runnables so any Meteor disconnect is cancelled if the user comes back to
// the app before it runs.
mMainThreadHandler.removeCallbacksAndMessages(null);
if (!mIsForeground)
{
mIsForeground = true;
}
}
@Override
public void onActivityStopped(final Activity activity)
{
mCount--;
// A transparent Activity like community user profile won't stop the Activity that launched
// it. If you launch another Activity from the user profile or hit the Android home button,
// there are two onStops(). One for the user profile and one for its parent. Remove any
// posted Runnables so we don't get two session ended events.
mMainThreadHandler.removeCallbacksAndMessages(null);
mMainThreadHandler.postDelayed(new Runnable()
{
@Override
public void run()
{
if (mCount == 0)
{
mIsForeground = false;
}
}
}, BACKGROUND_CHECK_DELAY_MS);
}
@Override
public void onActivityCreated(final Activity activity, final Bundle savedInstanceState)
{
}
@Override
public void onActivityResumed(final Activity activity)
{
}
@Override
public void onActivityPaused(final Activity activity)
{
}
@Override
public void onActivitySaveInstanceState(final Activity activity, final Bundle outState)
{
}
@Override
public void onActivityDestroyed(final Activity activity)
{
}
}
The principal problem is that you have to get an specific behavior when you start an activity from background. If you override your onPause() and onResume() methods, you'll have a close answer, but not the solution. The problem is that onPause() and onResume() methods are called even if you don't minimize your application, they can be called when you start an activity and later you press the back button to return to your activity. To eliminate that problem and to know really when your application comes from background, you must to get the running process and compare with your process:
private boolean isApplicationBroughtToBackground() {
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(getPackageName())) {
return true;
}
}
return false;
}
现在你必须声明一个布尔变量:
public boolean wasPaused = false;
并询问你的活动何时进入后台:
@Override
public void onPause(){
super.onPause();
if(isApplicationBroughtToBackground())
wasPaused = true;
}
现在,当你的活动再次出现在屏幕上时,在onResume()方法中询问:
@Override
public void onResume(){
super.onResume();
if(wasPaused){
lockScreen(true);
}
wasPaused = false;
}
就是这样。现在,当您的活动进入后台,稍后用户将其带到前台时,锁定屏幕将出现。
如果你想为你的应用程序的任何活动重复这个行为,你必须创建一个活动(可以是BaseActivity),放这个方法,你所有的活动都必须从BaseActivity继承。
我希望这对你有帮助。
问候!
推荐文章
- 警告:API ' variable . getjavacompile()'已过时,已被' variable . getjavacompileprovider()'取代
- 安装APK时出现错误
- 碎片中的onCreateOptionsMenu
- TextView粗体通过XML文件?
- 如何使线性布局的孩子之间的空间?
- DSL元素android.dataBinding。enabled'已过时,已被'android.buildFeatures.dataBinding'取代
- ConstraintLayout:以编程方式更改约束
- PANIC: AVD系统路径损坏。检查ANDROID_SDK_ROOT值
- 如何生成字符串类型的buildConfigField
- Recyclerview不调用onCreateViewHolder
- Android API 21工具栏填充
- Android L中不支持操作栏导航模式
- 如何在TextView中添加一个子弹符号?
- PreferenceManager getDefaultSharedPreferences在Android Q中已弃用
- 在Android Studio中创建aar文件