Android - 停止未恢复的活动

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26375920/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 11:19:47  来源:igfitidea点击:

Android - Performing stop of activity that is not resumed

androidandroid-activitybackgroundandroid-lifecycleonresume

提问by Salmaan

When I push my app to background, and do some other stuff like whatsapp or sms, onResume it works great.
But I recently discovered that when I open/launch facebook app while my app is on background, I don't know what happens...
But onResume, the app misbehaves...
Don't do what it is required to do, but when I go back to homepage and come back it works fine Please help me out.. how to fix it ???

当我将我的应用程序推送到后台,并执行其他一些操作(例如 whatsapp 或短信)时,onResume 效果很好。
但最近我发现,当我打开/推出的Facebook应用程序,而我的应用程序是在后台,我不知道会发生什么......
不过的onResume,该应用出现异常......
不要做它需要做的,但当我返回主页并返回时它工作正常请帮帮我..如何解决它???

Logcat with all messages (without filter)

带有所有消息的 Logcat(无过滤器)

10-15 12:53:59.899: I/Adreno-EGL(32033): Remote Branch: quic/LNX.LA.3.5.1_RB1.1
10-15 12:53:59.899: I/Adreno-EGL(32033): Local Patches: NONE
10-15 12:53:59.899: I/Adreno-EGL(32033): Reconstruct Branch: AU_LINUX_ANDROID_LNX.LA.3.5.1_RB1.04.04.02.048.018 + f2fd134 +  NOTHING
10-15 12:53:59.924: D/OpenGLRenderer(32033): Enabling debug mode 0
10-15 12:54:00.000: V/AlarmManager(7677): sending alarm Alarm{42cfa490 type 3 android}
10-15 12:54:00.110: I/ActivityManager(7677): Displayed uk.org.humanfocus.hfi/.EvaluateTrainingActivity: +838ms
10-15 12:54:00.114: D/WifiStateMachine(7677): handleMessage: E msg.what=151572
10-15 12:54:00.114: D/WifiStateMachine(7677): processMsg: ConnectedState
10-15 12:54:00.114: D/WifiStateMachine(7677): processMsg: L2ConnectedState
10-15 12:54:02.258: V/AlarmManager(7677): sending alarm Alarm{42ebd600 type 1 com.facebook.katana}
10-15 12:54:02.274: V/AlarmManager(7677): sending alarm Alarm{42ec0ff0 type 1 com.android.chrome}
10-15 12:54:02.428: D/hardware_info(7386): hw_info_append_hw_type : device_name = speaker
10-15 12:54:03.011: W/BroadcastQueue(7677): Permission Denial: broadcasting Intent { act=android.net.conn.INET_CONDITION_ACTION flg=0x4000010 (has extras) } from null (pid=-1, uid=-1) requires com.facebook.permission.prod.FB_APP_COMMUNICATION due to registered receiver BroadcastFilter{41fdecd0 u0 ReceiverList{42b2f608 31941 com.facebook.katana/10103/u0 remote:429a17e8}}
10-15 12:54:03.011: W/BroadcastQueue(7677): Permission Denial: broadcasting Intent { act=android.net.conn.CONNECTIVITY_CHANGE flg=0x4000010 (has extras) } from null (pid=-1, uid=-1) requires com.facebook.permission.prod.FB_APP_COMMUNICATION due to registered receiver BroadcastFilter{41fdecd0 u0 ReceiverList{42b2f608 31941 com.facebook.katana/10103/u0 remote:429a17e8}}
10-15 12:54:03.118: D/WifiStateMachine(7677): handleMessage: E msg.what=151572
10-15 12:54:03.118: D/WifiStateMachine(7677): processMsg: ConnectedState
10-15 12:54:03.118: D/WifiStateMachine(7677): processMsg: L2ConnectedState
10-15 12:54:03.140: D/WifiStateMachine(7677): handleMessage: X
10-15 12:54:03.141: D/GCoreFlp(8174): Unknown pending intent to remove.
10-15 12:54:03.145: W/fb4a(:<default>):AbstractMqttPushService(31941): Attempt to start service that is already started
10-15 12:54:03.242: D/WifiStateMachine(7677): handleMessage: E msg.what=131155
10-15 12:54:03.242: D/WifiStateMachine(7677): processMsg: ConnectedState
10-15 12:54:03.243: D/WifiStateMachine(7677): processMsg: L2ConnectedState
10-15 12:54:03.245: D/WifiStateMachine(7677): handleMessage: X
10-15 12:54:03.319: D/dalvikvm(31941): GC_CONCURRENT freed 1833K, 9% free 20190K/22072K, paused 5ms+7ms, total 86ms
10-15 12:54:03.320: D/dalvikvm(31941): WAIT_FOR_CONCURRENT_GC blocked 68ms
10-15 12:54:03.323: W/MediaPlayer-JNI(31941): MediaPlayer finalized without being released
10-15 12:54:03.452: W/BroadcastQueue(7677): Permission Denial: broadcasting Intent { act=android.net.conn.CONNECTIVITY_CHANGE flg=0x4000010 (has extras) } from null (pid=-1, uid=-1) requires com.facebook.permission.prod.FB_APP_COMMUNICATION due to registered receiver BroadcastFilter{42b51d68 u0 ReceiverList{429feb50 31941 com.facebook.katana/10103/u0 remote:41fb8788}}
10-15 12:54:03.573: W/fb4a(:<default>):HymanSON_FALLBACK(31941): Using com.fasterxml.Hymanson.databind.deser.std.EnumDeserializer@42914bc8 to deserialize [simple type, class com.facebook.common.util.TriState]
10-15 12:54:03.587: W/fb4a(:<default>):HymanSON_FALLBACK(31941): Using com.fasterxml.Hymanson.databind.deser.std.EnumDeserializer@42bb3100 to deserialize [simple type, class com.facebook.contacts.graphql.contactprofiletype.ContactProfileType]
10-15 12:54:03.957: D/dalvikvm(31941): GC_CONCURRENT freed 3400K, 15% free 20455K/23952K, paused 4ms+7ms, total 88ms
10-15 12:54:03.957: D/dalvikvm(31941): WAIT_FOR_CONCURRENT_GC blocked 75ms
10-15 12:54:04.099: W/fb4a(:<default>):HymanSON_FALLBACK(31941): Using BeanSerializer for com.facebook.katana.newbookmark.qe.NewBookmarkConfig to serialize class com.facebook.katana.newbookmark.qe.NewBookmarkConfig
10-15 12:54:04.119: D/WifiStateMachine(7677): handleMessage: E msg.what=151572
10-15 12:54:04.120: D/WifiStateMachine(7677): processMsg: ConnectedState
10-15 12:54:04.120: D/WifiStateMachine(7677): processMsg: L2ConnectedState
10-15 12:54:04.124: D/WifiStateMachine(7677): handleMessage: X
10-15 12:54:04.177: W/fb4a(:<default>):HymanSON_FALLBACK(31941): Using com.fasterxml.Hymanson.databind.deser.std.EnumDeserializer@42a30980 to deserialize [simple type, class com.facebook.platform.webdialogs.PlatformWebViewActionManifest$FetchState]
10-15 12:54:04.197: I/dalvikvm(31941): Could not find method com.android.internal.widget.ILockSettings$Stub.a, referenced from method com.facebook.keyguardtype.LockSettingsServiceKeyguardTypeResolver.b
10-15 12:54:04.197: W/dalvikvm(31941): VFY: unable to resolve static method 5338: Lcom/android/internal/widget/ILockSettings$Stub;.a (Landroid/os/IBinder;)Lcom/android/internal/widget/ILockSettings;
10-15 12:54:04.197: D/dalvikvm(31941): VFY: replacing opcode 0x71 at 0x0023
10-15 12:54:04.440: I/SBar.NetworkController(7758): onSignalStrengthsChanged SignalStrength: 19 0 -120 -160 -120 -1 -1 99 2147483647 2147483647 2147483647 2147483647 2147483647 gsm|lte 0 -108 -1 false 5 5 0 0 0 99 99 99 5 level=5
10-15 12:54:04.814: V/WebViewChromiumFactoryProvider(31941): Binding Chromium to main looper Looper (main, tid 1) {41f8cbd0}
10-15 12:54:04.815: I/LibraryLoader(31941): Expected native library version number "",actual native library version number ""
10-15 12:54:04.816: I/chromium(31941): [INFO:library_loader_hooks.cc(116)] Chromium logging enabled: level = 0, default verbosity = 0
10-15 12:54:04.817: I/BrowserStartupController(31941): Initializing chromium process, renderers=0
10-15 12:54:04.822: E/AudioManagerAndroid(31941): BLUETOOTH permission is missing!
10-15 12:54:04.864: W/chromium(31941): [WARNING:proxy_service.cc(890)] PAC support disabled because there is no system implementation
10-15 12:54:05.121: D/WifiStateMachine(7677): handleMessage: E msg.what=151572
10-15 12:54:05.121: D/WifiStateMachine(7677): processMsg: ConnectedState
10-15 12:54:05.122: D/WifiStateMachine(7677): processMsg: L2ConnectedState

