Làm thế nào để thiết lập bộ đếm thời gian trong Android?


325

Ai đó có thể đưa ra một ví dụ đơn giản về việc cập nhật trường văn bản mỗi giây hoặc lâu hơn không?

Tôi muốn tạo một quả bóng bay và cần tính toán / cập nhật tọa độ bóng mỗi giây, đó là lý do tại sao tôi cần một bộ đếm thời gian.

Tôi không nhận được gì từ đây .



Câu trả lời:


463

ok vì điều này chưa được làm rõ nhưng có 3 cách đơn giản để xử lý việc này. Dưới đây là một ví dụ hiển thị cả 3 và ở phía dưới là một ví dụ chỉ hiển thị phương pháp tôi tin là thích hợp hơn. Cũng nhớ dọn dẹp các tác vụ của bạn trong onPause, lưu trạng thái nếu cần.


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.os.Handler.Callback;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class main extends Activity {
    TextView text, text2, text3;
    long starttime = 0;
    //this  posts a message to the main thread from our timertask
    //and updates the textfield
   final Handler h = new Handler(new Callback() {

        @Override
        public boolean handleMessage(Message msg) {
           long millis = System.currentTimeMillis() - starttime;
           int seconds = (int) (millis / 1000);
           int minutes = seconds / 60;
           seconds     = seconds % 60;

           text.setText(String.format("%d:%02d", minutes, seconds));
            return false;
        }
    });
   //runs without timer be reposting self
   Handler h2 = new Handler();
   Runnable run = new Runnable() {

        @Override
        public void run() {
           long millis = System.currentTimeMillis() - starttime;
           int seconds = (int) (millis / 1000);
           int minutes = seconds / 60;
           seconds     = seconds % 60;

           text3.setText(String.format("%d:%02d", minutes, seconds));

           h2.postDelayed(this, 500);
        }
    };

   //tells handler to send a message
   class firstTask extends TimerTask {

        @Override
        public void run() {
            h.sendEmptyMessage(0);
        }
   };

   //tells activity to run on ui thread
   class secondTask extends TimerTask {

        @Override
        public void run() {
            main.this.runOnUiThread(new Runnable() {

                @Override
                public void run() {
                   long millis = System.currentTimeMillis() - starttime;
                   int seconds = (int) (millis / 1000);
                   int minutes = seconds / 60;
                   seconds     = seconds % 60;

                   text2.setText(String.format("%d:%02d", minutes, seconds));
                }
            });
        }
   };


   Timer timer = new Timer();
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        text = (TextView)findViewById(R.id.text);
        text2 = (TextView)findViewById(R.id.text2);
        text3 = (TextView)findViewById(R.id.text3);

        Button b = (Button)findViewById(R.id.button);
        b.setText("start");
        b.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Button b = (Button)v;
                if(b.getText().equals("stop")){
                    timer.cancel();
                    timer.purge();
                    h2.removeCallbacks(run);
                    b.setText("start");
                }else{
                    starttime = System.currentTimeMillis();
                    timer = new Timer();
                    timer.schedule(new firstTask(), 0,500);
                    timer.schedule(new secondTask(),  0,500);
                    h2.postDelayed(run, 0);
                    b.setText("stop");
                }
            }
        });
    }

    @Override
    public void onPause() {
        super.onPause();
        timer.cancel();
        timer.purge();
        h2.removeCallbacks(run);
        Button b = (Button)findViewById(R.id.button);
        b.setText("start");
    }
}


điều chính cần nhớ là UI chỉ có thể được sửa đổi từ luồng ui chính, vì vậy hãy sử dụng trình xử lý hoặc hoạt động.runOnUIThread (Runnable r);

Đây là những gì tôi coi là phương pháp ưa thích.


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

public class TestActivity extends Activity {

    TextView timerTextView;
    long startTime = 0;

