Android fragmented ProgressBar (like defrag or bittorrent)

119 views Asked by At

I need an advise on optimizing a custom indicator, that shows progress of downloading file in multiple chunks, in concurrent threads. I couldn't find a correct name for that type - pieces, fragments, chunks? But it should look like bittorrent progress bar or defrag progress from Win XP. And it looks like this:

enter image description here

My custom ProgressBar class as following:

public class FragmentedProgressBar extends ProgressBar {
    private int height;
    private float fragWidth;
    private final ArrayList<Integer> stateColors = new ArrayList<>();
    private final Paint progressPaint = new Paint();
    private ConcurrentHashMap<Integer, Integer> barData;

    public FragmentedProgressBar(Context context) {
        super(context);
        this.init(context);
    }
    public FragmentedProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.init(context);
    }
    public FragmentedProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.init(context);
    }

    @SuppressWarnings("deprecation")
    private void init(Context context) {
        barData = new ConcurrentHashMap<>();
        stateColors.addAll(
                Arrays.asList(
                        context.getResources().getColor(android.R.color.holo_blue_dark),
                        context.getResources().getColor(android.R.color.holo_green_light),
                        context.getResources().getColor(android.R.color.holo_orange_light),
                        context.getResources().getColor(android.R.color.holo_red_light)
                )
        );
    }

    public synchronized void setProgress(int progress, int state) {

        /* state serves to indicate "started", "ready", "retry", "error" by color */
        if(barData != null ) {
            barData.put(progress, state);
        }
        super.setProgress(progress);
    }

    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = getMeasuredWidth();
        height = getMeasuredHeight();
        setMeasuredDimension(width, height);
        fragWidth = (float) width / getMax();
    }

    @Override
    protected synchronized void onDraw(Canvas canvas) {
        for (Map.Entry<Integer, Integer> ent : barData.entrySet()) {
            int id = ent.getKey();
            int state = ent.getValue();
            float xleft = fragWidth * ( id - 1 );
            progressPaint.setColor(stateColors.get(state));
            canvas.drawRect(xleft, 0.0f, xleft + fragWidth, 0.0f + height, progressPaint);
        }
    }
}

However, in this approach, it redraws whole bar on every progress tick, and, I think, it's quite inefficient. I've done formerly same bar in javafx, extending Canvas and drawing each chunk separately on it.

What will be a better solution for android, desirably extending and reusing the ProgressBar class?

Thanks

0

There are 0 answers