【问题标题】:Activity not stopping when finished froim thread从线程完成后活动没有停止
【发布时间】:2020-06-02 14:40:36
【问题描述】:

我有一个正在运行动画的启动画面。以下是我关于从 启动画面 移动到 MainActivity 的逻辑。

启动画面的最短可见时间 = minTime

闪屏的最长可见时间 = maxTime

调用 API 并在一段时间内获得响应 - apiTime

1.至少为minTime显示启动画面

2. 致电API。如果在不到maxtime 内收到 API 的响应, 立即移动到下一个屏幕,否则,移动到下一个屏幕 maxtime

以下是我的代码:

public class SplashActivity extends AppCompatActivity {

private ImageView container;
private AnimationDrawable animationDrawable;
int apiTime = 2000, minTime = 1000, maxTime = 5000;

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

    container = findViewById(R.id.iv_icons);
    container.setBackgroundResource(R.drawable.splash_animation);

    animationDrawable = (AnimationDrawable) container.getBackground();
}

@Override
protected void onResume() {
    super.onResume();
    animationDrawable.start();
    final long start = System.currentTimeMillis();

    //calling api in thread simultaneously. As soon as response is received, move to next screen.
    //Thread.sleep is just dummy for api response time
    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(apiTime);
                //if apiTime is less than minTime, then we wait till minTime
                long time = minTime - (System.currentTimeMillis() - start);
                if (time > 0) {
                    Thread.sleep(time);
                }
                moveToNextScreen();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    t1.start();

    hardMoveToNextScreen();
}

private void moveToNextScreen() {
    Intent i = new Intent(SplashActivity.this, MainActivity.class);
    startActivity(i);
    finish();
}

private void hardMoveToNextScreen () {
    Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            moveToNextScreen();
        }
    }, maxTime);
}

}

现在,根据我使用的时间值,线程t1 调用方法moveToNextScreen() 之前方法hardMoveToNextScreen() 调用相同的方法。所以,一旦活动结束,我应该转移到MainActivity

我面临的问题是MainActivity 正在打开两次。一次来自线程,然后来自hardMoveToNextScreen() 方法。但是,这不应该发生,因为我已经在调用 finish(),这意味着一旦我移至 MainActivity,就不应再调用来自 SplashActivity 的任何方法。

我做错了什么?

【问题讨论】:

  • 你能用 if(!isFinishing) 来调节你的方法吗?这可能会确保其中任何一个方法都不会执行。

标签: android multithreading android-intent splash-screen


【解决方案1】:

所以首先我会告诉你发生这种情况的原因,然后我会继续解决这个问题。

原因:

即使调用了 onDestroy() 方法,活动实例仍保留在内存中。现在这并不意味着活动实例将永远保留在那里。它是由 Android 操作系统根据系统的内存需求销毁的。 这个答案很好地描述了这一点- What is Activity.finish() method doing exactly? 在这个也是 - Activity instance remains in the memory after onDestroy() (此外,* 上有很多答案描述了完全相同的事情。只需搜索即可)。

解决方案:

使用 isDestroyed() 方法返回一个布尔值来检查活动的 onDestroy() 方法是否被调用。你可以在这里找到它的文档 - https://developer.android.com/reference/android/app/Activity.html#isDestroyed%28%29

所以 moveToNextScreen() 方法现在应该看起来像这样 -

private void moveToNextScreen() {
    if (!isDestroyed()) {
        Intent i = new Intent(SplashActivity.this, MainActivity.class);
        startActivity(i);
        finish();
    }
}

【讨论】:

  • 我已经在我的机器上亲自执行了这段代码,它运行良好,并且只创建了一个 MainActivity 实例,正如您所要求的那样
【解决方案2】:

您正在调用 moveToNextScreen() 两次。第一次在线程中,第二次在 hardMoveToNextScreen() 中。

如果你删除了 hardMoveToNextScreen();在 t1.start() 之后;它应该适合你。

或者更好的选择是删除 Thread 并使用带有处理程序的 hardMoveToNextScreen() 方法。

更新答案:

如果要保持双重逻辑声明全局变量:

private boolean activityFinished = false;

然后将 moveToNextScreen() 方法更改为:

private void moveToNextScreen() {
    if( !activityFinished ) {
        Intent i = new Intent( SplashActivity.this, MainActivity.class );
        startActivity( i );
        finish();
        activityFinished = true;
    }
}

【讨论】:

  • 是的,我知道我调用 moveToNextScreen() 两次。这正是我需要做的。我只想调用 Thread 或 hardMoveToNextScreen() 中的一种方法。这应该是我最终从两个地方调用完成的情况,所以无论首先执行什么,都应该完成 SplashActivity
  • 我已将您的代码复制到我的项目中并进行了一些双重检查。在线程和处理程序中的 moveToNextScreen() 上放置断点,并在 startActivity(i) 方法上放置另一个断点。运行debug,你会看到startActivity被调用了两次。
  • 我知道它被调用了两次。这就是问题所在!
  • 嗯好吧,我没有清楚地理解你想要保留这两个逻辑。请检查更新的答案。这应该适合你。