And this is onResume()

这是 onResume()

super.onResume();

        if (backgroundThreadRunning == true) {
            backgroundThreadRunning = false;
        }

        if (Constants.isVideoEditing)
            editingProgress.setVisibility(View.VISIBLE);
        else
            editingProgress.setVisibility(View.GONE);

        if (Constants.isAudioProcessing)
            addAudioProgress.setVisibility(View.VISIBLE);
        else
            addAudioProgress.setVisibility(View.GONE);

        if (isHomeKeyPressed() && !(isRecentActivity)) {
            isRecentActivity = false;
            homeKeyPressed(false);
            AlertDialog.Builder ab = new AlertDialog.Builder(
                    CreateTrainingActivity.this);
            ab.setMessage(
                    "Due to Other Application Launches, video process will be cancelled!\nAre you sure you want to cancel?")
                    .setPositiveButton("Yes", dialogClickListener)
                    .setNegativeButton("No", dialogClickListener).show();
        }

    };

EDIT: HOW I FIXED THE ISSUE

编辑:我如何解决这个问题

I wrote this code in onResume()method

我在onResume()方法中 写了这段代码

try {
    // check if any view exists on current view
    style = ((Button) findViewById(R.id.xyz_button));   
} catch (Exception e) {
    // Button was not found
    // It means, your button doesn't exist on the "current" view
    // It was freed from the memory, therefore stop of activity was performed
    // In this case I restart my app
    Intent i = new Intent();
    i.setClass(getApplicationContext(), MainActivity.class);
    i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    startActivity(i);
    // Show toast to the user
    Toast.makeText(getApplicationContext(), "Data lost due to excess use of other apps", Toast.LENGTH_LONG).show();
}

