Cách đặt hẹn giờ trong Android


172

Cách thích hợp để đặt bộ hẹn giờ trong Android để khởi động một tác vụ (một chức năng mà tôi tạo không thay đổi giao diện người dùng) là gì? Sử dụng cách này theo cách Java: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Timer.html

Hoặc có một cách tốt hơn trong Android (xử lý của Android)?

Câu trả lời:


143

Cách Java tiêu chuẩn để sử dụng bộ định thời qua java.util.Timerjava.util.TimerTask hoạt động tốt trong Android, nhưng bạn nên lưu ý rằng phương thức này tạo ra một luồng mới.

Bạn có thể xem xét sử dụng lớp Handler rất tiện lợi (android.os.Handler) và gửi tin nhắn đến trình xử lý thông qua sendMessageAtTime(android.os.Message, long)hoặc sendMessageDelayed(android.os.Message, long). Khi bạn nhận được một tin nhắn, bạn có thể chạy các tác vụ mong muốn. Tùy chọn thứ hai sẽ là tạo một đối tượng Runnable và lên lịch cho nó thông qua các chức năng của Handler postAtTime(java.lang.Runnable, long)hoặc postDelayed(java.lang.Runnable, long).


10
Đây là cách sai để làm mọi thứ trong Android. Trong Android, bạn muốn sử dụng Trình quản lý báo thức (developer.android.com/reference/android/app/AlarmManager.html) để chạy các tác vụ trong tương lai.
Kurtis Nusbaum

9
@Kurtis Nusbaum Câu hỏi không nói nhiệm vụ trong tương lai là bao xa.
Christopher Perry

67
@KurtisNusbaum Điều đó không hẳn đúng, nó phụ thuộc vào bối cảnh. Các tài liệu trên AlarmManager cho biết: "Lưu ý: Trình quản lý báo thức dành cho các trường hợp bạn muốn mã ứng dụng của mình chạy vào một thời điểm cụ thể, ngay cả khi ứng dụng của bạn hiện không chạy. Đối với các hoạt động thời gian bình thường (tích tắc, hết giờ, v.v.) sử dụng Handler sẽ dễ dàng và hiệu quả hơn nhiều. "
Christopher Perry

5
@Scienceprodigy À, tôi hiểu rồi. Đủ công bằng.
Kurtis Nusbaum

10
sử dụng phương pháp Handler để lập lịch tác vụ chỉ đáng tin cậy nếu ứng dụng đã nhận được WakeLock và do đó bạn chắc chắn rằng điện thoại sẽ không chuyển sang trạng thái ngủ. Nếu điện thoại chuyển sang trạng thái ngủ thì sendMessageDelayed cũng như sendMessageAtTime sẽ không hoạt động. Do đó trong kịch bản đó, AlertManager sẽ là sự lựa chọn đáng tin cậy.
crazyaboutliv

159

có bộ đếm thời gian của java có thể được sử dụng , nhưng như câu hỏi yêu cầu cách tốt hơn (cho thiết bị di động). Điều này được giải thích ở đây .


Vì lợi ích của StackOverflow:

Timer tạo một luồng mới, nó có thể được coi là nặng

nếu tất cả những gì bạn cần là nhận được một cuộc gọi lại trong khi hoạt động đang chạy Trình xử có thể được sử dụng cùng với một

Runnable :

private final int interval = 1000; // 1 Second
private Handler handler = new Handler();
private Runnable runnable = new Runnable(){
    public void run() {
        Toast.makeText(MyActivity.this, "C'Mom no hands!", Toast.LENGTH_SHORT).show();
    }
};
...
handler.postAtTime(runnable, System.currentTimeMillis()+interval);
handler.postDelayed(runnable, interval);

hoặc một tin nhắn

private final int EVENT1 = 1; 
private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {         
        case Event1:
            Toast.makeText(MyActivity.this, "Event 1", Toast.LENGTH_SHORT).show();
            break;

        default:
            Toast.makeText(MyActivity.this, "Unhandled", Toast.LENGTH_SHORT).show();
            break;
        }
    }
};

...

Message msg = handler.obtainMessage(EVENT1);
handler.sendMessageAtTime(msg, System.currentTimeMillis()+interval);
handler.sendMessageDelayed(msg, interval);

