views:

117

answers:

4

Hey guys,

I've just started with android development and updating the UI is really bugging me :/

This is what I've got working so far -


package projects.Move;

import android.os.Bundle;
import android.view.View;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Color;

public class Move extends Activity {

    private float y = 0;
    private long now = 0;  
    private float delay = 75;
    private Paint paint = new Paint();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new SimpleMotion(this));
        paint.setColor(Color.BLACK);
    }
    private class SimpleMotion extends View {

        public SimpleMotion(Context context) {
            super(context);
        }

        @Override protected void onDraw(Canvas canvas) {

            float x = canvas.getWidth() / 2;
            canvas.drawColor(Color.WHITE);
            canvas.drawCircle(x, y, 30, paint);  
            if(System.currentTimeMillis() - now > delay) y++;    
            invalidate();
        }
    }
}

It works fine but everybody says that doing your graphics in the main thread, so I'm trying (and failing) to pass it off to another thread. Trouble is, I have absolutely no idea how since really I've never used Threads.

The examples that Google gives on using Threads doesn't seem to be very clear and I couldn't really follow it for what I want to do. Could I ask somebody out here to give me the most basic example of how I could do what I'm doing here efficiently using Threads?

Thanks in advance :)

+4  A: 

You can use AsyncTask for threading, basics: painless threading, example:Multithreading For Performance.

To update UI use update handlers, have a look at this. Everytime you want to update UI you send a message from the thread to your main ui thread.

ArtWorkAD
+1  A: 

Well the first question is -- why do you want to do your graphics in a separate thread? Because unless you are doing some specific things (mostly in the realm of games or media), you are going to find yourself in lots of pain with little benefit if you try to do that.

hackbod
+1  A: 

Your might end up with lots of unnecessary calls to invalidate() (and thus redraws) with the code you provide. Would be better to trigger the change of the y parameter (and the invalidate) with a handler, which you may also fire delayed.

devisnik
+2  A: 

Well, I guess there is some confusion going on here. You HAVE TO do your GUI updates from the main thread (also called the GUI thread) - otherwise you well get something like "Exception, blabla has leaked a view".

I guess what have misunderstood is that expensive operations, such as networking, should be done in a different thread than the main thread. And if you would like to update the GUI from the network thread you would do as ArtWorkAD says (or his links says).

So for what you want to do, you could achieve with something like replacing your SimpleMotion class with the following:

private class SimpleMotion extends View {

        public SimpleMotion(Context context) {
            super(context);

            new Thread(new Runnable() {
                public void run() {
                    while(true){
                        try {
                            Thread.sleep(75);
                            y++;
                            postInvalidate();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
              }).start();
        }

        @Override protected void onDraw(Canvas canvas) {

            float x = canvas.getWidth() / 2;
            canvas.drawColor(Color.WHITE);
            canvas.drawCircle(x, y, 30, paint);  
//            if(System.currentTimeMillis() - now > delay) y++;    
//            invalidate();
        }
    }

With your old code of having invalidate() in onDraw() you would continously be redrawing the gui even while there are no change to it.

The important part of the new code is postInvalidate(). This makes it possible to tell the GUI thread - from another thread - to redraw the GUI.

Cpt.Ohlund
btw, since you're new to threads you should read up on them. And make sure you stop them when you don't need them to run. Otherwise it will keep running in the background even if you press "back" or "home".
Cpt.Ohlund
Thanks, just what I was looking for. Can I assume that the postInvalidate() function always refers to the main UI thread so wherever you call it in the project it will call the onDraw() function of your main UI?
Mark D
Editing time is up: After some more thinking obviously it cannot refer to the main UI thread all the time. So how would you make it refer to a view in another class for example?
Mark D
Well I was some what difuse in my answer. But invalidate just makes a specific View invalid. A view can be a button, checkbox or as in your case a custom view. An activity can exist of multiple Views. So to update (or rather invalidate) a specific view from another thread you would first get the view like " Button btn = (Button) findViewById(R.id.button); " then call btn.postInvalidate();
Cpt.Ohlund
Thanks a million dude :)
Mark D