Search code examples
androidandroid-progressbarondraw

ProgressBar causing constant onDraw calls for all the UI


I have an activity which has a ProgressBar. This bar is used to show the elapsed time on the game level.

I'm updating this bar and a TextView with a CountdownTimer, called every 100ms. The problem is that every time I call setProgress, it seems to be causing an invalidate() that makes my whole UI to be redrawn. If I delete the line where the ProgressBar get updated everything works fine, even setText for the TextView that show the time left.

This is a problem for me because I also have a custom view which needs to be redrawn only when I need it, or at least a few times but not constantly because it'll affect performance.

This is a piece of my code:

private CountDownTimer timer;
private long ttime;
private long ctime;

private ProgressBar bar;
private TextView clock;

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    startTimer(500);
    ...
}

@Override
protected void onResume() {
    super.onResume();
    if(!checkFlags()){
        startTimer(500);
    } 
}

@Override
protected void onPause() {
    super.onPause();
    if(!checkFlags()){
        timer.cancel();
    }
}

private void startTimer(long delay){
    timer = new CountDownTimer(ctime,100){
        public void onTick(long millisUntilFinished){
            ctime = millisUntilFinished;
            clock.setText(formatTime(millisUntilFinished));
            bar.setProgress((int) (1000 - ((ctime * 1000)/ttime)));
        }
        
        public void onFinish(){
            clock.setText("00:00");
            gameOver(false);
        }
    };
    
    if(delay > 0){
        Handler handler = new Handler(); 
        handler.postDelayed(new Runnable(){
            public void run(){
                timer.start();
            }
        },delay);
    }else{
        timer.start();
    }
}

How could I prevent the ProgressBar to cause this onDraw calls for every element of the UI?


Solution

  • According to 'sources/android-18/android/widget/ProgressBar.java' in Android SDK the call of setProgress() will result in the call of invalidate().

    private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
            boolean callBackToApp) {
        float scale = mMax > 0 ? (float) progress / (float) mMax : 0;
        final Drawable d = mCurrentDrawable;
        if (d != null) {
            Drawable progressDrawable = null;
    
            if (d instanceof LayerDrawable) {
                progressDrawable = ((LayerDrawable) d).findDrawableByLayerId(id);
                if (progressDrawable != null && canResolveLayoutDirection()) {
                    progressDrawable.setLayoutDirection(getLayoutDirection());
                }
            }
    
            final int level = (int) (scale * MAX_LEVEL);
            (progressDrawable != null ? progressDrawable : d).setLevel(level);
        } else {
    >>>     invalidate();
        }
    
        if (callBackToApp && id == R.id.progress) {
            onProgressRefresh(scale, fromUser);
        }
    }
    

    Try to use setProgressDrawable(). It seems that invalidate() is not called in that case.