11

I've got a custom View in my application which fills the entire activity.

In most cases, when I want to refresh the control I call invalidate() without any parameters.

However, in certain circumstances, where I'm only changing a small area of the control, I call invalidate(Rect) to avoid redrawing the entire screen. This is important because in these situations I need the update to be as fast as possible.

This seems to work fine, however, when I enable hardware acceleration in Honeycomb (i.e. set android:hardwareAccelerated="true"in AndroidManifest.xml), the partial redraw does not seem to work.

This can be seen if I do Log.d("FOO", canvas.getClipBounds()) in my onDraw() method; the output simply shows that the whole control is being updated, whereas with hardware acceleration disabled, I get the correct region being output.

Is there any way to make partial invalidation work when using hardware acceleraton?

Many thanks, Matt

Matt Holgate
  • 533
  • 1
  • 4
  • 10
  • I have been wondering about this for a while as well and am experiencing the same results as you described. Do you have any update on trying to make partial invalidation work when using hardware acceleration? Or any updates on why this does not work? – ashughes Jan 20 '12 at 20:34
  • 1
    Partial updates work. Display lists must contain all the drawing commands of a View, but only the commands intersecting the dirty region are actually executed. – Romain Guy Feb 14 '13 at 17:50

2 Answers2

15

Partial redraw works just fine, only the specified region of the screen will get redrawn. What it won't do however is change the clip bounds on the Canvas. All the drawing operations will be recorded but only the ones intersecting with the dirty region will actually be executed.

Update: as of Lollipop (API 21), partial invalidation happens at the View level (i.e. you cannot invalidate less than an entire View).

Romain Guy
  • 97,993
  • 18
  • 219
  • 200
  • no , I have the same problem. With hardware acceleration, on `onDraw(Canvas canvas)`, `canvas.getClipBound()` return the entire view's region. Whereas, with no hardware acceleration, `canvas.getClipBound()` return correct dirty Rect. I think it might be depends on device. – Yeung Feb 14 '13 at 06:00
  • getClipBounds() returns the entire view's region with hardware acceleration but that doesn't mean all the drawing commands will be executed. Only the ones intersecting the dirty region will. – Romain Guy Feb 14 '13 at 17:50
  • 1
    Sorry, but I have done a experiment. In my view's `onDraw(Canvas canvas)`, it draw a long `Path` and I invaildate with a small `Rect`.With hardware acceleration, It draw the entire path. With no hardware acceleration, it draw the part only inside the `Rect`. – Yeung Feb 18 '13 at 09:24
  • 1
    With hardware acceleration, only the part inside the dirty rectangle will get drawn. What is your test exactly? How do you verify the result? Fwiw, I wrote this rendering pipeline :) – Romain Guy Feb 20 '13 at 18:19
  • I just new a `Path` point to left top corner of screen and then line to right bottom corner of screen. In `onDraw(Canvas canvas)`, draw the path. On my activity's `onResume()`, I post handler to set the path to the view and invailate with a small `Rect` on left top corner. With hardware acceleration, I see entire line drawn, and with no hardware acceleration, I see part of line. – Yeung Feb 21 '13 at 03:33
  • 1
    With hardware acceleration we force a redraw of the entire window in several cases, including resuming an Activity. This doesn't mean however that the dirty region is always ignored. You can verify this by turning on GPU View updates in Settings > Developer Options. The screen will flash red where the windows are updated. – Romain Guy Feb 21 '13 at 17:13
  • Ok, why then there is different behaviour between with/without HW acceleration for "getClipBound" in "onDraw" function? Why it returns non-fullscreen rectangle in case of SW-only mode? – Roman Jan 25 '14 at 13:08
  • @Roman, with HA enabled, the `Canvas` in `onDraw` is simply used to build the DisplayList which doesn't mean everything on the screen will be redrawn. – suitianshi Aug 22 '14 at 03:18
  • Whether partial redraw works with HW acceleration also seems to depend on the Android version. I have a custom HW accelerated view whose outcome of `onDraw()` depends on where it has last been touched. There is only one place from where this view is invalidated (I can check that no update ever occurs if I remove that invalidate). Using `invalidate(Rect)` leads to the expected partial updates on my Samsung s4 mini (4.4.2) but the whole view is always redrawn on my note 8 (4.2.2). – cgogolin Jul 31 '15 at 17:00
  • 2
    In my experience with hardware acceleration on, the entire view is always redrawn. I've verified this by splitting my view into a grid of smaller views and only invalidating the views that changed. Performance was much improved in this case. – jjxtra Oct 02 '15 at 15:46
  • I turned on `GPU View updates` and it shows that `Hardware Acceleration` causes redrawing entire of view instead of partial redrawing. – hasanghaforian Nov 01 '18 at 13:20
  • @hasanghaforian Yes, this is the new behavior. I've updated my answer to reflect this. – Romain Guy Dec 11 '18 at 17:47
1

When HA is enabled, the rendering pipeline will use DisplayList to store the drawing commands. Even if you specify the dirty region in View.invalidate, the whole displaylist will be rebuilt (just think that how can we only update a small set of DisplayList, that's impossible right?). Eventually, as @Romain says, only the real dirty region will be redrawn.

suitianshi
  • 3,300
  • 1
  • 17
  • 34