ở một mặt lưu ý cách tiếp cận này có thể được sử dụng, nếu bạn muốn chạy một đoạn mã trong luồng UI từ một luồng khác.

nếu bạn cần để có được một cuộc gọi trở lại ngay cả khi hoạt động của bạn không hoạt động sau đó, bạn có thể sử dụng một AlarmManager


1
Vâng, tôi đã googled chính xác câu trả lời này. Lấy upvote của tôi cho các liên kết hữu ích.
ulidtko

1
đã cập nhật liên kết, nói về việc google gặp sự cố khi duy trì liên kết.
Samuel

1
Bài viết này từ năm 2007 - không nói sai, nhưng tôi luôn nghi ngờ về một bài viết trên thiết bị di động nếu nó cũ hơn 3 năm. Mọi thứ thay đổi khá nhanh.
StackOverflow

1
nó sẽ giống như StackOverflow hơn nếu bạn có thể trích dẫn những điểm chính của liên kết của bạn ở đây trong câu trả lời của bạn.
n611x007

1
@naxa, hai xu của tôi để làm cho phản hồi này giống với StackOverflow hơn.
Samuel

131

Như tôi đã thấy, java.util.Timer được sử dụng nhiều nhất để thực hiện bộ đếm thời gian.

Đối với một nhiệm vụ lặp lại:

new Timer().scheduleAtFixedRate(task, after, interval);

Đối với một lần chạy một nhiệm vụ:

new Timer().schedule(task, after);


tác vụ là phương thức được thực thi
sau thời gian thực hiện ban đầu
( khoảng thời gian để lặp lại thực thi)


9
Tôi sẽ chỉ thêm thời gian đó tính bằng mili giây
Uri

2
tài liệu dành cho Android dành cho lịch
trìnhAtFixedRate

1
taskcó thể là một thể hiện của lớp của bạn kế thừa từ java.util.TimerTask và ghi đè void run().
n611x007

2
Rất nhiều upvote. Bạn có thể làm điều này. Nhưng @Samuel mô tả cách tốt hơn. Xem liên kết "Điều này được giải thích ở đây" để biết lý do tại sao. Ngoài ra, không thể cập nhật giao diện người dùng từ luồng Timer! Và xem các câu trả lời dựa trên Handler khác trong các luồng khác: (đơn giản) stackoverflow.com/a/6702767/199364 hoặc (hiển thị nhiều lựa chọn thay thế khác) stackoverflow.com/a/4598737/199364
ToolmakerSteve

@quemiously vì nó không phải luôn luôn là về sự tiện lợi, đó là về chất lượng và hiệu quả mã. Cách làm này sử dụng nhiều tài nguyên hơn sau đó sử dụng Trình xử lý
inDepth

33

Tôi hy vọng điều này hữu ích và có thể mất ít nỗ lực hơn để triển khai, lớp Android CountDownTimer

ví dụ

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

      public void onFinish() {
          mTextField.setText("done!");
      }  
}.start();

1
Đây là cách dễ nhất và đánh ngay trên đầu để đếm ngược đơn giản như thời gian bắt đầu phát video
Vijay Kumar Kanta

17

Có lẽ Timerconcept

new CountDownTimer(40000, 1000) { //40000 milli seconds is total time, 1000 milli seconds is time interval

 public void onTick(long millisUntilFinished) {
  }
  public void onFinish() {
 }
}.start();

hoặc là

Phương pháp 2 ::

Lập trình hẹn giờ

Thêm một biến mới của int tên thời gian. Đặt nó thành 0. Thêm mã sau vào hàm onCreate trong MainActivity.java.

//Declare the timer
Timer t = new Timer();
//Set the schedule function and rate
t.scheduleAtFixedRate(new TimerTask() {

    @Override
    public void run() {
        //Called each time when 1000 milliseconds (1 second) (the period parameter)
    }

},
//Set how long before to start calling the TimerTask (in milliseconds)
0,
//Set the amount of time between each execution (in milliseconds)
1000);

Đi vào phương thức chạy và thêm đoạn mã sau.

//We must use this function in order to change the text view text
runOnUiThread(new Runnable() {

    @Override
    public void run() {
        TextView tv = (TextView) findViewById(R.id.main_timer_text);
        tv.setText(String.valueOf(time));
        time += 1;
    }

});

11

Nó là tình huống.

