Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
harbulot opened this issue Dec 12, 2023 · 1 comment
Open

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

harbulot opened this issue Dec 12, 2023 · 1 comment

Comments

@harbulot
Copy link

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;
        }
@halfhp
Copy link
Owner

halfhp commented Dec 12, 2023

Thanks for the report @harbulot!

I know you stated in the first sentence that you were unable to make a code demo of the issue, but just being perfectly honest without a demo, it could be a while before I am able to dedicate the time to investigate and fix. Alternatively you're more than welcome to open a PR if you've got a clean solution that will not negatively impact other user's use cases!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants