为什么在ActivityB中调用finish()后不会调用Activity A中的onDestroy方法?

6
下一个过程很容易理解和复制,但会导致一个bug:
  • activityA在其onCreate()方法中启动activityB
  • activityB被创建并且我在其onResume()方法中调用finish()
  • activityB的onDestroy()被调用
  • activityA的onResume()被调用
  • 在此,我在activityA中点击菜单按钮调用finish()-或按返回键。
  • activityA被移除,但onDestroy()未被调用,因此A仍然存在(adb shell dumpsys 'myPackageName'显示存在太多的活动)

代码

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="gleroy.com.algo">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        <activity
            android:name=".activity.MainActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>


        <activity
            android:name="gleroy.com.algo.activity.FakeA"
            android:label="@string/app_name"></activity>

        <activity
            android:name="gleroy.com.algo.activity.FakeB"
            android:label="@string/app_name"></activity>
    </application>
</manifest>

活动 A:

public class FakeA extends Activity {

    private final static String TAG = FakeA.class.getCanonicalName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "onCreate, taskId :" + getTaskId());
        super.onCreate(savedInstanceState);

        Intent intent = new Intent(FakeA.this, FakeB.class);
        startActivity(intent);
    }

    @Override
    protected void onResume() {
        Log.d(TAG, "onResume");
        super.onResume();
    }


    @Override
    protected void onDestroy() {
        Log.d(TAG, "onDestroy");
        super.onDestroy();
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        super.onCreateOptionsMenu(menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
            case R.id.stop_session_menu_item:
                /* stop and quit */
                finish();
                return false;
        }

        return super.onOptionsItemSelected(item);
    }
}

活动B:

public class FakeB extends Activity {

    private final static String TAG = FakeB.class.getCanonicalName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "onCreate, taskId :"+getTaskId());
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume, isFinishing :" + isFinishing());
        finish();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");
    }
}

Activity A是从包含一个简单按钮的MainActivity中启动的:

 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(MainActivity.this, FakeA.class);
            startActivity(intent);
        }
    });

我知道我们不能确定 onDestroy() 是否会被调用,但是这里我的 ActivityA 明显有内存泄漏。

我还观察到,如果我使用 TimerTimerTask 来延迟在 ActivityA 中的 startActivity 或在 ActivityB 中的 finish(),那么我就不再遇到这个 bug 了。

以下是事件列表:

  • FakeA onCreate,taskId:154
  • FakeA onResume
  • FakeA onPause,isFinishing:false
  • FakeB onCreate,taskId:154
  • FakeB onResume,isFinishing:false
  • FakeA onResume
  • FakeB onDestroy
  • 调用 finish 或按返回键:FakeA onPause,isFinishing:true

false或true并不会改变任何事情。 - gleroyDroid
在A.onResume()中调用startActivity(B)?那个奇怪的UX的目的是什么? - pskink
您的代码在onCreate()中启动了activityB,而不是在onResume()中。您想要哪一个? - initramfs
@user1570693 好的,这可能是你系统的问题,将 + isFinishing() 添加到 FakeA 的 onPause() 内部的 Log 里面,看它是否返回 true。 - Strider
我认为由于FakeB的onDestroy在FakeA的onResume()之后被调用,因此FakeA的onDestroy不会被调用。如果您设置延迟,则FakeA的onResume将在FakeB的onDestroy之后被调用,因此此时FakeA的onDestroy将被调用。 - keshav kowshik
显示剩余7条评论
2个回答

1
finish() 的位置尝试使用 finishAffinity()。 据我所知: finish() 只会销毁当前活动的 Activity, 而 finishAffinity() 则会销毁所有活动的 Activities

0

最好的解决方案就是检测是否有必要启动FakeB活动。


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