我有一个闪烁光标的自定义视图。我使用Handler
制作闪烁光标,并在500毫秒延迟后向其发布Runnable
。
当视图所在的活动时,我想通过删除处理程序上的回调来停止闪烁。但是,我注意到当我切换到另一个应用程序时,处理程序/ runnable继续运行,即日志显示它仍在闪烁。
如果我控制了视图,我会做this
之类的操作@Override
protected void onPause() {
handler.removeCallbacks(runnable);
super.onPause();
}
但我的自定义视图将成为图书馆的一部分,因此我无法控制其他开发者使用我的自定义视图的活动。
我尝试了onFocusChanged
,onScreenStateChanged
和onDetachedFromWindow
,但当用户切换到其他应用时,这些都不起作用。
这是我的代码。我通过删除与问题无关的任何内容来简化它。
public class MyCustomView extends View {
static final int BLINK = 500;
private Handler mBlinkHandler;
private void init() {
// ...
mBlinkHandler = new Handler();
mTextStorage.setOnChangeListener(new MongolTextStorage.OnChangeListener() {
@Override
public void onTextChanged(/*...*/) {
// ...
startBlinking();
}
});
}
Runnable mBlink = new Runnable() {
@Override
public void run() {
mBlinkHandler.removeCallbacks(mBlink);
if (shouldBlink()) {
// ...
Log.i("TAG", "Still blinking...");
mBlinkHandler.postDelayed(mBlink, BLINK);
}
}
};
private boolean shouldBlink() {
if (!mCursorVisible || !isFocused()) return false;
final int start = getSelectionStart();
if (start < 0) return false;
final int end = getSelectionEnd();
if (end < 0) return false;
return start == end;
}
void startBlinking() {
mBlink.run();
}
void stopBlinking() {
mBlinkHandler.removeCallbacks(mBlink);
}
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
if (focused) {
startBlinking();
} else {
stopBlinking();
}
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
@Override
public void onScreenStateChanged(int screenState) {
switch (screenState) {
case View.SCREEN_STATE_ON:
startBlinking();
break;
case View.SCREEN_STATE_OFF:
stopBlinking();
break;
}
}
public void onAttachedToWindow() {
super.onAttachedToWindow();
startBlinking();
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
stopBlinking();
}
}
答案 0 :(得分:0)
我猜你是使用thread.run()分别启动线程,而只是创建一个方法并递归调用它像这样:
public void blink(){
mBlinkHandler.postDelayed(mBlink, BLINK);
}
在runnable中:
Runnable mBlink = new Runnable() {
@Override
public void run() {
mBlinkHandler.removeCallbacks(mBlink);
if (shouldBlink()) {
// ...
Log.i("TAG", "Still blinking...");
blink();
}
}
};
当您使用run方法直接启动线程时。所以它不会因删除回调而停止。
希望这有帮助。
答案 1 :(得分:0)
我在评论中遵循@ pskink的建议解决了问题,并调整了Android 1.6的代码。这可能是Android的旧版本,但闪烁的光标部分适用于我的目的。覆盖onWindowFocusChanged
是关键。
我的full code在GitHub上。以下是相关部分:
public class MyCustomView extends View {
private boolean mCursorVisible = true;
private Blink mBlink;
private long mShowCursor; // cursor blink timing based on system clock
static final int BLINK = 500;
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
mShowCursor = SystemClock.uptimeMillis();
if (focused) {
makeBlink();
}
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
@Override
protected void onDraw(Canvas canvas) {
int start = getSelectionStart();
int end = getSelectionEnd();
// draw the blinking cursor on top
if (start == end && blinkShouldBeOn()) {
canvas.drawRect(getCursorPath(start), mCursorPaint);
}
}
private boolean blinkShouldBeOn() {
if (!mCursorVisible || !isFocused()) return false;
return (SystemClock.uptimeMillis() - mShowCursor) % (2 * BLINK) < BLINK;
}
private void makeBlink() {
if (!mCursorVisible) {
if (mBlink != null) {
mBlink.removeCallbacks(mBlink);
}
return;
}
if (mBlink == null)
mBlink = new Blink(this);
mBlink.removeCallbacks(mBlink);
mBlink.postAtTime(mBlink, mShowCursor + BLINK);
}
public void setCursorVisible(boolean visible) {
mCursorVisible = visible;
invalidateCursorPath();
if (visible) {
makeBlink();
} else if (mBlink != null) {
mBlink.removeCallbacks(mBlink);
}
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if (hasWindowFocus) {
if (mBlink != null) {
mBlink.uncancel();
if (isFocused()) {
mShowCursor = SystemClock.uptimeMillis();
makeBlink();
}
}
} else {
if (mBlink != null) {
mBlink.cancel();
}
hideSystemKeyboard();
}
}
private static class Blink extends Handler implements Runnable {
private WeakReference<MongolEditText> mView;
private boolean mCancelled;
Blink(MongolEditText v) {
mView = new WeakReference<>(v);
}
public void run() {
if (mCancelled) {
return;
}
removeCallbacks(Blink.this);
MongolEditText met = mView.get();
if (met != null && met.isFocused()) {
int st = met.getSelectionStart();
int en = met.getSelectionEnd();
if (st == en && st >= 0 && en >= 0) {
if (met.mLayout != null) {
met.invalidateCursorPath();
}
postAtTime(this, SystemClock.uptimeMillis() + BLINK);
}
}
}
void cancel() {
if (!mCancelled) {
removeCallbacks(Blink.this);
mCancelled = true;
}
}
void uncancel() {
mCancelled = false;
}
}
}