CountDownTimer 导致的一个崩溃 (Can't create handler inside thread that has not called Looper.prepare())

来源:互联网 发布:网络社会案例分析 编辑:程序博客网 时间:2024/05/18 01:25
Section1  现象
new Thread(new Runnable() {    @Override    public void run() {        new CountDownTimer(10000, 1000) {            @Override            public void onTick(long l) {            }            @Override            public void onFinish() {            }        }.start();    }

}).start();

以上代码会导致:

 java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

====================================================

Section2 原因

原因:查看CountDonwTimer的源码的最后面我们可以看到:

    // handles counting down    private Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            synchronized (CountDownTimer.this) {                if (mCancelled) {                    return;                }                final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();                if (millisLeft <= 0) {                    onFinish();                } else if (millisLeft < mCountdownInterval) {                    // no tick, just delay until done                    sendMessageDelayed(obtainMessage(MSG), millisLeft);                } else {                    long lastTickStart = SystemClock.elapsedRealtime();                    onTick(millisLeft);                    // take into account user's onTick taking time to execute                    long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();                    // special case: user's onTick took more than interval to                    // complete, skip to next interval                    while (delay < 0) delay += mCountdownInterval;                    sendMessageDelayed(obtainMessage(MSG), delay);                }            }        }    };}
也就是说CountDownTimer 内部有一个随着对象初始化的成员变量handler,所以如果在没有Looper Prepare 的线程new 一个 CountDownTimer ,自然会有上述错误。
Section3 回调线程
===================================
测试回调线程
new CountDownTimer(5000, 1000) {    @Override    public void onTick(long l) {        Log.i("MainActivity","l==>"+l+"ThreadName==>"+Thread.currentThread().getName());    }    @Override    public void onFinish() {        Log.i("MainActivity","finish==>"+"ThreadName==>"+Thread.currentThread().getName());    }}.start();

打印结果如下:
12-14 10:52:34.504 3824-3824/com.example.administrator.myapplication I/MainActivity: l==>4935ThreadName==>main12-14 10:52:35.504 3824-3824/com.example.administrator.myapplication I/MainActivity: l==>3935ThreadName==>main12-14 10:52:36.505 3824-3824/com.example.administrator.myapplication I/MainActivity: l==>2933ThreadName==>main12-14 10:52:37.506 3824-3824/com.example.administrator.myapplication I/MainActivity: l==>1932ThreadName==>main12-14 10:52:39.439 3824-3824/com.example.administrator.myapplication I/MainActivity: finish==>ThreadName==>main
结论
==================================================================================
我们做出如下结论:
1.CountDownTimer 内部有new Handler 的逻辑,所以需要在主线程或者在Looper prepare 之后的线程中调用
2.CountDownTimer 的回调最终也是在其调用线程。


后记

这个破bug,耽误了我好几个小时,

updateExperimentResult()  这个方法回调会在子线程,而我在回调里面开了timer,但是开timer这个地方又有别的地方会调用。。
所以我一直以为是别地地方的问题。。。
改别人的代码,真是坑。。。。。。


这种问题,单看的时候比较简单,但是当和各种其他问题交杂在一块的时候,就不是那么容易发现的了

阅读全文
0 0
原创粉丝点击