采纳答案by HenriqueMS

Just giving my 50 cents on the issue. Catching the exception is indeed one possibility, but the correct way to deal with the issue of an activity being killed by the system for its resources in background is a common problem in android and according to Google the solution for this is:

在这个问题上只给我 50 美分。捕获异常确实是一种可能性,但是处理系统为其后台资源杀死活动的问题的正确方法是android中的常见问题,根据谷歌的解决方案是:

onPause() is where you deal with the user leaving your activity. Most importantly, any changes made by the user should at this point be committed(usually to the ContentProvider holding the data).

onPause() 是处理用户离开活动的地方。最重要的是,此时应该提交用户所做的任何更改(通常提交给持有数据的 ContentProvider)。

Emphasis is mine. But what this means is that the Android lifecycles are designed so that under normal conditions onPauseshould be called as an Activityor Fragmentis sent to the background. They hint at this in several of the android documentation pages:

重点是我的。但这意味着 Android 生命周期被设计为在正常情况下onPause应该被调用ActivityFragment发送到后台。他们在几个android 文档页面中暗示了这一点:

As your activity enters the paused state, the system calls the onPause() method on your Activity, which allows you to stop ongoing actions that should not continue while paused (such as a video) or persist any information that should be permanently saved in case the user continues to leave your app. If the user returns to your activity from the paused state, the system resumes it and calls the onResume() method.

当您的 Activity 进入暂停状态时,系统会调用您的 Activity 上的 onPause() 方法,该方法允许您停止暂停时不应继续的正在进行的操作(例如视频)或保留任何应永久保存的信息以备不时之需用户继续离开你的应用。如果用户从暂停状态返回到您的活动,系统将恢复它并调用 onResume() 方法。

Note: When your activity receives a call to onPause(), it may be an indication that the activity will be paused for a moment and the user may return focus to your activity. However, it's usually the first indication that the user is leaving your activity.

注意:当您的 Activity 收到对 onPause() 的调用时,这可能表示该 Activity 将暂停片刻,并且用户可能会将焦点返回到您的 Activity。但是,这通常是用户离开您的活动的第一个迹象。

But the resource that could most likely help you are these two:

但是最有可能帮助您的资源是这两个:

http://developer.android.com/training/basics/activity-lifecycle/stopping.html

http://developer.android.com/training/basics/activity-lifecycle/stopping.html

http://developer.android.com/training/basics/activity-lifecycle/recreating.html

