从 Handler Runnable 更新 Destroyed Activity UI
Updating Destroyed Activity UI from Handler Runnable
以下代码更新 TextView 直到某个条件评估为 false,然后 Handler postDelayed 不再被调用。
但是,如果 activity 被销毁,它会尝试更新空 TextView,正确的处理方法是什么?我知道我可以对 TextView 进行防御性空检查,但这仍然不是真正的线程安全。
@Override
protected void onCreate(Bundle savedInstanceState) {
Handler durationHandler = new Handler();
durationHandler.postDelayed(updateSeekBarTime, 50);
}
private Runnable updateSeekBarTime = new Runnable() {
public void run() {
timeElapsed = mediaPlayer.getCurrentPosition();
double timeRemaining = finalTime - timeElapsed;
timeLeft.setText(String.format("%d", TimeUnit.MILLISECONDS.toSeconds((long) timeRemaining)));
if (timeRemaining >= 1000)
durationHandler.postDelayed(this, 200);
}
};
换句话说,updateSeekBarTime 可以在任何执行点尝试访问已销毁的 activity 的数据成员,如何防止这种情况发生?
在 onResume() 中启动您的处理程序。
在 onPause() 中用
停止处理程序
handler.removeCallbacksAndMessages(null); //null removes everything
我正在构建自己的音乐播放器应用程序并使用
durationHandler.removeCallbacks(updateSeekBarTime);
在 onStop() 中。它对我有用。
编辑:
上面这行是因为我使用
防止 Activity
被破坏
@Override
public void onBackPressed() {
moveTaskToBack(true);
}
这确保了 Activity 被最小化而不是被破坏,因此再次打开时,它非常活泼。
编辑 2:
private Runnable updateSeekBarTime = new MyRunnable();
private class MyRunnable extends Runnable {
private boolean dontWriteText = false;
@Override
public void run() {
timeElapsed = mediaPlayer.getCurrentPosition();
double timeRemaining = finalTime - timeElapsed;
if(!dontWriteText)
timeLeft.setText(String.format("%d", TimeUnit.MILLISECONDS.toSeconds((long) timeRemaining)));
if (timeRemaining >= 1000)
durationHandler.postDelayed(this, 200);
}
public void dontWriteText() {
dontWriteText = true;
}
};
然后在onDestroy() 或onStop() 中调用updateSeekBarTime.dontWriteText()。我更喜欢 onStop()。
所以在一些代码搜索和阅读博客之后,我在 Communicating with the UI Thread
的示例代码中找到了答案
尽管您可以而且应该从处理程序中删除回调:
handler.removeCallbacksAndMessages(null)
但是以上内容不会阻止现有的 运行 线程访问已销毁的 Activity 或其视图。
我一直在寻找的答案是 WeakReference。
Create a weak reference to the TextView or UI element that you'll
access. The weak reference prevents memory leaks and crashes, because
it automatically tracks the "state" of the variable it backs. If the
reference becomes invalid, the weak reference is garbage-collected.
This technique is important for referring to objects that are part of
a component lifecycle. Using a hard reference may cause memory leaks
as the value continues to change; even worse, it can cause crashes if
the underlying component is destroyed. Using a weak reference to a
View ensures that the reference is more transitory in nature.
您仍应检查 null 引用,但现在视图将被活动 thread/runnable 设置为 null 所以你不会面临竞争条件。
以下代码更新 TextView 直到某个条件评估为 false,然后 Handler postDelayed 不再被调用。
但是,如果 activity 被销毁,它会尝试更新空 TextView,正确的处理方法是什么?我知道我可以对 TextView 进行防御性空检查,但这仍然不是真正的线程安全。
@Override
protected void onCreate(Bundle savedInstanceState) {
Handler durationHandler = new Handler();
durationHandler.postDelayed(updateSeekBarTime, 50);
}
private Runnable updateSeekBarTime = new Runnable() {
public void run() {
timeElapsed = mediaPlayer.getCurrentPosition();
double timeRemaining = finalTime - timeElapsed;
timeLeft.setText(String.format("%d", TimeUnit.MILLISECONDS.toSeconds((long) timeRemaining)));
if (timeRemaining >= 1000)
durationHandler.postDelayed(this, 200);
}
};
换句话说,updateSeekBarTime 可以在任何执行点尝试访问已销毁的 activity 的数据成员,如何防止这种情况发生?
在 onResume() 中启动您的处理程序。 在 onPause() 中用
停止处理程序handler.removeCallbacksAndMessages(null); //null removes everything
我正在构建自己的音乐播放器应用程序并使用
durationHandler.removeCallbacks(updateSeekBarTime);
在 onStop() 中。它对我有用。
编辑:
上面这行是因为我使用
防止Activity
被破坏
@Override
public void onBackPressed() {
moveTaskToBack(true);
}
这确保了 Activity 被最小化而不是被破坏,因此再次打开时,它非常活泼。
编辑 2:
private Runnable updateSeekBarTime = new MyRunnable();
private class MyRunnable extends Runnable {
private boolean dontWriteText = false;
@Override
public void run() {
timeElapsed = mediaPlayer.getCurrentPosition();
double timeRemaining = finalTime - timeElapsed;
if(!dontWriteText)
timeLeft.setText(String.format("%d", TimeUnit.MILLISECONDS.toSeconds((long) timeRemaining)));
if (timeRemaining >= 1000)
durationHandler.postDelayed(this, 200);
}
public void dontWriteText() {
dontWriteText = true;
}
};
然后在onDestroy() 或onStop() 中调用updateSeekBarTime.dontWriteText()。我更喜欢 onStop()。
所以在一些代码搜索和阅读博客之后,我在 Communicating with the UI Thread
的示例代码中找到了答案尽管您可以而且应该从处理程序中删除回调:
handler.removeCallbacksAndMessages(null)
但是以上内容不会阻止现有的 运行 线程访问已销毁的 Activity 或其视图。
我一直在寻找的答案是 WeakReference。
Create a weak reference to the TextView or UI element that you'll access. The weak reference prevents memory leaks and crashes, because it automatically tracks the "state" of the variable it backs. If the reference becomes invalid, the weak reference is garbage-collected. This technique is important for referring to objects that are part of a component lifecycle. Using a hard reference may cause memory leaks as the value continues to change; even worse, it can cause crashes if the underlying component is destroyed. Using a weak reference to a View ensures that the reference is more transitory in nature.
您仍应检查 null 引用,但现在视图将被活动 thread/runnable 设置为 null 所以你不会面临竞争条件。