Firebase 里显示了一个崩溃,是在 app 的代码调用 ApplicationPackageManager.getPackageInfo
进行数据查询的时候:“android.os.DeadSystemException”,“Package manager has died”。网上也有相关的分析,英文可以看这篇。看其中说,是因为跨进程交换的数据太大导致,而导致数据太大的原因,又往往是因为不止一个线程在同时调用。
app 里的正常逻辑显然是不应该出现同时并发调用的情况的,但我突然脑补了一种可能:功能入口按钮被快速重复点击。这是 Android 编程时的一个常见问题,在进行了验证测试后几个小时,果然 Firebase 里出现了该问题的新增计数。
如何避免重复点击带来的副作用,网上有好多现成代码,还有用 AspectJ 这种杀器自制注解的。老夫还是决定自己写一个小工具类,代码如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
public static class RepeatClickDetector { private static final long mTimeLimit = 1000; private final Map<Integer, Long> mTimeStamps = new HashMap<>(); private long mLastClickTime = 0; public RepeatClickDetector() { } public boolean detect() { return !beyondTimeLimit(); } // NOTE: the parameter 'cookie' could be a view id or anything else you want public boolean detect(int cookie) { return !beyondTimeLimit(cookie); } private boolean beyondTimeLimit() { long time = System.currentTimeMillis(); boolean b = mLastClickTime <= 0 || (time - mLastClickTime) > mTimeLimit; mLastClickTime = time; return b; } private boolean beyondTimeLimit(int cookie) { long time = System.currentTimeMillis(); Long lastClickTime = mTimeStamps.get(cookie); boolean b = lastClickTime == null || (time - lastClickTime) > mTimeLimit; mTimeStamps.put(cookie, time); return b; } } private final RepeatClickDetector rcd = new RepeatClickDetector(); public void onButtonClick(View view, int i) { if (rcd.detect()) return; ... } |
自评一句,那个带 cookie
参数的版本我没有测试,但那个参数本身我觉得设计的很棒,它使得一组按钮,既可以总体限速,也可以分别限速。1000ms 是个经验值,可能直觉上不应该有这么久,但事实就是如果时限短于 1 秒的话,效果会大打折扣。