    //runs without a timer by reposting this handler at the end of the runnable
    Handler timerHandler = new Handler();
    Runnable timerRunnable = new Runnable() {

        @Override
        public void run() {
            long millis = System.currentTimeMillis() - startTime;
            int seconds = (int) (millis / 1000);
            int minutes = seconds / 60;
            seconds = seconds % 60;

            timerTextView.setText(String.format("%d:%02d", minutes, seconds));

            timerHandler.postDelayed(this, 500);
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_activity);

        timerTextView = (TextView) findViewById(R.id.timerTextView);

        Button b = (Button) findViewById(R.id.button);
        b.setText("start");
        b.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Button b = (Button) v;
                if (b.getText().equals("stop")) {
                    timerHandler.removeCallbacks(timerRunnable);
                    b.setText("start");
                } else {
                    startTime = System.currentTimeMillis();
                    timerHandler.postDelayed(timerRunnable, 0);
                    b.setText("stop");
                }
            }
        });
    }

  @Override
    public void onPause() {
        super.onPause();
        timerHandler.removeCallbacks(timerRunnable);
        Button b = (Button)findViewById(R.id.button);
        b.setText("start");
    }

}



1
@ Dave.B, cảm ơn vì ví dụ tuyệt vời. Có bất kỳ lợi thế / bất lợi nào khi sử dụng một phương pháp so với các phương pháp khác mà bạn đã vạch ra không?
Gautam

2
@Gautam Tôi tin rằng tất cả các phương pháp trên thực hiện giống nhau. Cá nhân tôi thích phương thức xử lý được mô tả ở trên với Runnable và h2 Handler chạy vì đây là phương thức được quy định bởi trang web dành cho nhà phát triển Android và theo tôi cũng thanh lịch nhất.
Dave.B

6
Sẽ rất tốt nếu phương thức ưa thích của bạn tách biệt với phần còn lại của mã. Giống như bạn có thể có một ví dụ cho thấy cách ưa thích của bạn và một ví dụ khác hiển thị các lựa chọn thay thế. Có cả ba phương pháp cùng nhau khiến cho việc hiểu những gì đang diễn ra trở nên khó khăn hơn (đặc biệt đối với một người mới chơi Android như tôi). Có lẽ hỏi quá nhiều mặc dù :)
Jesse Aldridge

4
@JlieAldridge Ý kiến ​​hay. Tôi đã đi trước và thêm mã với phương pháp ưa thích chỉ.
Dave.B

1
@bluesm Thật lòng tôi chỉ không nghĩ về nó nhưng vâng, nó sẽ hoạt động tốt.
Dave.B

84

Nó đơn giản! Bạn tạo bộ đếm thời gian mới.

Timer timer = new Timer();

Sau đó, bạn mở rộng nhiệm vụ hẹn giờ

class UpdateBallTask extends TimerTask {
   Ball myBall;

   public void run() {
       //calculate the new position of myBall
   }
}

Và sau đó thêm tác vụ mới vào Timer với một số khoảng thời gian cập nhật

final int FPS = 40;
TimerTask updateBall = new UpdateBallTask();
timer.scheduleAtFixedRate(updateBall, 0, 1000/FPS);

Disclaimer: Đây không phải là giải pháp lý tưởng. Đây là giải pháp sử dụng lớp Timer (theo yêu cầu của OP). Trong SDK Android, nên sử dụng lớp Handler (có ví dụ trong câu trả lời được chấp nhận).


1
nếu bạn đọc bài viết ở trên, bạn sẽ thấy tại sao đây không phải là một giải pháp lý tưởng
Dave.B

2
Tất nhiên. OP muốn làm điều đó với TimerTask, mà tôi sẽ không khuyến nghị sử dụng trong trò chơi.
tiểu thuyết

3
Huh? OP đã không xác định cách họ muốn nó được thực hiện. Họ đã liên kết đến một bài viết sử dụng TimerTask, nhưng họ không yêu cầu nó được thực hiện theo cách đó.
ToolmakerSteve