http://developer.android.com/training/basics/activity-lifecycle/recreating.html

What's probably happening with your lost resources is this:

您丢失的资源可能发生的情况是:

When your activity receives a call to the onStop() method, it's no longer visible and should release almost all resources that aren't needed while the user is not using it. Once your activity is stopped, the system might destroy the instance if it needs to recover system memory. ... By default, the system uses the Bundle instance state to save information about each View object in your activity layout (such as the text value entered into an EditText object). So, if your activity instance is destroyed and recreated, the state of the layout is restored to its previous state with no code required by you. However, your activity might have more state information that you'd like to restore, such as member variables that track the user's progress in the activity.

当您的 Activity 收到对 onStop() 方法的调用时,它不再可见,并且应该会在用户不使用它时释放几乎所有不需要的资源。一旦您的活动停止,系统可能会在需要恢复系统内存时销毁实例。... 默认情况下,系统使用 Bundle 实例状态来保存有关活动布局中每个 View 对象的信息(例如输入到 EditText 对象中的文本值)。因此,如果您的 Activity 实例被销毁并重新创建,则布局的状态将恢复到其先前的状态,而您不需要任何代码。但是,您的活动可能有更多您想要恢复的状态信息,例如跟踪用户在活动中的进度的成员变量。

Note: In order for the Android system to restore the state of the views in your activity, each view must have a unique ID, supplied by the android:id attribute.

注意:为了让 Android 系统恢复您 Activity 中视图的状态,每个视图都必须有一个唯一的 ID,由 android:id 属性提供。

To save additional data about the activity state, you must override the onSaveInstanceState() callback method. The system calls this method when the user is leaving your activity and passes it the Bundle object that will be saved in the event that your activity is destroyed unexpectedly. If the system must recreate the activity instance later, it passes the same Bundle object to both the onRestoreInstanceState() and onCreate() methods.

要保存有关活动状态的其他数据,您必须覆盖 onSaveInstanceState() 回调方法。当用户离开您的 Activity 时,系统会调用此方法并将 Bundle 对象传递给它,该对象将在您的 Activity 意外销毁时保存。如果系统稍后必须重新创建活动实例,它会将相同的 Bundle 对象传递给 onRestoreInstanceState() 和 onCreate() 方法。

The correct solution for this is to override and implement the lifecycle methods of the Activity / Fragment as needed.

正确的解决方案是根据需要覆盖和实现 Activity / Fragment 的生命周期方法。

Two examples given by Google:

谷歌给出的两个例子:

    static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
...

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state
    savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
    savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);

    // Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(savedInstanceState);
}
Caution: Always call the superclass implementation of onSaveInstanceState() so the default implementation can save the state of the view hierarchy.

And the reverse restore operation:

和反向恢复操作:

public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState);

    // Restore state members from saved instance
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

回答by Whisky

One Line: It seems some of your activity variables were freed from memory as Android OS needed memory for the Facebook application.

一行:似乎您的某些活动变量已从内存中释放,因为 Android 操作系统需要 Facebook 应用程序的内存。

Explanation: When an application in foreground needs more memory than that is available, Android frees some memory from the apps that are running in background. Foreground tasks always have higher priority than background applications.

说明:当前台应用程序需要的内存超过可用内存时,Android 会从后台运行的应用程序中释放一些内存。前台任务总是比后台应用程序具有更高的优先级。

So, what might have happened to your application while it was in background is that some of its variables have lost their values which you are using in your onResume(). Because of this they are holding wrong values or default values (you can check by using Sysout) as they are re-created when you again bring your app to foreground and due to which some of your code is not working right.

因此,您的应用程序在后台运行时可能发生的情况是,它的某些变量丢失了您在 onResume() 中使用的值。因此,它们持有错误的值或默认值(您可以使用 Sysout 检查),因为它们会在您再次将应用程序置于前台时重新创建,因此您的某些代码无法正常工作。

回答by Diarrhio

Hopefully you've addressed the issue already, but there is an error in your code, perhaps related:

希望您已经解决了这个问题,但是您的代码中存在一个错误,可能与以下相关:

if (backgroundThreadRunning = true) {
    backgroundThreadRunning = false;
}

you are assigning instead of comparing in the "if" statement. Should be:

您正在分配而不是在“if”语句中进行比较。应该:

if (backgroundThreadRunning == true) {
    backgroundThreadRunning = false;
}

or

或者

if (backgroundThreadRunning) {
    backgroundThreadRunning = false;
}