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.
Related
I understand that postInvalidate() is for non-UI threads. However calling postInvalidate() in the UI thread seems harmless and effectively equivalent. (The cost difference seems negligible.)
There is an advantage to always using postInvalidate(): you'll never get a crash when your code containing invalidate() one day makes its way into a non-UI thread. So why bother with invalidate()?
I am programming a simple game and has to draw animation on the screen and currently calling invalidate() method from within onDraw(). I simply wish to periodically update my canvas.
I would like to move the invalidate() call somewhere else as calling within onDraw() is rather bad. However, my target platform is android gingerbread and I probably can't utilize those methods which involve multithreading.
Is there anyway to setup a timer outside of onDraw() which invalidate() if the time lapse interval meets my desire without involving multithreading?
I probably can't utilize those methods which involve multithreading.
That's not true. It is not what you need though. If you need to call invalidate periodically on your view, you can use the View's internal handler and its postDelayed method, to invoke invalidate(). The runnable runs on the UI Thread.
Wouldn't it be an idea to call invalidate() after an user input?
If you want a timer look to this:
https://developer.android.com/training/scheduling/alarms.html
This method should be viable with your android version.
I would expect this (inside getView()) to work...
but nothing happens, the bitmaps are not loaded into the ImageView....
Thread th= new Thread(new Runnable() {
#Override
public void run() {
ImageLoader.getInstance().displayImage(rss.getChannel().getItems().get(position).getEnclosure().getUrl(),holder.imageView,options,new ImageLoadingListener() {
#Override
public void onLoadingStarted(String imageUri, View view) {
//...stuff...
}
//... more stuff
#Override
public void onLoadingCancelled(String imageUri, View view) {
//...stuff
}
});
}
});
th.start();
Please why it's not???
Thanks :-)
What you try to do is really bad practice. However, I cant tell you from the information you provide us what the problem is.
I think that the ImageLoading library is already doing things in its own thread, therefore your Thread is already finished. Also only the main UI Thread can access or manipulate UI Views, but there should be an exception thrown if this would be the problem.
Furthermore, I would recommend you to use Picasso. It handles Threadpooling, scheduling, caching, memory management (avoid memory leaks by using WeakReference) and recycling view in ListView or RecyclerView.
Update:
You are creating a Thread everytime getView() is called while scrolling. This is bad practice, because creating a Thread is expensive. Think about flinging or fast scrolling a list. If you scroll 20 elements, 20 Threads will be created and started. All the thready have the same priority as the main UI thread. That means that the CPU is shared between 20 Threads plus the main UI Thread. This could lead to bad UI performance. You should use a ThreadPool. Furthermore, you don't stop your Thread. This brings two problems:
Your view get recycled in getView() while the Thread is not, so the thread is still running while the view should display already another item.
You get memory leaks! Do you know how Garbage Collection works? It starts at thread level and searches for unused objects (objects that are not referenced anymore by any other object). Your Thread is a inner class. Therefore it has a hard reference to the surrounding Adapter class. The Adapter is attached to the ListView, the ListView to the Activity. So if your Activity gets closed by the user the garbage collector can not collect Activity and all the views and other objects until the Thread (or in your case, all Threads) are finished. You probably run out of memory.
Last but not least, the Android System has its own message queue based threading system and only the main UI Thread can access UI Views. I don't want to get to deep in detail here, I'm sure you can google it. At this point I recommend to use AsyncTask if you really have to start your own Thread. But you also have to cancel the AsyncTask manually to avoid memory leaks.
First of all, Android application UI not updated or accessed from worker thread. So your Thread not going to change/access Image.
Second, you don't need Thread for Image loading, as your ImageLoader library itself take care of it.
Only the UIThread can change its views. I suggest to use runOnUIThread() method from Activity.
More info: https://developer.android.com/training/multiple-threads/communicate-ui.html
My surfaceView is running in a thread because at times it's animated , however
most the time it just needs to be re-drawn once and left in response to some user interaction , but because its running in the thread onDraw is continually being called... the constant re-draws are slowing it down and making my phone warm :)
I would like to use invalidate(Rect) but can't see how to do this when the thread is controlling onDraw ...
Everything constantly redrawing can't be the way i should go , any help will be greatly appriciated ...
In your thread, you can call wait() after calling onDraw(). This will force the thread to sleep until prompted to continue working. Once the user has interacted and you want to resume animation, call notify() on the thread to wake it up and have it redraw.
If that doesn't exactly solve your problem, consider putting the wait() inside of an if statement so it will only happen after some condition is met.
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();
}
});