1
Đã giúp rất nhiều, Cảm ơn @fiction
Naveed Ahmad

1
câu trả lời tuyệt vời đơn giản để làm theo.
JMASTER B

64

Nếu bạn cũng cần chạy mã của mình trên luồng UI (chứ không phải trên chuỗi hẹn giờ), hãy xem blog: http : //steve.odyf Family.com/?p=12

public class myActivity extends Activity {
private Timer myTimer;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.main);

    myTimer = new Timer();
    myTimer.schedule(new TimerTask() {          
        @Override
        public void run() {
            TimerMethod();
        }

    }, 0, 1000);
}

private void TimerMethod()
{
    //This method is called directly by the timer
    //and runs in the same thread as the timer.

    //We call the method that will work with the UI
    //through the runOnUiThread method.
    this.runOnUiThread(Timer_Tick);
}


private Runnable Timer_Tick = new Runnable() {
    public void run() {

    //This method runs in the same thread as the UI.               

    //Do something to the UI thread here

    }
};
}

Để hoàn thiện, có lẽ bạn có thể đề cập đến những việc cần làm để dừng bộ hẹn giờ và có thể khởi động lại nó. (Tôi đã tìm thấy thông tin cần thiết ở đây: stackoverflow.com/questions/11550561/ cấp )
RenniePet

3
Có bất kỳ lý do nào bạn không thể gọi trực tiếp runOnUIThread từ phương thức chạy TimerTask không? Có vẻ hoạt động tốt và loại bỏ một mức độ làm tổ khác.
RichieHH

Chắc chắn, nó chỉ là một phương pháp giáo khoa để hiểu tất cả các bước. Tôi đề nghị tiêu chuẩn này để có một mã dễ đọc.
Meir Gerenstadt

41

Nếu người ta chỉ muốn lên lịch đếm ngược cho đến một thời điểm trong tương lai với các thông báo thường xuyên theo chu kỳ, bạn có thể sử dụng lớp CountDownTimer có sẵn kể từ API cấp 1.

new CountDownTimer(30000, 1000) {
    public void onTick(long millisUntilFinished) {
        editText.setText("Seconds remaining: " + millisUntilFinished / 1000);
    }

    public void onFinish() {
        editText.setText("Done");
    }
}.start();

2
CountDownTimer chỉ có ý nghĩa nếu bạn biết rằng bạn muốn nó biến mất sau vài lần thực thi. Đây không phải là một cách tiếp cận điển hình, cũng không đặc biệt linh hoạt. Phổ biến hơn là bộ đếm thời gian lặp lại mãi mãi (mà bạn hủy khi không còn cần thiết) hoặc trình xử lý chạy một lần, sau đó tự khởi động lại nếu cần thiết một lần nữa. Xem câu trả lời khác.
ToolmakerSteve

1
Bạn hoàn toàn đúng. Từ tên lớp, nó cung cấp một lần đếm ngược thời gian đếm ngược cho đến khi kết thúc và tất nhiên nó sử dụng Handler trong quá trình thực hiện.
Ahmed Hegazy

Làm thế nào để hiển thị mili giây cũng? Trong định dạng SS:MiMi? Cảm ơn
Ruchir Baronia

26

Đây là một số mã đơn giản cho một bộ đếm thời gian:

Timer timer = new Timer();
TimerTask t = new TimerTask() {       
    @Override
    public void run() {

        System.out.println("1");
    }
};
timer.scheduleAtFixedRate(t,1000,1000);

12

Tôi nghĩ bạn có thể làm điều đó theo cách Rx như:

 timerSubscribe = Observable.interval(1, TimeUnit.SECONDS)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Action1<Long>() {
                @Override
                public void call(Long aLong) {
                      //TODO do your stuff
                }
            });

Và hủy bỏ như thế này:

timerSubscribe.unsubscribe();

