Skip to content

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

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 nullCanvas, 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) -> {
XYPlotplot = (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 bgBuffernull, and therefore makes getCanvas() return null.

As a result, renderOnCanvas returns straight away:

protectedsynchronizedvoidrenderOnCanvas(@NullableCanvascanvas) {
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:

protectedsynchronizedvoidrenderOnCanvas(@NullableCanvascanvas) {
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