Java – Android View Canvas onDraw is not executed

Android View Canvas onDraw is not executed… here is a solution to the problem.

Android View Canvas onDraw is not executed

I’m currently working on a custom View that draws some graph blocks on Canvas.
These graph blocks are loaded from multiple files and will be loaded when needed.

They will be loaded by AsyncTask. If they are already loaded, they will be drawn on the Canvas. This works fine!

If these images are loaded, AsyncTask will trigger view.postInvalidate().
The problem is that every time I trigger view.postInvalidate(), my custom view doesn’t fire onDraw(Canvas canvas).

view.postInvalidate only fires the onDraw() method the first time the image is loaded, and then only when I trigger this.invalidate() in my internal onTouchEvent in my custom View

Is it possible for View to decide whether to draw the Canvas again?
Is there a way to force a redraw of the View? I think the invalidate method tells View that it would be cool if View considered redrawing -.-

Are there restrictions on those invalidate methods?

I hope any of you know more about this issue.

Edit:

I just changed every postInvalidate() to invalidate() because the images are all loaded by AsyncTask executing from the main thread
However, there is still the problem of executing invalidate() and not the onDraw() method.
I found that view.invalidate() is triggered by overriding the original method:

@Override
public void invalidate() {
    super.invalidate();
    Log.d(TAG, "invalidate executed");
}

I don’t know what to do now. I’m firing view.invalidate() and view.postInvalidate() but there is absolutely no combination.

Solution

There is a bit of a misunderstanding here. The invalidate and postInvalidate methods are used to tell the View that it needs to be refreshed and redrawn at the earliest draw cycle. The difference is that the invalidate method should be called from inside the UI thread, while the postInvalidate method should be called from outside the UI thread.

These methods are briefly described here:

AsyncTask On the other hand are classes designed specifically for the problem you face. When you need to perform a big task in the background, async you need AsyncTask, but! AsyncTask’s callback method runs in UIThread!

Here’s an explanation of the AsyncTask method

When an asynchronous task is executed, the task goes through 4 steps:

  1. onPreExecute(), invoked on the UI thread immediately after the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.

  2. doInBackground(Params…), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress…) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress…) step.

  3. onProgressUpdate(Progress…), invoked on the UI thread after a call to publishProgress(Progress…). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.

  4. onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.

This means that in the onPostExecute method, you should try to use the invalidate method instead of the postInvalidate method because it is called from UIThread.

Related Problems and Solutions