Bộ định thời Rx http://reactivex.io/documentation/operators/timer.html


10

Bởi vì câu hỏi này vẫn đang thu hút rất nhiều người dùng từ tìm kiếm google (về bộ đếm thời gian Android), tôi muốn chèn hai đồng tiền của mình.

Trước hết, lớp Timer sẽ không được dùng trong Java 9 (đọc câu trả lời được chấp nhận) .

Cách chính thức được đề xuất là sử dụng lên lịchThreadPoolExecutor , có hiệu quả và giàu tính năng hơn, có thể lên lịch các lệnh để chạy sau một độ trễ nhất định hoặc thực hiện định kỳ. Thêm vào đó, nó cung cấp thêm tính linh hoạt và khả năng của ThreadPoolExecutor.

Dưới đây là một ví dụ về việc sử dụng các chức năng đơn giản.

  1. Tạo dịch vụ thực thi:

    final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1);
  2. Chỉ cần lên lịch bạn có thể chạy:

    final Future<?> future = SCHEDULER.schedule(Runnable task, long delay,TimeUnit unit);
  3. Bây giờ bạn có thể sử dụng futuređể hủy tác vụ hoặc kiểm tra nếu nó được thực hiện chẳng hạn:

    future.isDone();

Hy vọng bạn sẽ thấy điều này hữu ích cho việc tạo một tác vụ trong Android.

Ví dụ hoàn chỉnh:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Future<?> sampleFutureTimer = scheduler.schedule(new Runnable(), 120, TimeUnit.SECONDS);
if (sampleFutureTimer.isDone()){
    // Do something which will save world.
}

8

Tôi ngạc nhiên rằng không có câu trả lời nào đề cập đến giải pháp với RxJava2 . Nó thực sự đơn giản và cung cấp một cách dễ dàng để thiết lập bộ đếm thời gian trong Android.

Trước tiên, bạn cần thiết lập phụ thuộc Gradle, nếu bạn chưa làm như vậy:

implementation "io.reactivex.rxjava2:rxjava:2.x.y"

(thay thế xyvới số phiên bản hiện tại )

Vì chúng ta chỉ có một NHIỆM VỤ KHÔNG SỬA CHỮA đơn giản , chúng ta có thể sử dụng Completableđối tượng:

Completable.timer(2, TimeUnit.SECONDS, Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(() -> {
            // Timer finished, do something...
        });

Đối với NHIỆM VỤ REPEATING , bạn có thể sử dụng Observabletheo cách tương tự:

Observable.interval(2, TimeUnit.SECONDS, Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(tick -> {
            // called every 2 seconds, do something...
        }, throwable -> {
            // handle error
        });

Schedulers.computation()đảm bảo rằng bộ định thời của chúng tôi đang chạy trên luồng nền và .observeOn(AndroidSchedulers.mainThread())có nghĩa là mã chúng tôi chạy sau khi kết thúc bộ hẹn giờ sẽ được thực hiện trên luồng chính.

Để tránh rò rỉ bộ nhớ không mong muốn, bạn nên đảm bảo hủy đăng ký khi Activity / Fragment bị hủy.


4
Đây là cách tiếp cận sạch nhất!
Constantin

Làm thế nào để hủy bỏ những thứ này? tức là khi người dùng nhấn nút [STOP] trên giao diện người dùng và Hoàn thành sẽ bị hủy trước khi thực hiện.
Ai đó ở đâu đó

@SomeoneSomewhere Chỉ cần lưu phương thức Subscriptionđược trả về .subscribe()trong biến và sau đó gọi subscription.unsubscribe()khi bạn muốn dừng bộ hẹn giờ.
Micer

2

Anh ấy là giải pháp đơn giản hơn, hoạt động tốt trong ứng dụng của tôi.

  public class MyActivity extends Acitivity {

    TextView myTextView;
    boolean someCondition=true;

     @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.my_activity);

            myTextView = (TextView) findViewById(R.id.refreshing_field);

            //starting our task which update textview every 1000 ms
            new RefreshTask().execute();



        }

    //class which updates our textview every second

    class RefreshTask extends AsyncTask {

            @Override
            protected void onProgressUpdate(Object... values) {
                super.onProgressUpdate(values);
                String text = String.valueOf(System.currentTimeMillis());
                myTextView.setText(text);

            }

            @Override
            protected Object doInBackground(Object... params) {
                while(someCondition) {
                    try {
                        //sleep for 1s in background...
                        Thread.sleep(1000);
                        //and update textview in ui thread
                        publishProgress();
                    } catch (InterruptedException e) {
                        e.printStackTrace(); 

                };
                return null;
            }
        }
    }

2

Bạn muốn cập nhật giao diện người dùng của mình xảy ra trong luồng UI đã tồn tại.

Cách tốt nhất là sử dụng Trình xử lý sử dụng postDelayed để chạy Runnable sau khi trì hoãn (mỗi lần chạy lịch trình tiếp theo); xóa cuộc gọi lại với removeCallbacks.

Bạn đã tìm đúng chỗ, vì vậy hãy nhìn lại, có lẽ làm rõ lý do tại sao mẫu mã đó không phải là thứ bạn muốn. (Xem thêm bài viết giống hệt tại Cập nhật giao diện người dùng từ Timer ).


Thật không may, liên kết của bạn đã chết. Tôi không thể nhanh chóng tìm lại bài viết chính xác.
Lekensteyn


1

Đây là một cách đáng tin cậy đơn giản ...

Đặt mã sau vào Hoạt động của bạn và phương thức tick () sẽ được gọi mỗi giây trong luồng UI trong khi hoạt động của bạn ở trạng thái "tiếp tục". Tất nhiên, bạn có thể thay đổi phương thức tick () để làm những gì bạn muốn hoặc được gọi nhiều hơn hoặc ít thường xuyên hơn.

@Override
public void onPause() {
    _handler = null;
    super.onPause();
}

private Handler _handler;

@Override
public void onResume() {
    super.onResume();
    _handler = new Handler();
    Runnable r = new Runnable() {
        public void run() {
            if (_handler == _h0) {
                tick();
                _handler.postDelayed(this, 1000);
            }
        }

        private final Handler _h0 = _handler;
    };
    r.run();
}

private void tick() {
    System.out.println("Tick " + System.currentTimeMillis());
}

Đối với những người quan tâm, mã "_h0 = _handler" là cần thiết để tránh hai bộ định thời chạy cùng lúc nếu hoạt động của bạn bị tạm dừng và tiếp tục trong khoảng thời gian đánh dấu.


2
Tại sao làm _h0phương pháp khó xử này , thay vì removeCallbackstrong onPause, như mọi người khác?
ToolmakerSteve

1

Bạn cũng có thể sử dụng một trình hoạt hình cho nó:

int secondsToRun = 999;

ValueAnimator timer = ValueAnimator.ofInt(secondsToRun);
timer.setDuration(secondsToRun * 1000).setInterpolator(new LinearInterpolator());
timer.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
    {
        @Override
        public void onAnimationUpdate(ValueAnimator animation)
        {
            int elapsedSeconds = (int) animation.getAnimatedValue();
            int minutes = elapsedSeconds / 60;
            int seconds = elapsedSeconds % 60;

            textView.setText(String.format("%d:%02d", minutes, seconds));
        }
    });
timer.start();

0

Bạn cần tạo một luồng để xử lý vòng cập nhật và sử dụng nó để cập nhật textarea. Mặc dù vậy, phần khó khăn là chỉ có luồng chính thực sự có thể sửa đổi ui, vì vậy luồng vòng lặp cập nhật cần báo hiệu cho luồng chính để thực hiện cập nhật. Điều này được thực hiện bằng cách sử dụng Handler.

Kiểm tra liên kết này: http://developer.android.com/guide/topics/ui/dialogs.html# Nhấp vào phần có tiêu đề "Ví dụ ProgressDialog với một chuỗi thứ hai". Đây là một ví dụ về chính xác những gì bạn cần làm, ngoại trừ với hộp thoại tiến trình thay vì trường văn bản.


Đừng làm điều này. Có một lớp hẹn giờ đơn giản làm tất cả điều này cho bạn. Và câu hỏi này không có gì để làm với các tiến trình, hoặc các hộp thoại cả.
Falmarri

Bạn đã nhìn vào phần của liên kết tôi đã đăng hoặc bạn chỉ thấy hộp thoại từ và giả sử? Mã có liên quan 100%. Ngoài ra FYI, nếu bạn sử dụng bộ đếm thời gian, bạn vẫn đang tạo một luồng để xử lý vòng cập nhật. Bạn vẫn sẽ cần sử dụng Trình xử lý như được mô tả trong liên kết tôi đã đăng.
Nick

Thật không may, trang được liên kết không còn chứa một phần với tiêu đề được đề cập. Khi liên kết đến mã, người ta phải luôn bao gồm đoạn mã trực tiếp trong câu trả lời của bạn.
ToolmakerSteve

0
void method(boolean u,int max)
{
    uu=u;
    maxi=max;
    if (uu==true)
    { 
        CountDownTimer uy = new CountDownTimer(maxi, 1000) 
  {
            public void onFinish()
            {
                text.setText("Finish"); 
            }

            @Override
            public void onTick(long l) {
                String currentTimeString=DateFormat.getTimeInstance().format(new Date());
                text.setText(currentTimeString);
            }
        }.start();
    }

    else{text.setText("Stop ");
}

2
Có thể một số thụt mã và giải thích mã sẽ hữu ích.
Raul Rene

0

Nếu bất cứ ai quan tâm, tôi bắt đầu chơi xung quanh với việc tạo một đối tượng tiêu chuẩn để chạy trên luồng UI hoạt động. Có vẻ làm việc ok. Bình luận hoan nghênh. Tôi muốn điều này có sẵn trên trình thiết kế bố trí như một thành phần để kéo vào một Hoạt động. Không thể tin được những thứ như thế không tồn tại.

package com.example.util.timer;

import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;

public class ActivityTimer {

    private Activity m_Activity;
    private boolean m_Enabled;
    private Timer m_Timer;
    private long m_Delay;
    private long m_Period;
    private ActivityTimerListener m_Listener;
    private ActivityTimer _self;
    private boolean m_FireOnce;

    public ActivityTimer() {
        m_Delay = 0;
        m_Period = 100;
        m_Listener = null;
        m_FireOnce = false;
        _self = this;
    }

    public boolean isEnabled() {
        return m_Enabled;
    }

    public void setEnabled(boolean enabled) {
        if (m_Enabled == enabled)
            return;

        // Disable any existing timer before we enable a new one
        Disable();

        if (enabled) {
            Enable();
        }
    }

    private void Enable() {
        if (m_Enabled)
            return;

        m_Enabled = true;

        m_Timer = new Timer();
        if (m_FireOnce) {
            m_Timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    OnTick();
                }
            }, m_Delay);
        } else {
            m_Timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    OnTick();
                }
            }, m_Delay, m_Period);
        }
    }

    private void Disable() {
        if (!m_Enabled)
            return;

        m_Enabled = false;

        if (m_Timer == null)
            return;

        m_Timer.cancel();
        m_Timer.purge();
        m_Timer = null;
    }

    private void OnTick() {
        if (m_Activity != null && m_Listener != null) {
            m_Activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    m_Listener.OnTimerTick(m_Activity, _self);
                }
            });
        }
        if (m_FireOnce)
            Disable();
    }

    public long getDelay() {
        return m_Delay;
    }

    public void setDelay(long delay) {
        m_Delay = delay;
    }

    public long getPeriod() {
        return m_Period;
    }

    public void setPeriod(long period) {
        if (m_Period == period)
            return;
        m_Period = period;
    }

    public Activity getActivity() {
        return m_Activity;
    }

    public void setActivity(Activity activity) {
        if (m_Activity == activity)
            return;
        m_Activity = activity;
    }

    public ActivityTimerListener getActionListener() {
        return m_Listener;
    }

    public void setActionListener(ActivityTimerListener listener) {
        m_Listener = listener;
    }

    public void start() {
        if (m_Enabled)
            return;
        Enable();
    }

    public boolean isFireOnlyOnce() {
        return m_FireOnce;
    }

    public void setFireOnlyOnce(boolean fireOnce) {
        m_FireOnce = fireOnce;
    }
}

