代码之家  ›  专栏  ›  技术社区  ›  fredley

为什么用android.os.CountDownTimer会得到“无法在未调用Looper.prepare()的线程内创建处理程序”?

  •  3
  • fredley  · 技术社区  · 14 年前

    在使用这个类时,我遇到了一个奇怪的异常。它是用来打印出一个不错的计时器显示我的游戏,并创建时,我的主要GameView类创建。在第26行抛出错误:super(s*10001000);

    package tommedley.android.game;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.drawable.Drawable;
    import android.os.CountDownTimer;
    
    public class Timer extends CountDownTimer{
        public static int MODE_COUNTING = 0;
        public static int MODE_PAUSED = 1;
        public static int MODE_FINISHED = 2;
    
        private Canvas canvas;
        private Context context;
        private float xPos;
        private float yPos;
        private static int DIGIT_WIDTH = 50;
        private static int DIGIT_HEIGHT = 70;
        private int numDigits = 3;
        private int seconds;
        Drawable[] digitImgs;
        private int mode;
    
    
        public Timer(Canvas c, Context con, float x, float y, int digits, int s){
            super(s*1000, 1000);
            mode = MODE_COUNTING;
            canvas = c;
            context = con;
            xPos = x;
            yPos = y;
            seconds = s;
            numDigits = digits;
            digitImgs = new Drawable[numDigits];
            this.start();
        }
        public void draw(){
            String reprNum = String.format("%0"+numDigits+"d", seconds);
            for(int i = 0;i<numDigits;i++){
                switch(reprNum.charAt(i)){
                case '0':
                    digitImgs[i] = context.getResources().getDrawable(R.drawable.digit_0);
                    break;
                case '1':
                    digitImgs[i] = context.getResources().getDrawable(R.drawable.digit_1);
                    break;
                case '2':
                    digitImgs[i] = context.getResources().getDrawable(R.drawable.digit_2);
                    break;
                case '3':
                    digitImgs[i] = context.getResources().getDrawable(R.drawable.digit_3);
                    break;
                case '4':
                    digitImgs[i] = context.getResources().getDrawable(R.drawable.digit_4);
                    break;
                case '5':
                    digitImgs[i] = context.getResources().getDrawable(R.drawable.digit_5);
                    break;
                case '6':
                    digitImgs[i] = context.getResources().getDrawable(R.drawable.digit_6);
                    break;
                case '7':
                    digitImgs[i] = context.getResources().getDrawable(R.drawable.digit_7);
                    break;
                case '8':
                    digitImgs[i] = context.getResources().getDrawable(R.drawable.digit_8);
                    break;
                case '9':
                    digitImgs[i] = context.getResources().getDrawable(R.drawable.digit_9);
                    break;
                }
                digitImgs[i].setBounds((int)xPos+DIGIT_WIDTH*i, (int)yPos, (int)xPos+DIGIT_WIDTH*(i+1), (int)yPos+DIGIT_HEIGHT);
                digitImgs[i].draw(canvas);
            }
        }
        @Override
        public void onFinish() {
            seconds = 0;
            mode = MODE_FINISHED;
        }
        @Override
        public void onTick(long millsLeft) {
            seconds = (int)millsLeft / 1000;
        }
        public int getMode(){
            return mode;
        }
    }
    
    1 回复  |  直到 14 年前
        1
  •  6
  •   Neil Traft    14 年前

    这有点奇怪——我想你一定是在主线程以外的线程上构造这个对象?

    我不知道你是否熟悉 Handlers Loopers ,但它们是Android在线程上执行异步操作的方式。如果要在线程上执行异步操作,可以使用处理程序来执行。但在使用处理程序之前,必须通过创建 MessageQueue Looper.prepare() .

    如果你看 the source 对于 CountDownTimer 类,您会注意到它创建了一个私有 Handler 实例。这个成员变量是在构造函数执行之前直接创建的,这就是调用 super .

    Looper.prepare() 在构造计时器之前。 ,如果在主线程上构造计时器,则不需要这样做。Android进程的主线程会自动声明为looper(如果 已经在主线程上调用了这个,并且仍然得到这个异常,那么这确实非常奇怪)。从稀疏的javadocs中我可以看出,这个类是要在主线程上使用的,所以我建议这样做。你的 onTick 方法似乎很轻,不值得额外增加线程的开销。