I'm trying to write a debug utility that will take certain actions (logging, screenshots, etc...) when a view in the current Activity's view hierarchy changes. Change here is anything that would result in the visual representation of the view tree to change: setting the text on a TextView, changing the background color on a View, or adding/removing children to/from a ViewGroup.
Ideally, I'm looking for an API that will notify me when these changes are about to occur and what view/view subtree they will be effecting.
I've spent a lot of time looking at possible solutions and the cleanest would be to use ViewTreeObserver's OnPreDrawListener and OnGlobalLayoutListener. They seem to be notified when the events of interest occur. However, they do not provide any context information as to which views are affected. AFAIK attaching these listeners to a view's ViewTreeObserver results in the notifications being fired whenever anything in the view tree changes and there is no way to create isolated ViewTreeObservers for individual views. This means that I would have to traverse the entire view tree at each notification to determine which property was changed.
Another approach would be to binary patch the View classes so that they callback to my API in methods like setBackgroundColor or any other methods of interest. android-aspectj could be used for that. The downside here is that this would only work for classes that I compiled and so is next to useless since I could just modify the source directly. Along the same idea, dexmaker would be a more complete solution as it allows for patching the classes at runtime. Here, however, we run into the problems of class loading. To patch the class I would have to load it through my own ClassLoader but all of the View classes would have already been loaded in by Android. One solution would be to clone the view tree after it was created but instead of using the stock loaded classes, use my own patched classes. This would almost work except for situations where the app has grabbed references to the view tree before my patching has been put into place. Of course I would also have to redo the clone at each layout change event (adding/removing views). I understand that this process would be slow but so far it is the most transparent and most complete solution.
Finally, and this is probably the most difficult approach, is there a way to use the method tracing system built into Android (Traceview) to receive trace events at runtime? Currently the system will dump the trace to a file on the SD card for offline processing. That is obviously too late for my needs but it would be nice if there were hooks exposed in the native SDK for intercepting these events.
Any and all suggestions are welcome. At this point I am not even looking for portable solutions so feel free to mention any reflaction/hidden API tricks. Thanks for reading this behemoth of a post.
Related
Suppose an app project is already written, all you want to do is to additionally write a somehow standalone script that captures the onClick, onFocusChange or even onAppear in the app. Is that even feasible? How robust is the approach?
All answer I found was to fully add listeners (or global listeners, although less comprehensively functional) for each item or so, which is a boring work for a large project, and not always desired at the end of a production process(where I just cut in).
Another purposed approach was to locate the root of the nodes and scan from there? Correct me if that's a dead end. Other answer mentioned spying app, which is not the case, since it's the original developer who wants to track everything from inside the app.
I am not sure, if this solves your problem but have your extension of views. Eg: MyTextView extends TextView then just override the touchEventHandlers, log what you want and dispatch the event down to the listeners.
So instead of normal TextViews, use MyTextView.
I know how to use the View.isInEditMode method.
What I don't fully understand is when should I use it. That is, what should I prevent from running in EditMode.
There are the obvious cases, where the custom view does all kind of crazy things like DB access, networking, threads etc. where it is clear you should avoid them while in EditMode.
I created a several custom views that don't do anything of the above. They only use the regular drawing API, or load resources such as drawables.
When running on device they look exactly as expected, but inside the layout designer they either don't look as they should or even just fail to render due to some mysterious exception (Usually NullPointerException).
So, are there any limitations in EditMode on these APIs?
Custom views should work just fine as long as they only call parts of the view framework, not any application code. That's a good separation to have for views anyway: they should contain view state, not app logic.
Typically you only have to use View#isInEditMode if your custom view is trying to access classes from its constructor (or measure or draw methods) where those calls for example try to access application framework code like say the FragmentManager. In that case you skip those calls with View#isInEditMode.
It's hard to say more about what the problem you're seeing is without knowing more. In particular, what exactly is the NullPointerException you're seeing (full stack trace).
It could also be a layoutlib bug. Try switching the render version (in the render toolbar) to a different version.
I am targeting mobile using FlashBuilder, I am using TileLayout to view items of data, I am setting useVirtualLayout to "true"
I have some questions please:
Is item renderer resued by default? or shall I set it to true my self?
How can I control the range of items being virtualized?
Is there any tips on boosting performance of building child items of TileLayout ?
If native TileLayout is slow, is there alternative control to use? if building my own would be better, is there any example to build custom layout?
It is set to true by default. There are a few instances where they are not virtualized, however. If you have the list sizing to fit its contents, I don't believe virtualization occurs. If I am not mistaken, virtualization only occurs when an ItemRenderer leaves the viewport of the parent List control. So if you have a list on a page and that page is controlling the scrolling and not the list, I don't believe virutalization occurs. That is what I have seen in the past. Not sure if that is how it actually works, but that is the impression I have gotten. Easy way to find out is to throw a trace statement in your DataChange handler. If it traces out after initialization, you know virtualization is working
I'm not sure you can control this. You may be able to write a custom layout that does it, but that is likely more trouble than it is worth
The TileLayout itself is likely not the issue you are having, it is the ItemRenderer.
On mobile, do not extend any ItemRenderer class except LabelItemRenderer and IconItemRenderer.
Do not write a renderer in MXML. Write in AS3.
Utilize the proper renderer life-cycle. This means you should do very little in your constructor. Maybe set a few properties, but do not instantiate any DisplayObject. Instead, override createChildren() and do it there. Override layoutContents() for positioning and sizing. Override drawBackground() for handling the background. I highly suggest reading this post from Flextras (you'll see him going by Reboog77 on SO) about writing mobile item renderers. https://www.flextras.com/blog/index.cfm/2011/6/24/Building-a-Mobile-ItemRenderer-in-Flex
Keep the renderers as simple as possible. If you can get away with drawing directly into the object using the Graphics class, do that instead of using a Rect or similar.
Text is slow to render. Do not change it often and keep the text seen in the renderer to a minimum
Use ContentCache for any images outside of the iconDisplay in IconItemRenderer. ContentCache will negate the need for reloading images every single time.(iconDisplay/icon already utilizes this by default)
I am wondering, in Android, when you specify setContentView(R.layout.some_layout); thing to note from docs:
This view is placed directly into the activity's view hierarchy
in which way Android renders all views in R.layout.some_layout?
How does Android calculate all the dimensions of views?
I am asking because I know that it is a common courtesy to wait until all views are rendered and already then try to get desired dimensions of views
Question popped up during a small discussion under this answer, when user #AndroidDev stated the following:
Android knows already BEFORE it creates your view the dimension of the
area to create the view
And I started thinking that it actually might be true. Either Android already knows in advance all the measurements or runs a recursive measurement function after each and every new Laoyout, UI component being appended to the Activitys root view, which updates some sort of temporary pointers where to insert the next view (that is how i used to imagine it)
The Hierarchy Viewer is a visual tool that can be used to inspect your application user interfaces in ways that allow you to identify and improve your layout designs.
Check articles here and here.
Developer's site has provided Optimizing Your UI
Edit
Red to know how Android Draws View.
Here is video by Google I/O 2011: Accelerated Android Rendering.
I'm reading up on SurfaceView and how to use it, and I've come across some information that states that a SurfaceView has View#willNotDraw() set to false by default, and that it's up to you to call SurfaceView#onDraw(). I also read that RomainGuy said that this is done by default because it is more efficient. My question now is, when should you handle calling SurfaceView#onDraw() in a separate thread, and when should you just set View#willNotDraw() to true, and just call SurfaceView#invalidate(). Is there a difference between the two, and does one improve performance more than the other?
See:
http://developer.android.com/reference/android/view/View.html#setWillNotDraw(boolean)
I'm not sure where you got your information, but at least the javadoc says that most users will set this to false to get Android to send it onDraw events itself. As for your question about when you should do this, I would say it comes down to why you're using a SurfaceView.
If your view is displaying something dynamic (e.g. for a game or something that has a tight event loop), you'll want to be controlling exactly when updates happen, especially if you'll have the information to use one of the more detailed forms of invalidate to save redrawing the entire View. You won't want Android to call invalidate for you, and that's why the flag is there.
If, on the other hand, you are simply drawing something static, it makes sense to let Android's UI stack control the invalidations.
By the way, invalidate only posts a request to re-draw the View, so be aware of this if you intend to use the event-loop style (onDraw will be called sometime after you call it).
Edit: some clarifications.
Using SurfaceView.onDraw() and SurfaceView.invalidate() will make SurfaceView behave like a normal View and you will pay for the extra overhead associated with SurfaceView. If you want to draw from the UI thread, use a regular View instead. It's easier and cheaper.