Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
204 views
in Technique[技术] by (71.8m points)

android - Canvas not displaying all drawn parts in Custom View?

I'm working on a custom view for an android application, similar to the Analog Gauge sample code available from Mind the Robot.

Running the code from listed site, I get see this on my screen:

(Motorola Droid, 2.2.3), (Emulator, 4.0.3)

has an arrow

(Xoom, 4.0.3)(Other phone, 4.0.3)

does not have an arrow

The hand is missing!

The drawing calls are being made (I can see them in logcat), but the canvas elements the calls draw are invisible.

It's not API level dependent, though; if I import it the right way into a project, it will hand will show up when I run it on the Xoom.

But, when I move the files to a different project folder (same source code, same layouts) it goes back to missing the dial.

What's going on? How could the same code be producing such different outcomes on different devices?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

So, the key clue in my mystery seemed to be that it worked on the emulator, but not on the hardware devices.

Hardware Rendering

I did peruse the hardware rendering page on the Android Developer's website, but apparently not closely enough.

http://developer.android.com/guide/topics/graphics/hardware-accel.html

While it does mention that the API's are available beginning version 11, it does not say that Hardware Rendering is turned on for all applications by default, starting with API Level 14 (ICS).

What does this mean for us?

Almost everything is faster; except for the few things that don't work.

I managed to violate two of these, without realizing it:

  • Canvas.DrawTextOnPath()
  • Paint.setShadowLayer()

It's not mentioned in the API reference (or anywhere else I can find, and certainly not checked by Lint), but using any of the listed operations can do weird things.

In my case, Canvas.DrawTextOnPath() seemed to work just fine.

But when Android notice that the paint that I used on the hand had shadow layer set, it silently ignored it.

How do I know if my View is hardware accelerated?

From the documentation link above:

There are two different ways to check whether the application is hardware accelerated:

  • View.isHardwareAccelerated() returns true if the View is attached to a hardware accelerated window.
  • Canvas.isHardwareAccelerated() returns true if the Canvas is hardware accelerated

If you must do this check in your drawing code, use Canvas.isHardwareAccelerated() instead >of View.isHardwareAccelerated() when possible. When a view is attached to a hardware >accelerated window, it can still be drawn using a non-hardware accelerated Canvas. This >happens, for instance, when drawing a view into a bitmap for caching purposes.

In my case, the opposite appears to have occurred. The custom view logs that it is not Hardware-accelerated; however, the canvas reports that it is hardware-accelerated.

Work Arounds and Fixings

The simplest fix is forcing the custom view to do software rendering. Per the documentation this can be accomplished by:

myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

Alternatively, you could remove the offending operations, and keep hardware rendering turned on.

Learn from my misfortune. Good luck, all.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...