Monday, June 9, 2014

Use CountDownTimer to do something repeatly, updating custom view.

This example show how to change color spots in custom view repeatly with CountDownTimer. We also implement callback interface on MainActivity.java, such that our custom view can callback MainActivity to pass something.

May be it is not a good practice to achieve such a job, just a example to use CountDownTimer.


MainActivity.java
package com.example.androidcountdowntimer;

import com.example.androidcountdowntimer.SpotView.SpotCallBack;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity 
  implements SpotCallBack{

 TextView myState, myCounter;
 Button btnStart;
 
 SpotView mySpotView;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  mySpotView = (SpotView)findViewById(R.id.myspotview);
  mySpotView.setCallback(this);

  myState = (TextView) findViewById(R.id.mystate);
  
  myCounter = (TextView) findViewById(R.id.mycounter);
  btnStart = (Button) findViewById(R.id.start);
  btnStart.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
    mySpotView.startRun();
   }
  });

 }

 @Override
 public void cb_onTick(String msg) {
  myCounter.setText("onTick: " + msg);
 }

 @Override
 public void cb_onFinish(String msg) {
  myState.setText(msg);
 }

}

SpotView.java
package com.example.androidcountdowntimer;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.CountDownTimer;
import android.util.AttributeSet;
import android.view.View;

public class SpotView extends View{
 
 //used to pass back something to MainActivity
 interface SpotCallBack {
  void cb_onTick(String msg);
  void cb_onFinish(String msg); 
 }
 
 SpotCallBack spotCallback;
 
 CountDownTimer countDownTimer;
 
 int state;
 final static int STATE_IDLE = 0;
 final static int STATE_RED = 1;
 final static int STATE_GREEN = 2;
 final static int STATE_BLUE = 3;
 
 Paint paintRed, paintGreen, paintBlue;

 public SpotView(Context context) {
  super(context);
  init();
 }

 public SpotView(Context context, AttributeSet attrs) {
  super(context, attrs);
  init();
 }

 public SpotView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  init();
 }
 
 private void init(){
  state = STATE_IDLE;
  
  paintRed = new Paint();
  paintRed.setColor(Color.RED);
  paintRed.setStrokeWidth(1);
  paintRed.setStyle(Paint.Style.FILL);
  
  paintGreen = new Paint();
  paintGreen.setColor(Color.GREEN);
  paintGreen.setStrokeWidth(1);
  paintGreen.setStyle(Paint.Style.FILL);
  
  paintBlue = new Paint();
  paintBlue.setColor(Color.BLUE);
  paintBlue.setStrokeWidth(1);
  paintBlue.setStyle(Paint.Style.FILL);
 }
 
 public void setCallback(SpotCallBack cb){
  spotCallback = cb;
 }
 
 public void startRun(){
  state = STATE_RED;
  
  if(countDownTimer!=null){
   countDownTimer.cancel();
  }
  
  countDownTimer = new CountDownTimer(3000, 500) {
   
   @Override
   public void onTick(long millisUntilFinished) {
    spotCallback.cb_onTick(String.valueOf(millisUntilFinished));
   }
   
   @Override
   public void onFinish() {
    if(state == STATE_RED){
     state = STATE_GREEN;
     spotCallback.cb_onFinish("GREEN");
    }else if(state == STATE_GREEN){
     state = STATE_BLUE;
     spotCallback.cb_onFinish("BLUE");
    }else if(state == STATE_BLUE){
     state = STATE_RED;
     spotCallback.cb_onFinish("RED");
    }
    countDownTimer.start();
    invalidate();
   }
  };
  
  countDownTimer.start();
  spotCallback.cb_onFinish("RED");
  invalidate();
 }

 @Override
 protected void onDraw(Canvas canvas) {
  
  float w = getWidth();
  float h = getHeight();
  
  if(state == STATE_RED){
   canvas.drawCircle(w/4, h/2, 100, paintRed);
  }else if(state == STATE_GREEN){
   canvas.drawCircle(w/2, h/2, 100, paintGreen);
  }else if(state == STATE_BLUE){
   canvas.drawCircle(3*w/4, h/2, 100, paintBlue);
  }
 }

}

/res/layout/activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.androidcountdowntimer.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <Button
        android:id="@+id/start"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Start CountDownTimer" />
    <TextView
        android:id="@+id/mystate"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/mycounter"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
    <com.example.androidcountdowntimer.SpotView 
        android:id="@+id/myspotview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</LinearLayout>

Next example:
- Another approach to handle CountDownTimer in MainActivity, and the custom view handle display only.

No comments: