Android View implements Runnable - is it ok, or Handler is a must?
I would like to ask a question about android View drawing in a loop for games or animations.
I have done previously some game development for j2me, and I tried to implement the same drawing logic in android, just to measure performance and to experiment with the framework. My first try is with View and onDraw(). Later I'll try with SurfaceView.
So here is my question: I extended View and made the View implement Runnable, so it can start a thread to make the loop not on the UI thread. The code is working fine.
The thing that bothers me is that in the android documentation, it's written that it's not possible to call methods of the View from another thread without using a Handler. The docs say that I should use a handler, however my code is working without it.
开发者_如何学编程Quote:
Note: The entire view tree is single threaded. You must always be on the UI thread when calling any method on any view. If you are doing work on other threads and want to update the state of a view from that thread, you should use a Handler.
Here is the code of the View. Is there a reason why I should prefer using Handler instead of the code below?
Thank you very much.
public class DrawView extends View implements Runnable
{
private Context mContext = null;
private Thread drawThread = null;
private Drawable mIcon = null;
public DrawView(Context context)
{
super(context);
mContext = context;
mIcon = context.getResources().getDrawable(R.drawable.icon);
}
protected void onDraw(Canvas canvas)
{
mIcon.draw(canvas);
}
public void start()
{
if(drawThread == null) drawThread = new Thread(this);
drawThread.start();
}
public void run()
{
while(true)
{
// updateGameState(); // move the objects (icon) to new position
postInvalidate(); // request for drawing objects
}
}
}
---- EDIT ----
It seems that its reasonable to use the code above without using Handler, when the View is updated via postInvalidate.
Cause an invalidate of the specified area to happen on a subsequent cycle through the event loop. Use this to invalidate the View from a non-UI thread.
So it seems to me that the note in the Android Docs about View should be corrected, because Handler is not the only option to go when you want to update a View from another thread.
Handler is not a must, you could always use runOnUiThread()
.
However I'm not sure this behaves as you intend. To clarify: Your View must (as far as I know) be generated on and handled by the UI thread's Looper
. Most functionality exposed by View checks for illegal cross-thread calls, because View
is not designed to be accessible by multiple threads at once.
If you extend View, you can always call your own methods from any thread, BUT you cannot access the inherited functionality without posting something to the UI thread's message queue. If you do this with a Handler
, by runOnUiThread()
or by using some other thread-safe method (can't think of any right now) is up to you.
In your case, run()
runs on it's own thread, but postInvalidate()
will cause the redraw from the UI thread.
the movement is more smooth whith runnable as i get 60fps or 150 if i want compared to 30 when using handler, though i dont have more than 10 objects moving at the same time, i guess this might be device dependent and maybe android os version dependent. Motorola flipout uses 2.1. Anyway using runnable method comes from j2me games so it should be working ok and you only have to minimize your thread sleep not to run too fast. Using handler probably does that for you
did some xperimenting and if you want to achieve more than 30fps, for example matching iphone standards 60fps you will need to use runnable as in your example without handler, when i use a handler it never goes beyond 30fps. Some say its enough but when you compare to 60 its just not the same especially for fast paced games but it will possibly drain battery quicker
精彩评论