Các tài liệu Android gợi ý rằng bạn nên sử dụng AlarmManager đăng ký Intent mà sẽ cháy tại thời gian quy định nếu ứng dụng của bạn có thể không chạy.

Nếu không, bạn nên sử dụng Handler.

Lưu ý: Trình quản lý báo thức dành cho các trường hợp bạn muốn mã ứng dụng của mình chạy vào một thời điểm cụ thể, ngay cả khi ứng dụng của bạn hiện không chạy. Đối với các hoạt động thời gian bình thường (đánh dấu, hết thời gian, vv), sử dụng Handler sẽ dễ dàng và hiệu quả hơn nhiều.


11

Ở đây chúng tôi đi .. Chúng tôi sẽ cần hai lớp. Tôi đang đăng một mã thay đổi cấu hình âm thanh di động sau mỗi 5 giây (5000 mili giây) ...

Lớp 1 của chúng tôi

public class ChangeProfileActivityMain extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);

        Timer timer = new Timer();
        TimerTask updateProfile = new CustomTimerTask(ChangeProfileActivityMain.this);
        timer.scheduleAtFixedRate(updateProfile, 0, 5000);
    }

}

Lớp 2 của chúng tôi

public class CustomTimerTask extends TimerTask {

    private AudioManager audioManager;
    private Context context;
    private Handler mHandler = new Handler();

    // Write Custom Constructor to pass Context
    public CustomTimerTask(Context con) {
        this.context = con;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub

        // your code starts here.
        // I have used Thread and Handler as we can not show Toast without starting new thread when we are inside a thread.
        // As TimePicker has run() thread running., So We must show Toast through Handler.post in a new Thread. Thats how it works in Android..
        new Thread(new Runnable() {
            @Override
            public void run() {
                audioManager = (AudioManager) context.getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        if(audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) {
                            audioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
                            Toast.makeText(context, "Ringer Mode set to Normal", Toast.LENGTH_SHORT).show();
                        } else {
                            audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
                            Toast.makeText(context, "Ringer Mode set to Silent", Toast.LENGTH_SHORT).show();
                        }
                    }
                });
            }
        }).start();

    }

}

5

Tôi là người mới sử dụng Android nhưng đây là lớp hẹn giờ tôi tạo dựa trên các câu trả lời ở trên. Nó hoạt động cho ứng dụng của tôi nhưng tôi hoan nghênh mọi đề xuất.

Ví dụ sử dụng:

...{
public Handler uiHandler = new Handler();

  private Runnable runMethod = new Runnable()
    {
        public void run()
        {
              // do something
        }
    };

    timer = new UITimer(handler, runMethod, timeoutSeconds*1000);       
        timer.start();
}...

public class UITimer
{
    private Handler handler;
    private Runnable runMethod;
    private int intervalMs;
    private boolean enabled = false;
    private boolean oneTime = false;

    public UITimer(Handler handler, Runnable runMethod, int intervalMs)
    {
        this.handler = handler;
        this.runMethod = runMethod;
        this.intervalMs = intervalMs;
    }

    public UITimer(Handler handler, Runnable runMethod, int intervalMs, boolean oneTime)
    {
        this(handler, runMethod, intervalMs);
        this.oneTime = oneTime;
    }

    public void start()
    {
        if (enabled)
            return;

        if (intervalMs < 1)
        {
            Log.e("timer start", "Invalid interval:" + intervalMs);
            return;
        }

        enabled = true;
        handler.postDelayed(timer_tick, intervalMs);        
    }

    public void stop()
    {
        if (!enabled)
            return;

        enabled = false;
        handler.removeCallbacks(runMethod);
        handler.removeCallbacks(timer_tick);
    }

    public boolean isEnabled()
    {
        return enabled;
    }

    private Runnable timer_tick = new Runnable()
    {
        public void run()
        {
            if (!enabled)
                return;

            handler.post(runMethod);

            if (oneTime)
            {
                enabled = false;
                return;
            }

            handler.postDelayed(timer_tick, intervalMs);
        }
    }; 
}

3

