Activity 线程完成后不停止
Activity not stopping when finished froim thread
我有一个 Splashscreen,其中我是 运行 动画。以下是我关于从 初始屏幕 移动到 MainActivity
.
的逻辑
启动画面的最短可见时间 = minTime
启动画面的最长可见时间 = maxTime
API 被调用,它会在一段时间内得到响应 - apiTime
1. 显示 启动画面 至少 minTime
.
2. 呼叫 API
。如果 API 的响应在不到 maxtime
的时间内收到,
立即移动到下一个屏幕,否则,移动到下一个屏幕
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
在方法 hardMoveToNextScreen()
调用相同方法之前调用方法 moveToNextScreen()
。所以,一旦 activity 完成,我应该移动到 MainActivity
.
我面临的问题是 MainActivity
打开了两次。一次来自线程,然后来自 hardMoveToNextScreen()
方法。但是,这不应该发生,因为我已经在调用 finish()
,这意味着一旦我移动到 MainActivity
,就不应该再调用 SplashActivity
中的任何方法。
我做错了什么?
您正在调用 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;
}
}
所以首先我会告诉你发生这种情况的原因,然后我会继续解决这个问题。
原因:
即使在调用 onDestroy() 方法后,activity 实例仍保留在内存中。现在这并不意味着 activity 实例将永远保留在那里。它根据系统的内存要求由 Android OS 销毁。
这在这个答案中有很好的描述-
What is Activity.finish() method doing exactly?
在这一个里——
Activity instance remains in the memory after onDestroy()
(此外,Whosebug 上有很多描述完全相同的事情的答案。只需搜索即可)。
解决方案:
使用 returns 布尔值 isDestroyed() 方法检查是否调用了 activity 的 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();
}
}
我有一个 Splashscreen,其中我是 运行 动画。以下是我关于从 初始屏幕 移动到 MainActivity
.
启动画面的最短可见时间 = minTime
启动画面的最长可见时间 = maxTime
API 被调用,它会在一段时间内得到响应 - apiTime
1. 显示 启动画面 至少 minTime
.
2. 呼叫 API
。如果 API 的响应在不到 maxtime
的时间内收到,
立即移动到下一个屏幕,否则,移动到下一个屏幕
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
在方法 hardMoveToNextScreen()
调用相同方法之前调用方法 moveToNextScreen()
。所以,一旦 activity 完成,我应该移动到 MainActivity
.
我面临的问题是 MainActivity
打开了两次。一次来自线程,然后来自 hardMoveToNextScreen()
方法。但是,这不应该发生,因为我已经在调用 finish()
,这意味着一旦我移动到 MainActivity
,就不应该再调用 SplashActivity
中的任何方法。
我做错了什么?
您正在调用 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;
}
}
所以首先我会告诉你发生这种情况的原因,然后我会继续解决这个问题。
原因:
即使在调用 onDestroy() 方法后,activity 实例仍保留在内存中。现在这并不意味着 activity 实例将永远保留在那里。它根据系统的内存要求由 Android OS 销毁。 这在这个答案中有很好的描述- What is Activity.finish() method doing exactly? 在这一个里—— Activity instance remains in the memory after onDestroy() (此外,Whosebug 上有很多描述完全相同的事情的答案。只需搜索即可)。
解决方案:
使用 returns 布尔值 isDestroyed() 方法检查是否调用了 activity 的 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();
}
}