Skip to content

Plot not displayed with background thread if initial size is 0 #120

@harbulot

Description

@harbulot

This is using Androidplot 1.5.10.

Due to various degrees of nesting (e.g. XYPlot within a LinearLayout, within a fragment that replaces a FrameLayout of the fragment of a ViewPager2's page, ...), I've encountered a situation where the one of the dimensions of the XYPlot instance is 0, before being expended to its actual size later on.
(Apologies, I'm unable to re-create a small fully contained example.)

In this case, renderOnCanvas is called with a null Canvas, but when we're using a background thread, isIdle is never set to true in this case (as it would with non-zero dimensions).
As a result, the background thread is stuck waiting at renderSync.wait(), and the plot can never be rendered by resizing.

Details

In a situation where rendering is done in background-thread mode, this shows these logs:

plot.addOnLayoutChangeListener(
	(view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
		XYPlot plot = (XYPlot) view;
		Log.d(TAG, String.format(
				"Plot layout change: %s/%s/%s/%s -> %s/%s/%s/%s",
				 oldLeft, oldTop, oldRight, oldBottom,
				 left, top, right, bottom));
	});
D  Plot layout change: 0/0/0/0 -> 0/0/1080/0
I  Thread started with id 143665258
D  Plot layout change: 0/0/1080/0 -> 0/53/1080/824

The problem here is that the background thread, and the first pass at rendering starts with a dimension of 0 height.

In this case, the Canvas in the pingPong instance is null, in Plot.startBackgroundrendering().

Indeed, the BufferedCanvas is resized using (0,0), which makes its bgBuffer null, and therefore makes getCanvas() return null.

As a result, renderOnCanvas returns straight away:

    protected synchronized void renderOnCanvas(@Nullable Canvas canvas) {
        if(canvas == null) {
            return;
        }

The problem here, is that isIdle is never set to true (as it would with a non-null canvas).

As a result, redraw() never does anything, since isIdle is always false:

    public void redraw() {

        if (renderMode == RenderMode.USE_BACKGROUND_THREAD) {

            // only enter synchronized block if the call is expected to block OR
            // if the render thread is idle, so we know that we won't have to wait to
            // obtain a lock.
            if (renderThread != null && isIdle) {
                synchronized (renderSync) {
                    renderSync.notify();
                }
            }

Because of that, renderSync.notify() can never be called, so the background thread is stuck at renderSync.wait(), so no further redrawing can take place.

Solution

Setting isIdle = true in Plot.renderOnCanvas seems to fix the problem:

    protected synchronized void renderOnCanvas(@Nullable Canvas canvas) {
        if(canvas == null) {
            isIdle = true;
            return;
        }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions