วิธีตั้งเวลาใน Android


172

เป็นวิธีที่เหมาะสมในการตั้งเวลาใน Android เพื่อเริ่มงาน (ฟังก์ชั่นที่ฉันสร้างที่ไม่เปลี่ยน UI) คืออะไร? ใช้วิธีนี้ของ Java: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Timer.html

หรือมีวิธีที่ดีกว่าใน Android (ตัวจัดการของ android)?

คำตอบ:


143

วิธี Java มาตรฐานเพื่อใช้ตัวจับเวลาผ่านjava.util.Timerและjava.util.TimerTaskทำงานได้ดีใน Android แต่คุณควรทราบว่าวิธีนี้จะสร้างเธรดใหม่

คุณอาจจะพิจารณาใช้สะดวกมากHandlerระดับ (android.os.Handler) และส่งข้อความไปยังตัวจัดการผ่านหรือsendMessageAtTime(android.os.Message, long) sendMessageDelayed(android.os.Message, long)เมื่อคุณได้รับข้อความคุณสามารถเรียกใช้งานที่ต้องการได้ ตัวเลือกที่สองจะสร้างRunnableวัตถุและกำหนดเวลาผ่านฟังก์ชั่นจัดการของหรือpostAtTime(java.lang.Runnable, long)postDelayed(java.lang.Runnable, long)


10
นี่เป็นวิธีที่ผิดในการทำสิ่งต่าง ๆ ใน Android ใน android คุณต้องการใช้ Alarm Manager (developer.android.com/reference/android/app/AlarmManager.html) เพื่อใช้งานในอนาคต
Kurtis Nusbaum

9
@ Kurtis Nusbaum คำถามไม่ได้บอกว่าในอนาคตงานมีมากแค่ไหน
Christopher Perry

67
@ KurtisNusbaum นั่นไม่จำเป็นต้องเป็นจริงเลยมันขึ้นอยู่กับบริบท เอกสารใน AlarmManager พูดว่า "หมายเหตุ: ตัวจัดการสัญญาณเตือนมีไว้สำหรับกรณีที่คุณต้องการให้รหัสแอปพลิเคชันของคุณทำงานในเวลาที่กำหนดแม้ว่าแอปพลิเคชันของคุณจะไม่ทำงานในปัจจุบันสำหรับการดำเนินการตามกำหนดเวลาปกติ มันง่ายกว่าและมีประสิทธิภาพกว่าในการใช้ Handler "
Christopher Perry

5
@Scienceprodigy อ่าฉันเข้าใจแล้ว ยุติธรรมพอสมควร
Kurtis Nusbaum

10
การใช้วิธีจัดการตัวตั้งเวลางานจะเชื่อถือได้เฉพาะเมื่อแอปพลิเคชันได้รับ WakeLock และด้วยเหตุนี้คุณจึงมั่นใจว่าโทรศัพท์จะไม่เข้าสู่โหมดสลีป หากโทรศัพท์เข้าสู่สถานะสลีปดังนั้น sendMessageDelayed และ sendMessageAtTime จะไม่ทำงาน ดังนั้นในสถานการณ์นั้น AlarmManager จะเป็นตัวเลือกที่น่าเชื่อถือ
crazyaboutliv

159

ใช่ตัวจับเวลาของ java สามารถใช้ได้แต่เป็นคำถามที่ถามวิธีที่ดีกว่า (สำหรับมือถือ) ซึ่งจะมีการอธิบายที่นี่


เพื่อประโยชน์ของ StackOverflow:

เนื่องจากตัวจับเวลาสร้างเธรดใหม่อาจถือว่าหนัก

หากสิ่งที่คุณต้องการคือการโทรกลับในขณะที่กิจกรรมกำลังเรียกใช้ตัวจัดการสามารถใช้ร่วมกับ

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);

หรือข้อความ

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);

ในหมายเหตุด้านวิธีการนี้สามารถใช้ถ้าคุณต้องการเรียกใช้ชิ้นส่วนของรหัสในเธรด UI จากเธรดอื่น

หากคุณต้องการโทรกลับแม้ว่ากิจกรรมของคุณจะไม่ทำงานคุณสามารถใช้AlarmManager ได้


1
ใช่แล้วฉันตอบคำตอบนี้ไปทุกประการ ใช้ upvote ของฉันสำหรับลิงก์ที่มีประโยชน์
ulidtko

1
อัปเดตลิงก์แล้วพูดคุยเกี่ยวกับ google ว่ามีปัญหาในการดูแลลิงก์
ซามูเอล

1
บทความนี้จากปี 2007 - ไม่ได้บอกว่ามันผิด แต่ฉันมักจะสงสัยบทความมือถือหากมีอายุมากกว่า 3 ปี สิ่งต่าง ๆ เปลี่ยนไปอย่างรวดเร็ว
StackOverflow

1
มันจะเป็นเหมือน StackOverflow ถ้าคุณสามารถอ้างอิงประเด็นหลักของลิงค์ที่นี่ในคำตอบของคุณ
n611x007

1
@naxa ฉันทั้งสองเซ็นต์เพื่อให้การตอบสนองนี้เป็นเหมือน StackOverflow
ซามูเอล

131

อย่างที่ฉันได้เห็นมันjava.util.Timerเป็นส่วนใหญ่ที่ใช้สำหรับการใช้ตัวจับเวลา

สำหรับงานที่ทำซ้ำ:

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

สำหรับการทำงานครั้งเดียว:

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


งานเป็นวิธีการที่จะดำเนินการ
หลังจากเวลาที่จะดำเนินการเริ่มต้น
( ช่วงเวลาสำหรับการทำซ้ำการดำเนินการ)


9
ฉันจะเพิ่มเวลานั้นในหน่วยมิลลิวินาที
Uri

2
android dev เอกสารสำหรับตารางเวลา
คงที่อัตรา

1
taskอาจจะเป็นตัวอย่างของการเรียนของคุณที่สืบทอดจากjava.util.TimerTaskvoid run()และแทนที่
n611x007

2
upvotes มากมาย คุณสามารถทำสิ่งนี้ แต่ @Samuel อธิบายวิธีที่ดีกว่า ดูลิงก์ "ซึ่งอธิบายที่นี่" ของเขาสำหรับเหตุผล นอกจากนี้ไม่สามารถอัปเดต UI จากเธรดตัวจับเวลาได้! และดูคำตอบที่ใช้ตัวจัดการอื่น ๆ เหล่านี้ในหัวข้ออื่น ๆ : (ง่าย) stackoverflow.com/a/6702767/199364หรือ (แสดงทางเลือกอื่น ๆ ) stackoverflow.com/a/4598737/199364
ToolmakerSteve

@quemeful เพราะมันไม่เกี่ยวกับความสะดวกสบายเสมอไปมันเกี่ยวกับคุณภาพของรหัสและประสิทธิภาพ วิธีการทำเช่นนี้จะใช้ทรัพยากรมากขึ้นแล้วใช้ Handler
ลึก

33

ฉันหวังว่าอันนี้มีประโยชน์และอาจใช้ความพยายามน้อยลงในการใช้งาน คลาส Android CountDownTimer

เช่น

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

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

1
นี่เป็นวิธีที่ง่ายที่สุดและเล่นได้อย่างง่ายดายบนหัวเพื่อนับถอยหลังอย่างง่าย ๆ เช่นเริ่มเล่นวิดีโอ
Vijay Kumar Kanta

17

อาจ 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();

หรือ

วิธีที่ 2 ::

ตั้งโปรแกรมจับเวลา

เพิ่มตัวแปรใหม่ของเวลาที่ตั้งชื่อไว้ ตั้งเป็น 0 เพิ่มรหัสต่อไปนี้เพื่อฟังก์ชั่น onCreate ใน 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);

ไปที่วิธีการเรียกใช้และเพิ่มรหัสต่อไปนี้

//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

มันเป็นสถานการณ์

เอกสาร Android แนะนำว่าคุณควรใช้AlarmManagerเพื่อลงทะเบียน Intent ที่จะดำเนินการตามเวลาที่กำหนดหากใบสมัครของคุณอาจไม่ทำงาน

มิฉะนั้นคุณควรใช้ตัวจัดการ

หมายเหตุ: ตัวจัดการสัญญาณเตือนมีไว้สำหรับกรณีที่คุณต้องการให้รหัสแอปพลิเคชันของคุณทำงานในเวลาที่กำหนดแม้ว่าแอปพลิเคชันของคุณจะไม่ทำงาน สำหรับการดำเนินการกำหนดเวลาตามปกติ (เห็บหมดเวลา ฯลฯ ) มันง่ายและมีประสิทธิภาพมากขึ้นในการใช้ Handler


11

ไปเลย .. เราจะต้องเรียนสองวิชา ฉันกำลังโพสต์รหัสซึ่งเปลี่ยนโปรไฟล์เสียงมือถือหลังจากผ่านไป 5 วินาที (5,000 mili วินาที) ...

ชั้นหนึ่งของเรา

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);
    }

}

ชั้นสองของเรา

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

ฉันเป็นมือใหม่ Android แต่นี่คือคลาสจับเวลาที่ฉันสร้างขึ้นตามคำตอบข้างต้น มันใช้งานได้กับแอพของฉัน แต่ฉันยินดีรับข้อเสนอแนะ

ตัวอย่างการใช้งาน:

...{
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

ฉันใช้ตัวจัดการและ runnable เพื่อสร้างตัวจับเวลา ฉันห่อสิ่งนี้ในชั้นนามธรรม เพิ่งได้รับ / ใช้งานและคุณพร้อมที่จะไป:

 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);
    }
}

โปรดทราบว่าhandler.postDelayedจะมีการเรียกใช้รหัสก่อนที่จะเรียกใช้งานซึ่งจะทำให้ตัวจับเวลาถูกปิดใช้งานมากขึ้นตามที่คาดไว้ อย่างไรก็ตามในกรณีที่ตัวจับเวลาทำงานเป็นประจำและงาน ( onTimer()) ยาว - อาจมีการทับซ้อน หากคุณต้องการเริ่มนับintervalMSหลังจากงานเสร็จแล้วให้ย้ายonTimer()สายที่โทรมาด้านบน


2

ฉันเชื่อว่าวิธีการทำเช่นนี้บน Android คือคุณต้องมีบริการพื้นหลังเพื่อให้ทำงานได้ ในแอปพลิเคชันเบื้องหลังให้สร้างตัวจับเวลา เมื่อตัวจับเวลา "เห็บ" (ตั้งค่าช่วงเวลาที่คุณต้องการรอ) ให้เปิดกิจกรรมที่คุณต้องการเริ่ม

http://developer.android.com/guide/topics/fundamentals.html (<- บทความนี้อธิบายถึงความสัมพันธ์ระหว่างกิจกรรมบริการเจตนาและพื้นฐานพื้นฐานอื่น ๆ ของการพัฒนา Android)


1

ฉันเคยใช้ ( Timer, TimerTask) เช่นเดียวกับHandlerการเริ่มงาน (ใช้เวลา) เป็นระยะ ๆ ตอนนี้ฉันเปลี่ยนไปเป็น RxJava ทั้งหมด RxJava ให้บริการObservable.timerซึ่งใช้งานง่ายกว่าไม่ผิดพลาดน้อยกว่าและไม่ยุ่งยาก

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

สำหรับการดำเนินงานระยะเวลาที่คุณควรใช้Handler

หากคุณต้องการเรียกใช้บริการพื้นหลัง AlarmManager เป็นวิธีที่จะไป


0

ตัวอย่างนี้เริ่มหน่วยจับเวลาที่ทำลายใน 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;
            }
        }

    }

ยกเลิก timertask ใน onDestroy ()

timerTask.cancel()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.