What is the difference between Android's invalidate() and postInvalidate() methods? - android

What is the difference between Android's invalidate() and postInvalidate() methods? When does each one get called? Must the methods be called only in classes which extend View?

If you want to re-draw your view from the UI thread you can call invalidate() method.
If you want to re-draw your view from a non-UI thread you can call postInvalidate() method.
Each class which is derived from the View class has the invalidate and the postInvalidate method. If invalidate gets called it tells the system that the current view has changed and it should be redrawn as soon as possible. As this method can only be called from your UI thread another method is needed for when you are not in the UI thread and still want to notify the system that your View has been changed. The postInvalidate method notifies the system from a non-UI thread and the view gets redrawn in the next event loop on the UI thread as soon as possible. It is also shortly explained in the SDK documentation:
CLICK HERE
UPDATE:
There are some problems that arise when using postInvalidate from other threads (like not having the UI updated right-away), this will be more efficient:
runOnUiThread(new Runnable() {
public void run() {
myImageView.setImageBitmap(image);
imageView.invalidate();
}
});

Related

Run a method after onViewCreated

I have a fragment that creates a view, this view uses other classes and methods, but I want after create the view (inflated and initialized) is visible to the user call a method that is going to display the data usage per app.
Is there a way i can run a method after everything is inflated and initialized?
Thanks
The view does not load until the method is over
That is because you are doing some long task in UI thread. Then even you put that method in onResume() or onStart(), your UI will freeze. You should use AsyncTask if you want do some long thread work after UI is inflated.
see
What is the Android UiThread (UI thread)
https://developer.android.com/topic/performance/threads
try running it into onResume()
It is the last called method of the fragment lifecycle

Does posting Runnable to an UI thread guarantee that layout is finished when it is run?

First thing! I do know about ViewTreeObserver.onGlobalLayoutListener.
What made me ask this question is the following notice on Android developer documentation website:
The snippet below does the following:
Gets the parent view and posts a Runnable on the UI thread. This ensures that the parent lays out its children before calling the
getHitRect() method. The getHitRect() method gets the child's hit
rectangle (touchable area) in the parent's coordinates.
Snippet itself is:
parentView.post(new Runnable() {
// Post in the parent's message queue to make sure the parent
// lays out its children before you call getHitRect()
#Override
public void run() {
/// do UI stuff
}
});
(you can look at the full article)
So is this a wrong statement or is it true?
I am asking because posting a runnable seems easier and more convenient compared to doing all that register-listener/handle-event/unregister-listener dance with ViewTreeObserver :)
UPDATE: One more question to bring clarity to the whole subject:
If all this is nice and Runnable can actually be posted instead of using a global layout listener, then why do we have this ViewTreeObserver.onGlobalLayoutListener mechanism at all? When is it better to use it rather than posting a Runnable and what the difference is between this methods?
I like the question too. It forced me to dig into Android source code once again. I believe this works because post() gets called after setContentView().
Method setContentView() ends up in calling ViewGroup.addView() of the top view, and addView() call always triggers requestLayout(). In turn, requestLayout() posts a task to the main thread to be executed later. This task will execute measure and layout on the view hierarchy. Now if you post another task it will be put into the queue after layout task and, as the result, always executed after measure and layout happen. Thus you will always have valid sizes.

Android - listener after redrawing on invalidate()

I'd like to be notified after the view finishes redrawing after I ask it to invalidate. As said in this answer, the invalidate() method doesn't call a View's onDraw() the UI immediately, but schedules the repaint in a message queue which is executed after when the main thread is idle.
I'd like to show a progress dialog, do some UI modifications and then dismiss the dialog when the view is drawn properly. Is there some trick that I can do to know when the View was drawn? Maybe by subclassing the view, overriding the onDraw() method?
I think you answered your question yourself. Why not:
public class DrawListenerView extends View{
private Callback callback;
public DrawListenerView(Callback callback){
this.callback = callback;
}
#Override
protected void onDraw (Canvas canvas){
super.onDraw(canvas);
//add your method here you want to call
//Or use a Callback-pattern
callback.finish();
}
}
public interface Callback(){
public void finish();
}
If you look at the Source:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.1_r2/android/view/View.java#View.invalidate%28%29
The comment above says
Invalidate the whole view. If the view is visible, onDraw(android.graphics.Canvas) will >be called at some point in the future. This must be called from a UI thread. To call from >a non-UI thread, call postInvalidate().
Try it :)
Edit: probably you want to use a Callback to handle this.
You're finding it strange to try to do this because you're going about it all wrong. ;)
You're talking about wanting to wait to dismiss a dialog until something is finished drawing. That implies that you have a drawing operation that is long enough that you want to wait for it.
Drawing a frame in onDraw should be fast. You have 16 milliseconds per frame to do any sort of input processing and drawing if you want to hit 60fps and have a smooth UI. Drawing should never take long enough that you would want to show a progress dialog while it's finishing. (Aside from that, drawing as a result of invalidating part of your UI blocks your UI thread, and your progress dialog wouldn't illustrate any progress until it's done anyway.)
If you need to do some complex off-screen rendering to show later, you should do it in an AsyncTask or similar off of your UI thread, not in a view's actual onDraw method. Once you get the finished callback from that, you can quickly draw the prerendered image you just created and dismiss your progress dialog.

Detecting when a View has been invalidated

In a custom View, I need to perform some additional work inside onDraw() if and only if the View was invalidated by the application; that is, my own code called invalidate() in the UI thread or postInvalidate() in a non-UI thread. If on the other hand onDraw() is being called because the system invalidated the View, I don't wish that additional work to be performed.
What's the best way to achieve this? My immediate thought is to simply override invalidate() and postInvalidate() and set a flag in both of those, but it would be nicer if there was a single UI-thread method I could override.
Any thoughts please?
Thanks, Trev
postInvalidate() ends up calling invalidate() so you don't need to override both. But if you override invalidate(), the system will call the overridden version.
There is a way to do that without extending view class.
view.getViewTreeObserver().addOnDrawListener(new ViewTreeObserver.OnDrawListener() {
#Override
public void onDraw() {
//View was invalidated
}
});

invalidate() inside of a thread android app

I'm new to programming androids but I have quite a bit of experience programming blackberries.
I created an app that has an activity class (main.java) and a view class (game.java).
Inside the view class I have some bitmaps being drawn to the screen. I created a thread and I'm moving the images around in the thread. However when I call invalidate() inside the thread it never redraws the screen.
Are you not able to invalidate() the screen from a thread? I know the thread is running and the invalidate is being called, it just never makes the changes on the screen.
You have to use View.postInvalidate() if you call it from a non-UI thread.
According to docs:
public void postInvalidate ()
Since: API Level 1
Cause an invalidate to happen on a subsequent cycle through the event loop. Use this to invalidate the View from a non-UI thread.

Categories

Resources