Trong hoạt động, tôi có cái này trên Khởi động:

@Override
protected void onStart() {
    super.onStart();

    m_Timer = new ActivityTimer();
    m_Timer.setFireOnlyOnce(true);
    m_Timer.setActivity(this);
    m_Timer.setActionListener(this);
    m_Timer.setDelay(3000);
    m_Timer.start();
}

1
Anh chàng có vấn đề gì với ActivityTimerListener? Gói ADT của tôi nói rằng không có lớp học như vậy.
Sorokin Andrey

0
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;

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

public class MainActivity extends Activity {

 CheckBox optSingleShot;
 Button btnStart, btnCancel;
 TextView textCounter;

 Timer timer;
 MyTimerTask myTimerTask;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  optSingleShot = (CheckBox)findViewById(R.id.singleshot);
  btnStart = (Button)findViewById(R.id.start);
  btnCancel = (Button)findViewById(R.id.cancel);
  textCounter = (TextView)findViewById(R.id.counter);

  btnStart.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {

    if(timer != null){
     timer.cancel();
    }

    //re-schedule timer here
    //otherwise, IllegalStateException of
    //"TimerTask is scheduled already" 
    //will be thrown
    timer = new Timer();
    myTimerTask = new MyTimerTask();

    if(optSingleShot.isChecked()){
     //singleshot delay 1000 ms
     timer.schedule(myTimerTask, 1000);
    }else{
     //delay 1000ms, repeat in 5000ms
     timer.schedule(myTimerTask, 1000, 5000);
    }
   }});

  btnCancel.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    if (timer!=null){
     timer.cancel();
     timer = null;
    }
   }
  });

 }

 class MyTimerTask extends TimerTask {

  @Override
  public void run() {
   Calendar calendar = Calendar.getInstance();
   SimpleDateFormat simpleDateFormat = 
     new SimpleDateFormat("dd:MMMM:yyyy HH:mm:ss a");
   final String strDate = simpleDateFormat.format(calendar.getTime());

   runOnUiThread(new Runnable(){

    @Override
    public void run() {
     textCounter.setText(strDate);
    }});
  }

 }

}

.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=".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" />
<CheckBox 
    android:id="@+id/singleshot"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Single Shot"/>


Tôi thấy rằng bạn đã thêm điều này vài năm sau câu hỏi và câu trả lời ban đầu. Vui lòng thêm giải thích về cách câu trả lời này so với các câu trả lời khác đã có. Tại sao bạn lại thêm cái khác - lợi ích / khi hữu ích / thiếu sót gì bạn thấy trong các câu trả lời khác?
ToolmakerSteve

Tôi chỉ chia sẻ một mã đang làm việc tương tự với một cách tiếp cận khác. Nhưng bất cứ khi nào bạn muốn cập nhật bất kỳ dữ liệu của chế độ xem. Bạn phải sử dụng xử lý cho nó. bởi vì nhiều lần tôi đã nhận thấy rằng việc sử dụng một khung thời gian để cập nhật một khung nhìn không hoạt động .. @ Phương pháp Dave.B đúng hơn với kiến ​​thức của tôi.
Zar E Ahmer