Tôi đang sử dụng một trình xử lý và runnable để tạo một bộ đếm thời gian. Tôi gói cái này trong một lớp trừu tượng. Chỉ cần lấy / thực hiện nó và bạn tốt để đi:

 public static abstract class SimpleTimer {
    abstract void onTimer();

    private Runnable runnableCode = null;
    private Handler handler = new Handler();

    void startDelayed(final int intervalMS, int delayMS) {
        runnableCode = new Runnable() {
            @Override
            public void run() {
                handler.postDelayed(runnableCode, intervalMS);
                onTimer();
            }
        };
        handler.postDelayed(runnableCode, delayMS);
    }

    void start(final int intervalMS) {
        startDelayed(intervalMS, 0);
    }

    void stop() {
        handler.removeCallbacks(runnableCode);
    }
}

Lưu ý rằng mã handler.postDelayedđược gọi trước khi mã được thực thi - điều này sẽ làm cho bộ định thời đóng hơn theo thời gian là "mong đợi". Tuy nhiên, trong trường hợp bộ đếm thời gian chạy thường xuyên và tác vụ ( onTimer()) dài - có thể có sự chồng chéo. Nếu bạn muốn bắt đầu đếm intervalMSsau khi hoàn thành nhiệm vụ, hãy di chuyển onTimer()cuộc gọi một dòng ở trên.


2

Tôi tin rằng cách để làm điều này trên Android là bạn cần một dịch vụ nền để chạy. Trong ứng dụng nền đó, tạo bộ đếm thời gian. Khi bộ đếm thời gian "tích tắc" (đặt khoảng thời gian bạn muốn đợi), hãy khởi chạy hoạt động mà bạn muốn bắt đầu.

http://developer.android.com/guide/topics/fundamentals.html (<- bài viết này giải thích mối quan hệ giữa các hoạt động, dịch vụ, ý định và các nguyên tắc cơ bản cốt lõi khác của phát triển Android)


1

Tôi đã từng sử dụng ( Timer, TimerTask) cũng như Handlerđể khởi động các nhiệm vụ (tốn thời gian) theo định kỳ. Bây giờ tôi đã chuyển toàn bộ sang RxJava. RxJava cung cấp Observable.timerđơn giản hơn, ít lỗi hơn, không rắc rối khi sử dụng.

public class BetterTimerFragment extends Fragment {
  public static final String TAG = "BetterTimer";
  private TextView timeView;
  private Subscription timerSubscription;

  @Override
  public View onCreateView(LayoutInflater inflater,
                           @Nullable ViewGroup container,
                           @Nullable Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_timer, container, false);
  }

  @Override
  public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    timeView = (TextView) view.findViewById(R.id.timeView);
  }

  @Override
  public void onResume() {
    super.onResume();

    // Right after the app is visible to users, delay 2 seconds
    // then kick off a (heavy) task every 10 seconds.
    timerSubscription = Observable.timer(2, 10, TimeUnit.SECONDS)
        .map(new Func1<Long, String>() {
          @Override
          public String call(Long unused) {
            // TODO: Probably do time-consuming work here.
            // This runs on a different thread than the main thread.
            return "Time: " + System.currentTimeMillis();
          }
        })
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Action1<String>() {
          @Override
          public void call(String timeText) {
            // The result will then be propagated back to the main thread.
            timeView.setText(timeText);
          }
        }, new Action1<Throwable>() {
          @Override
          public void call(Throwable throwable) {
            Log.e(TAG, throwable.getMessage(), throwable);
          }
        });
  }

  @Override
  public void onPause() {
    super.onPause();

    // Don't kick off tasks when the app gets invisible.
    timerSubscription.unsubscribe();
  }
}

1

Đối với hoạt động thời gian, bạn nên sử dụng Handler .

Nếu bạn cần chạy một dịch vụ nền, thì Trình quản lý báo động là cách phù hợp.


0

ví dụ này bắt đầu đơn vị hẹn giờ bị phá hủy trong Kotlin

private lateinit var timerTask: TimerTask

 timerTask = object : TimerTask() {
        override fun run() {
            Log.d("KTZ", "$minutes:$seconds");
            timeRecordingLiveData.postValue("$minutes:$seconds")
            seconds += 1;
            if (seconds == 60) {
                Log.d("KTZ", "$minutes:$seconds");
                timeRecordingLiveData.postValue("$minutes:$seconds")
                seconds = 0;
                minutes += 1;
            }
        }

    }

Hủy bỏ timertask trong onDestroy ()

timerTask.cancel()
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.