Android - 执行未恢复的活动的停止

40
当我把我的应用程序推到后台,并进行一些其他的操作,比如whatsapp或短信,然后在onResume时它能够正常工作。但是最近我发现,当我打开/启动facebook应用程序时,我的应用程序在后台运行时会出现问题... 在onResume时,应用程序表现不佳,没有执行所需的操作,但是当我返回主页并再次打开它时,它就可以正常工作了。请帮忙解决一下,该如何修复?日志记录器中包含所有消息(无过滤器)。
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>):JACKSON_FALLBACK(31941): Using com.fasterxml.jackson.databind.deser.std.EnumDeserializer@42914bc8 to deserialize [simple type, class com.facebook.common.util.TriState]
10-15 12:54:03.587: W/fb4a(:<default>):JACKSON_FALLBACK(31941): Using com.fasterxml.jackson.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>):JACKSON_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>):JACKSON_FALLBACK(31941): Using com.fasterxml.jackson.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

这是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();
        }

    };

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

我将这段代码写在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();
}
3个回答

28

一句话概括: 似乎由于Android操作系统需要为Facebook应用程序释放内存,导致您的某些活动变量被释放了。

解释: 当前台应用程序需要比可用内存更多的内存时,Android会从后台运行的应用程序中释放一些内存。前台任务始终比后台应用程序优先级更高。

因此,在您的应用程序处于后台运行时可能发生的情况是,其中一些变量已经失去了它们的值,而这些值是在onResume()方法中使用的。因为这些变量在再次将应用程序带到前台时重新创建,并且因此持有错误的值或默认值(您可以使用Sysout来检查),这就导致了一些代码无法正常工作。


3
那么我应该怎么做才能避免这个问题? - Salmaan
1
基本上,您需要检查哪个变量正在丢失其数据。然后,根据您的应用程序需求开发逻辑以存储该值,以便在onResume()中使用它。 - Whisky
@Whisky你能分享一些如何使用sysout进行检查的代码片段吗? - Ajay S
请使用sysout检查! 假设mVar是一个变量(比如字符串),它的值为“hello world”。 你可以输入:Log.d("Tag","Variable mVar value is: "+mVar +"!!!");这将打印出:Variable mVar value is: hello world!!! - Esmaeel Ibraheem

15

对于这个问题,我想发表自己的意见。捕获异常确实是一种可能的解决方法,但处理Android系统因为资源而杀死后台活动的问题的正确方式在安卓中很常见,并且据Google称,解决方案是:

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

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

当您的Activity进入已暂停状态时,系统会在您的Activity上调用 onPause() 方法,以便您停止在暂停期间不应继续的正在进行的操作(如视频),或者持久保存任何应该永久保存的信息,以防用户继续离开您的应用程序。如果用户从已暂停的状态返回您的Activity,系统将恢复它并调用 onResume() 方法。

注意:当您的Activity接收到 onPause() 的调用时,它可能是暂停一会儿,用户可能会重新聚焦到您的Activity。但通常它是用户正在离开您的Activity的第一个迹象。

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

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

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

您遇到的丢失资源的问题可能是这样的:

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

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

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

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

谷歌提供了两个示例:

    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.

以及反向还原操作:

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);
}

1
是的,这是我在处理类似问题后所理解的。 - Salmaan
1
感谢您提供详细的答案并深入探讨关键点,同时也感谢您提供代码示例。这非常有帮助。 - John Ward
@JohnWard 没问题,很高兴能帮到你 ;) - HenriqueMS

7
希望您已经解决了问题,但是您的代码存在错误,可能与以下相关:
if (backgroundThreadRunning = true) {
    backgroundThreadRunning = false;
}

您在 "if" 语句中使用了赋值而不是比较运算符。应该为:

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

或者
if (backgroundThreadRunning) {
    backgroundThreadRunning = false;
}

6
因为它最终会被设置为false,所以可以将backgroundThreadRunning设置为false。 - kareblak
1
据我所知,Android Studio(Lint)将此匹配标记为错误。不可能写成:if(a=b)... - CoolMind
1
@CoolMind 赋值表达式(a = b)的结果是a本身。由于此处的a是布尔类型,因此它可以工作。Java将其理解为if (赋值完成后的 a 本身) - Piovezan
@Piovezan,是的,你说得对,这对布尔值是正确的。 - CoolMind

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接