0

Nếu bạn có thời gian delta.

public class Timer {
    private float lastFrameChanged;
    private float frameDuration;
    private Runnable r;

    public Timer(float frameDuration, Runnable r) {
        this.frameDuration = frameDuration;
        this.lastFrameChanged = 0;
        this.r = r;
    }

    public void update(float dt) {
        lastFrameChanged += dt;

        if (lastFrameChanged > frameDuration) {
            lastFrameChanged = 0;
            r.run();
        }
    }
}

0

Tôi Tóm tắt Timer đi và biến nó thành một lớp riêng biệt:

Timer.java

import android.os.Handler;

public class Timer {

    IAction action;
    Handler timerHandler = new Handler();
    int delayMS = 1000;

    public Timer(IAction action, int delayMS) {
        this.action = action;
        this.delayMS = delayMS;
    }

    public Timer(IAction action) {
        this(action, 1000);
    }

    public Timer() {
        this(null);
    }

    Runnable timerRunnable = new Runnable() {

        @Override
        public void run() {
            if (action != null)
                action.Task();
            timerHandler.postDelayed(this, delayMS);
        }
    };

    public void start() {
        timerHandler.postDelayed(timerRunnable, 0);
    }

    public void stop() {
        timerHandler.removeCallbacks(timerRunnable);
    }
}

Và trích xuất hành động chính từ Timerlớp ra như

IAction.java

public interface IAction {
    void Task();
}

Và tôi đã sử dụng nó như thế này:

MainActivity.java

public class MainActivity extends Activity implements IAction{
...
Timer timerClass;
@Override
protected void onCreate(Bundle savedInstanceState) {
        ...
        timerClass = new Timer(this,1000);
        timerClass.start();
        ...
}
...
int i = 1;
@Override
public void Task() {
    runOnUiThread(new Runnable() {

        @Override
        public void run() {
            timer.setText(i + "");
            i++;
        }
    });
}
...
}

Tôi hy vọng điều này sẽ giúp


0

Tôi sử dụng cách này:

String[] array={
       "man","for","think"
}; int j;

sau đó bên dưới onCreate

TextView t = findViewById(R.id.textView);

    new CountDownTimer(5000,1000) {

        @Override
        public void onTick(long millisUntilFinished) {}

        @Override
        public void onFinish() {
            t.setText("I "+array[j] +" You");
            j++;
            if(j== array.length-1) j=0;
            start();
        }
    }.start();

đó là cách dễ dàng để giải quyết vấn đề này.


0

Đối với những người không thể dựa vào Chronometer , tôi đã tạo một lớp tiện ích từ một trong những gợi ý:

public class TimerTextHelper implements Runnable {
   private final Handler handler = new Handler();
   private final TextView textView;
   private volatile long startTime;
   private volatile long elapsedTime;

   public TimerTextHelper(TextView textView) {
       this.textView = textView;
   }

   @Override
   public void run() {
       long millis = System.currentTimeMillis() - startTime;
       int seconds = (int) (millis / 1000);
       int minutes = seconds / 60;
       seconds = seconds % 60;

       textView.setText(String.format("%d:%02d", minutes, seconds));

       if (elapsedTime == -1) {
           handler.postDelayed(this, 500);
       }
   }

   public void start() {
       this.startTime = System.currentTimeMillis();
       this.elapsedTime = -1;
       handler.post(this);
   }

   public void stop() {
       this.elapsedTime = System.currentTimeMillis() - startTime;
       handler.removeCallbacks(this);
   }

   public long getElapsedTime() {
       return elapsedTime;
   }
 }

sử dụng..chỉ cần làm:

 TimerTextHelper timerTextHelper = new TimerTextHelper(textView);
 timerTextHelper.start();

.....

 timerTextHelper.stop();
 long elapsedTime = timerTextHelper.getElapsedTime();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.