Kyri33
Kyri33

Reputation: 599

android updating view from a thread. Only the original thread that created the view can touch its views.

I know this may seem like a noob question but I've tried everything. I want to animate a number incrementing. So I set up a view. I made a thread inside the view that loops a certain amount of times. In the loop I call Thread.sleep and then I increment a number. However I'm not sure how to call the invalidate() method to update the view each time it goes through the loop. I've tried a callback but that isn't working. Your help would be appreciated. What I'm trying to increment is the 'centerText' which is drawn using textPaint

public class GameView extends View {

private int backgroundColor;
private int circleColor;
private int radiusFactor;
private Paint circlePaint;
private Paint textPaint;
private Paint text2Paint;
private Paint text3Paint;
private String topMessage;
private String bottomMessage;
private String topMessage2;
private String bottomMessage2;
private String centerText;
private boolean isRunning = false;
private int FPS = 60;

public interface animateThread{
    public void updateUI(String text);
}

private animateThread threadCheck = new animateThread(){
    @Override
    public void updateUI(String text) {
        centerText="text";
        invalidate();
    }
};


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

    backgroundColor = Color.parseColor("#FF4000");
    circleColor = Color.parseColor("#B40404");
    radiusFactor = 4;

    centerText="?";

    circlePaint = new Paint();
    circlePaint.setAntiAlias(true);
    circlePaint.setColor(circleColor);

    textPaint = new Paint();
    textPaint.setAntiAlias(true);
    textPaint.setColor(Color.WHITE);
    textPaint.setTextAlign(Paint.Align.CENTER);

    text2Paint = new Paint();
    text2Paint.setAntiAlias(true);
    text2Paint.setColor(Color.BLACK);
    text2Paint.setTextAlign(Paint.Align.CENTER);

    text3Paint = new Paint();
    text3Paint.setAntiAlias(true);
    text3Paint.setColor(Color.BLACK);
    text3Paint.setTextAlign(Paint.Align.CENTER);

    topMessage = "One in a";
    topMessage2="Hundred?";
    bottomMessage="Click the Circle";
    bottomMessage2="To find out";
}

@Override
public boolean onTouchEvent(MotionEvent event) {

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            break;
        case MotionEvent.ACTION_UP:

            break;
        case MotionEvent.ACTION_MOVE:
            break;

    }
    if(!isRunning) startAnimation(threadCheck);

    return true;
}

@Override
protected void onDraw(Canvas canvas) {
    setBackgroundColor(backgroundColor);

    textPaint.setTextSize(getWidth()/4);
    text2Paint.setTextSize(getWidth()/6);
    text3Paint.setTextSize(getWidth()/8);

    canvas.drawCircle(getWidth()/2, getHeight()/2,getWidth()/radiusFactor,  
circlePaint);
    canvas.drawText(centerText, getWidth()/2, getHeight()/2- 
((textPaint.descent()+textPaint.ascent())/2), textPaint);

    canvas.drawText(topMessage, getWidth()/2, ((getHeight()/2-
getWidth()/radiusFactor)/2+((text2Paint.descent()+text2Paint.ascent())/2)),  
text2Paint);
    canvas.drawText(topMessage2, getWidth()/2, (getHeight()/2-
getWidth()/radiusFactor)/2-((text2Paint.descent()+text2Paint.ascent())), 
text2Paint);

    canvas.drawText(bottomMessage, getWidth()/2, getHeight()*4/5+
((text3Paint.descent()+text3Paint.ascent())/2), text3Paint);
    canvas.drawText(bottomMessage2, getWidth()/2, getHeight()*4/5-   
((text3Paint.descent()+text3Paint.ascent())), text3Paint);

}

public void startAnimation(final animateThread mCallback) {
    Thread animate = new Thread(new Runnable(){

        @Override
        public void run() {
            isRunning=true;
            int count=0;
            for (int i=0;i<FPS*5;i++) {
                count++;
                if(count>100) count = 1;
                mCallback.updateUI(count+"");
                try {
                    Thread.sleep(1000/FPS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            isRunning=false;
        }
    });
    animate.start();
}



}

Upvotes: 0

Views: 55

Answers (1)

Singed
Singed

Reputation: 1113

Anything invoked within

  new Thread(new Runnable(){
  ...
  }

Will implicitly run on a non-UI thread. If you want to touch the UI, the code for that task must be forced to run on the UI thread like this:

context.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        updateUI(count+"");
    }
});

Upvotes: 1

Related Questions