При попытке ограничить использование батареи мне не нужно иметь петли занятости, поэтому я не уверен, как решить эту проблему.
Если у меня есть программа, которая позволит кому-то петь в течение 45 секунд, они останавливаются на 20 секунд, чтобы выпить, а затем повторить несколько песен.
Мой таймер находится в Проблема получения таймера для работы после отмены одной итерации и начала другого, но для того, чтобы это работало, когда кто-то нажимает кнопку, он запускает первый отсчет времени, но время было поставлено в очередь, и заголовок был отображен, затем, когда время будет завершено, он покажет Rest, а затем через 20 секунд отобразит новое название.
Поэтому использование sendMessageDelayed
является проблемой, хотя оно работает для первой части.
В идеале я хотел бы вернуть Runnable
при обратном отсчете до некоторой функции контроллера, которая затем использовала бы оператор if.
void Controller(int curCount) {
if(curCount % 2 == 0) {
// call thread that uses runnable with next song time limit and title
} else {
// call thread with 20 and "REST"
}
}
Но это будет работать, только если
Thread t = new Thread(runnable);
... // Go to controller, which will count down
t.join();
заблокировано до завершения. Я мог бы сделать t.wait(time * 1000);
вместо t.join()
, но это может быть немного запоздалым или ранним, поскольку таймер не будет идеальным для поддержания времени, поэтому я не думаю, что это правильно.
Так что лучший способ сделать что-то подобное, без лишних опросов или циклов занятости.
for(SongModel m : songList) {
countdownTime(m.getSongTime(), m.getTitle);
countdownTime(10, "REST");
}
Edit:
Я думаю, что я не знал о проблеме с моим текущим таймером. Поскольку сообщения помещаются в очередь, они будут меняться на "Отдых", все еще отсчитывая время, оставшееся до первой песни, так как Runnable
заканчивается намного быстрее, чем обработка Handler
. Итак, есть недостаток в этом подходе, который заставляет меня думать, что этот дизайн с использованием sendMessageDelayed
не будет работать, как я надеялся, хотя, если мне просто нужно отсчитывать один раз/кнопку, это будет хорошо, но мои потребности состоят в том, чтобы все это произошло с одним нажатием кнопки, оно запускает процесс, а затем должно имитировать цикл for
в конце моего вопроса.
Здесь мы снова:)
Я написал это и протестировал его в Eclipse с эмулятором Eclair и работал нормально. Один клик рассчитывается от 54 до 0, затем от 20 до 0, затем от 45 до 0 и т.д., Пока другой клик не отменяет его. Дайте мне знать, если это соответствует вашим потребностям. Конечно, пользовательский интерфейс - это всего лишь минимальный минимум:
TimerTest.java
package com.aleadam.timertest;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class TimerTest extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button = (Button) findViewById(R.id.btn);
button.setOnClickListener(new MyListener ());
}
private class MyListener implements OnClickListener {
private long mStartTime = 0L;
private boolean started = false;
private boolean singing = true;
private final Handler mHandler = new Handler();
private Runnable mUpdateTimeTask;
TextView label, timer;
public MyListener() {
super();
label = (TextView) findViewById (R.id.lbl);
timer = (TextView) findViewById (R.id.timer);
}
public void onClick(View v) {
if (!started) {
started = true;
((Button) v).setText(R.string.button_label_stop);
mUpdateTimeTask = new Runnable() {
public void run() {
long millis = SystemClock.elapsedRealtime() - mStartTime;
if (singing && millis >= 45000L) {
label.setText(R.string.text_label_rest);
mStartTime = SystemClock.uptimeMillis();
timer.setText("20");
singing = false;
} else if (!singing && millis >= 20000L) {
label.setText(R.string.text_label_sing);
mStartTime = SystemClock.uptimeMillis();
timer.setText("45");
singing = true;
} else {
if (singing)
timer.setText(Long.toString(45-millis/1000));
else
timer.setText(Long.toString(20-millis/1000));
}
mHandler.postDelayed (mUpdateTimeTask, 1000);
}
};
singing = true;
mStartTime = SystemClock.uptimeMillis();
label.setText(R.string.text_label_sing);
timer.setText("45");
mHandler.removeCallbacks(mUpdateTimeTask);
mHandler.postDelayed(mUpdateTimeTask, 1000);
} else {
started = false;
mHandler.removeCallbacks(mUpdateTimeTask);
label.setText("");
timer.setText("");
((Button) v).setText(R.string.button_label_start);
}
}
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/title_label"
/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/button_label_start"
android:id="@+id/btn"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/lbl"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/timer"
android:textSize="24dp"
android:textStyle="bold"
android:typeface="monospace"/>
</LinearLayout>
strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="title_label">Timer test - 45 + 20 sec</string>
<string name="app_name">Timer Test</string>
<string name="button_label_start">Click to start</string>
<string name="text_label_sing">Sing for 45 seconds</string>
<string name="text_label_rest">20 seconds to drink!</string>
<string name="button_label_stop">Click to cancel</string>
</resources>
Я бы сделал это с помощью Timer
и пары TimerTasks
.
Timer scheduler = new Timer("Song Scheduler");
TimerTask restTask = new TimerTask() {
public void run() {
// call rest code
scheduler.schedule(songTask, 20*1000);
}
};
TimerTask songTask = new TimerTask() {
public void run() {
// call song code
scheduler.schedule(restTask, 45*1000);
}
};
Важно то, что я не планирую следующий таймер до истечения последнего. Вы можете отрегулировать время динамически, если вы хотите, чтобы songTask продолжала длительность текущей песни (как подсказывает ваш код) или 45 секунд (как предлагает ваша проза). В любом случае, основы одинаковы.
Listener
и создатьArrayList
или что угодно, что затем можно проверить в блокеif (!singing && millis >= 20000L)
чтобы определить, должен ли он вызывать новыйpostDelayed()
или просто вернись;