需要注意的問題主要有兩點:
1、Timer和TimerTask在調用cancel()取消後不能再執行 schedule語句,否則提示出錯,提示如下:
- D/AndroidRuntime( 6672): Shutting down VM
- W/dalvikvm( 6672): threadid=1: thread exiting with uncaught exception (group=0x40018560)
- E/AndroidRuntime( 6672): FATAL EXCEPTION: main
- E/AndroidRuntime( 6672): java.lang.IllegalStateException: Timer was canceled
- E/AndroidRuntime( 6672): at java.util.Timer.scheduleImpl(Timer.java:563)
- E/AndroidRuntime( 6672): at java.util.Timer.schedule(Timer.java:483)
- E/AndroidRuntime( 6672): at com.snowdream.timerdemo.TimerDemoActivity$2.onClick(TimerDemoActivity.java:73)
- E/AndroidRuntime( 6672): at android.view.View.performClick(View.java:2501)
- E/AndroidRuntime( 6672): at android.view.View$PerformClick.run(View.java:9107)
- E/AndroidRuntime( 6672): at android.os.Handler.handleCallback(Handler.java:587)
- E/AndroidRuntime( 6672): at android.os.Handler.dispatchMessage(Handler.java:92)
- E/AndroidRuntime( 6672): at android.os.Looper.loop(Looper.java:130)
- E/AndroidRuntime( 6672): at android.app.ActivityThread.main(ActivityThread.java:3835)
- E/AndroidRuntime( 6672): at java.lang.reflect.Method.invokeNative(Native Method)
- E/AndroidRuntime( 6672): at java.lang.reflect.Method.invoke(Method.java:507)
- E/AndroidRuntime( 6672): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
- E/AndroidRuntime( 6672): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
- E/AndroidRuntime( 6672): at dalvik.system.NativeStart.main(Native Method)
- W/ActivityManager( 154): Force finishing activity com.snowdream.timerdemo/.TimerDemoActivity
- W/ActivityManager( 154): Activity pause timeout for HistoryRecord{40550560 com.snowdream.timerdemo/.TimerDemoActivity}
- W/ActivityManager( 154): Activity destroy timeout for HistoryRecord{40550560 com.snowdream.timerdemo/.TimerDemoActivity}
- D/dalvikvm( 800): GC_EXPLICIT freed 13K, 58% free 3127K/7431K, external 0K/0K, paused 70ms
- D/dalvikvm( 562): GC_EXPLICIT freed 59K, 51% free 2935K/5959K, external 245K/512K, paused 84ms
- I/ActivityManager( 154): Start proc com.android.email for service com.android.email/.service.MailService: pid=6691 uid=10019 gids={3003, 1015}
(注:這種情況下,可以通過Hander發送消息的方式來更新控件/組件,詳情參考例子。)
- E/AndroidRuntime( 6309): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
- E/AndroidRuntime( 6309): at android.view.ViewRoot.checkThread(ViewRoot.java:2941)
- E/AndroidRuntime( 6309): at android.view.ViewRoot.invalidateChild(ViewRoot.java:643)
- E/AndroidRuntime( 6309): at android.view.ViewRoot.invalidateChildInParent(ViewRoot.java:669)
- E/AndroidRuntime( 6309): at android.view.ViewGroup.invalidateChild(ViewGroup.java:2511)
- E/AndroidRuntime( 6309): at android.view.View.invalidate(View.java:5296)
- E/AndroidRuntime( 6309): at android.widget.TextView.checkForRelayout(TextView.java:5533)
- E/AndroidRuntime( 6309): at android.widget.TextView.setText(TextView.java:2730)
- E/AndroidRuntime( 6309): at android.widget.TextView.setText(TextView.java:2598)
- E/AndroidRuntime( 6309): at android.widget.TextView.setText(TextView.java:2573)
- E/AndroidRuntime( 6309): at com.snowdream.timerdemo.TimerDemoActivity$1.run(TimerDemoActivity.java:48)
- E/AndroidRuntime( 6309): at java.util.Timer$TimerImpl.run(Timer.java:284)
Demo源碼如下:TimerDemoActivity.java
- package com.snowdream.timerdemo;
- import java.util.Timer;
- import java.util.TimerTask;
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.util.Log;
- import android.view.View;
- import android.widget.Button;
- import android.widget.TextView;
- public class TimerDemoActivity extends Activity {
- private static String TAG = "TimerDemo";
- private TextView mTextView = null;
- private Button mButton_start = null;
- private Button mButton_pause = null;
- private Timer mTimer = null;
- private TimerTask mTimerTask = null;
- private Handler mHandler = null;
- private static int count = 0;
- private boolean isPause = false;
- private boolean isStop = true;
- private static int delay = 1000; //1s
- private static int period = 1000; //1s
- private static final int UPDATE_TEXTVIEW = 0;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- mTextView = (TextView)findViewById(R.id.mytextview);
- mButton_start = (Button)findViewById(R.id.mybutton_start);
- mButton_pause = (Button)findViewById(R.id.mybutton_pause);
- mButton_start.setOnClickListener(new Button.OnClickListener() {
- public void onClick(View v) {
- if (isStop) {
- Log.i(TAG, "Start");
- } else {
- Log.i(TAG, "Stop");
- }
- isStop = !isStop;
- if (!isStop) {
- startTimer();
- }else {
- stopTimer();
- }
- if (isStop) {
- mButton_start.setText(R.string.start);
- } else {
- mButton_start.setText(R.string.stop);
- }
- }
- });
- mButton_pause.setOnClickListener(new Button.OnClickListener() {
- public void onClick(View v) {
- if (isPause) {
- Log.i(TAG, "Resume");
- } else {
- Log.i(TAG, "Pause");
- }
- isPause = !isPause;
- if (isPause) {
- mButton_pause.setText(R.string.resume);
- } else {
- mButton_pause.setText(R.string.pause);
- }
- }
- });
- mHandler = new Handler(){
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case UPDATE_TEXTVIEW:
- updateTextView();
- break;
- default:
- break;
- }
- }
- };
- }
- private void updateTextView(){
- mTextView.setText(String.valueOf(count));
- }
- private void startTimer(){
- if (mTimer == null) {
- mTimer = new Timer();
- }
- if (mTimerTask == null) {
- mTimerTask = new TimerTask() {
- @Override
- public void run() {
- Log.i(TAG, "count: "+String.valueOf(count));
- sendMessage(UPDATE_TEXTVIEW);
- do {
- try {
- Log.i(TAG, "sleep(1000)...");
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- }
- } while (isPause);
- count ++;
- }
- };
- }
- if(mTimer != null && mTimerTask != null )
- mTimer.schedule(mTimerTask, delay, period);
- }
- private void stopTimer(){
- if (mTimer != null) {
- mTimer.cancel();
- mTimer = null;
- }
- if (mTimerTask != null) {
- mTimerTask.cancel();
- mTimerTask = null;
- }
- count = 0;
- }
- public void sendMessage(int id){
- if (mHandler != null) {
- Message message = Message.obtain(mHandler, id);
- mHandler.sendMessage(message);
- }
- }
- }
layout-main.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical" >
- <TextView
- android:id="@+id/mytextview"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:text="@string/number" />
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:orientation="horizontal" >
- <Button
- android:id="@+id/mybutton_start"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/start" />
- <Button
- android:id="@+id/mybutton_pause"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/pause" />
- </LinearLayout>
- </LinearLayout>
strings.xml
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <string name="app_name">TimerDemo</string>
- <string name="number">0</string>
- <string name="start">start</string>
- <string name="stop">stop</string>
- <string name="pause">pause</string>
- <string name="resume">resume</string>
- </resources>