Android定时器Chronometer切到后台,无法监听回调onChronometerTick解决方案

    技术2025-02-25  14

    关于定时器的使用,我就不过多介绍了。今天就讲一下关于定时器Chronometer的回调onChronometer方法的使用。

    在一些特殊场景中,我们使用定时器会有一定的限制;比如:

    倒计时

    Chronometer只能进行正计时,无法进行倒计时。但是想实现倒计时的需求该怎么做呢? 这时候就用到了onChronometer回调方法。 这个回调方法是在定时器在每次计时的时候都会回调的一个方法,具体用法如下:

    chronometer.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() { @Override public void onChronometerTick(Chronometer ch) { if(countDownNum>0){ countDownNum--; } chronometer.setText("00:00:"+countDownNum); } });

    我们只需要通过Chronometer的 setText 方法,再去定义一下我们需要倒计时的时间,具体实现逻辑自己随心,然后去设置我们需要显示的倒计时就可以了。

    问题

    这时候问题就来了。 当APP切到后台时候,再切回来时候,发现时间还是切出去时候的时间,这是为什么呢? 原来: 当APP进入后台时,会调用onWindowVisibilityChanged()方法,Chronometer回调的onChronometer方法是通过dispatchChronometerTick()方法进行回调的,但是在updateRunning()方法中有一个running变量,这个变量进行了一个是否在显示在前台判断,所以在后台时并不会调用dispatchChronometerTick()方法

    解决方案: 针对于需要在后台用到回调的场景,我的解决方案是这样的: 重写一个自定义View,将Chronometer中的几个必要方法复制过来,在将是否前台判断去掉即可;下面是我的代码:

    public class MyChronometer extends android.support.v7.widget.AppCompatTextView { private static final String TAG = "Chronometer"; public interface OnChronometerTickListener { void onChronometerTick(MyChronometer myChronometer); } private long mBase; private boolean mVisible; private boolean mStarted; private boolean mRunning; private boolean mLogged; private String mFormat; private Formatter mFormatter; private Locale mFormatterLocale; private Object[] mFormatterArgs = new Object[1]; private StringBuilder mFormatBuilder; private OnChronometerTickListener mOnChronometerTickListener; private StringBuilder mRecycle = new StringBuilder(8); private static final int TICK_WHAT = 2; public MyChronometer(Context context) { super(context); } public MyChronometer(Context context, AttributeSet attrs) { super(context, attrs); } public MyChronometer(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mBase = SystemClock.elapsedRealtime(); updateText(mBase); } public void setBase(long base) { mBase = base; dispatchChronometerTick(); updateText(SystemClock.elapsedRealtime()); } public long getBase() { return mBase; } public void setFormat(String format) { mFormat = format; if (format != null && mFormatBuilder == null) { mFormatBuilder = new StringBuilder(format.length() * 2); } } public String getFormat() { return mFormat; } public void setOnChronometerTickListener(OnChronometerTickListener listener) { mOnChronometerTickListener = listener; } public OnChronometerTickListener getOnChronometerTickListener() { return mOnChronometerTickListener; } public void start() { mStarted = true; updateRunning(); } public void stop() { mStarted = false; updateRunning(); } public void setStarted(boolean started) { mStarted = started; updateRunning(); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mVisible = false; updateRunning(); } @Override protected void onWindowVisibilityChanged(int visibility) { super.onWindowVisibilityChanged(visibility); updateRunning(); } private synchronized void updateText(long now) { long seconds = now - mBase; seconds /= 1000; String text = DateUtils.formatElapsedTime(mRecycle, seconds); if (mFormat != null) { Locale loc = Locale.getDefault(); if (mFormatter == null || !loc.equals(mFormatterLocale)) { mFormatterLocale = loc; mFormatter = new Formatter(mFormatBuilder, loc); } mFormatBuilder.setLength(0); mFormatterArgs[0] = text; try { mFormatter.format(mFormat, mFormatterArgs); text = mFormatBuilder.toString(); } catch (IllegalFormatException ex) { if (!mLogged) { Log.w(TAG, "Illegal format string: " + mFormat); mLogged = true; } } } setText(text); } private void updateRunning() { boolean running = mStarted; if (running != mRunning) { if (running) { updateText(SystemClock.elapsedRealtime()); dispatchChronometerTick(); mHandler.sendMessageDelayed(Message.obtain(mHandler, TICK_WHAT), 1000); } else { mHandler.removeMessages(TICK_WHAT); } mRunning = running; } } private Handler mHandler = new Handler() { public void handleMessage(Message m) { if (mRunning) { updateText(SystemClock.elapsedRealtime()); dispatchChronometerTick(); sendMessageDelayed(Message.obtain(this, TICK_WHAT), 1000); } } }; void dispatchChronometerTick() { if (mOnChronometerTickListener != null) { mOnChronometerTickListener.onChronometerTick(this); } } @SuppressLint("NewApi") @Override public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); event.setClassName(MyChronometer.class.getName()); } @SuppressLint("NewApi") @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); info.setClassName(MyChronometer.class.getName()); } }

    这样APP在后台的时候也可以收到onChronometerTick的回调了。

    Processed: 0.009, SQL: 9