oreo - android pie
Repita una tarea con un retraso de tiempo? (10)
Tengo una variable en mi código que dice que es "estado".
Quiero mostrar algo de texto en la aplicación dependiendo de este valor de variable. Esto tiene que hacerse con un retraso de tiempo específico.
Es como,
Comprobar el valor de la variable de estado
Mostrar un texto
Espera 10 segundos
Comprobar el valor de la variable de estado
Mostrar un texto
Espere 15 segundos
y así. El retraso de tiempo puede variar y se establece una vez que se muestra el texto.
He intentado Thread.sleep(time delay)
y falló. ¿Alguna mejor manera de hacer esto?
Basado en la publicación anterior sobre el ScheduledThreadPoolExecutor , se me ocurrió una utilidad que se ajustaba a mis necesidades (quería lanzar un método cada 3 segundos):
class MyActivity {
private ScheduledThreadPoolExecutor mDialogDaemon;
private void initDebugButtons() {
Button btnSpawnDialogs = (Button)findViewById(R.id.btn_spawn_dialogs);
btnSpawnDialogs.setVisibility(View.VISIBLE);
btnSpawnDialogs.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
spawnDialogs();
}
});
}
private void spawnDialogs() {
if (mDialogDaemon != null) {
mDialogDaemon.shutdown();
mDialogDaemon = null;
}
mDialogDaemon = new ScheduledThreadPoolExecutor(1);
// This process will execute immediately, then execute every 3 seconds.
mDialogDaemon.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
// Do something worthwhile
}
});
}
}, 0L, 3000L, TimeUnit.MILLISECONDS);
}
}
Creo que el nuevo calor es usar un ScheduledThreadPoolExecutor . Al igual que:
private final ScheduledThreadPoolExecutor executor_ =
new ScheduledThreadPoolExecutor(1);
this.executor_.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
update();
}
}, 0L, kPeriod, kTimeUnit);
Debería usar la función postDelayed
Handler
para este propósito. Ejecutará el código con la demora especificada en la secuencia de la interfaz de usuario principal, por lo que podrá actualizar los controles de la interfaz de usuario.
private int mInterval = 5000; // 5 seconds by default, can be changed later
private Handler mHandler;
@Override
protected void onCreate(Bundle bundle) {
// your code here
mHandler = new Handler();
startRepeatingTask();
}
@Override
public void onDestroy() {
super.onDestroy();
stopRepeatingTask();
}
Runnable mStatusChecker = new Runnable() {
@Override
public void run() {
try {
updateStatus(); //this function can change value of mInterval.
} finally {
// 100% guarantee that this always happens, even if
// your update method throws an exception
mHandler.postDelayed(mStatusChecker, mInterval);
}
}
};
void startRepeatingTask() {
mStatusChecker.run();
}
void stopRepeatingTask() {
mHandler.removeCallbacks(mStatusChecker);
}
El temporizador es otra forma de hacer su trabajo, pero asegúrese de agregar runOnUiThread
si está trabajando con UI.
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);
}});
}
}
}
y xml es ...
<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"/>
Otra forma de usar CountDownTimer
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();
Programe una cuenta regresiva hasta un momento en el futuro, con notificaciones regulares en intervalos en el camino. Ejemplo de mostrar una cuenta atrás de 30 segundos en un campo de texto:
En mi caso, tuve que ejecutar un proceso si una de estas condiciones era verdadera: si se completó un proceso anterior o si ya pasaron 5 segundos. Entonces, hice lo siguiente y funcionó bastante bien:
private Runnable mStatusChecker;
private Handler mHandler;
class {
method() {
mStatusChecker = new Runnable() {
int times = 0;
@Override
public void run() {
if (times < 5) {
if (process1.isRead()) {
executeProcess2();
} else {
times++;
mHandler.postDelayed(mStatusChecker, 1000);
}
} else {
executeProcess2();
}
}
};
mHandler = new Handler();
startRepeatingTask();
}
void startRepeatingTask() {
mStatusChecker.run();
}
void stopRepeatingTask() {
mHandler.removeCallbacks(mStatusChecker);
}
}
Si se lee el proceso1, ejecuta el proceso2. De lo contrario, incrementa la variable veces, y hace que el controlador se ejecute después de un segundo. Mantiene un bucle hasta que se lea el proceso1 o el tiempo sea 5. Cuando el tiempo es 5, significa que pasaron 5 segundos y en cada segundo se ejecuta la cláusula if de process1.isRead ().
Intenta seguir el ejemplo, ¡funciona!
Utilice [Handler] en el método onCreate () que utiliza el método postDelayed () que hace que Runnable se agregue a la cola de mensajes, para que se ejecute una vez transcurrido el tiempo especificado que es 0 en el ejemplo dado. 1
Consulte este código:
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//------------------
//------------------
android.os.Handler customHandler = new android.os.Handler();
customHandler.postDelayed(updateTimerThread, 0);
}
private Runnable updateTimerThread = new Runnable()
{
public void run()
{
//write here whaterver you want to repeat
customHandler.postDelayed(this, 1000);
}
};
Para cualquier persona interesada, he aquí una clase que he creado utilizando el código de inazaruk que crea todo lo que necesito (lo llamé UIUpdater porque lo uso para actualizar periódicamente la interfaz de usuario, pero puede llamarlo como quiera):
import android.os.Handler;
/**
* A class used to perform periodical updates,
* specified inside a runnable object. An update interval
* may be specified (otherwise, the class will perform the
* update every 2 seconds).
*
* @author Carlos Simões
*/
public class UIUpdater {
// Create a Handler that uses the Main Looper to run in
private Handler mHandler = new Handler(Looper.getMainLooper());
private Runnable mStatusChecker;
private int UPDATE_INTERVAL = 2000;
/**
* Creates an UIUpdater object, that can be used to
* perform UIUpdates on a specified time interval.
*
* @param uiUpdater A runnable containing the update routine.
*/
public UIUpdater(final Runnable uiUpdater) {
mStatusChecker = new Runnable() {
@Override
public void run() {
// Run the passed runnable
uiUpdater.run();
// Re-run it after the update interval
mHandler.postDelayed(this, UPDATE_INTERVAL);
}
};
}
/**
* The same as the default constructor, but specifying the
* intended update interval.
*
* @param uiUpdater A runnable containing the update routine.
* @param interval The interval over which the routine
* should run (milliseconds).
*/
public UIUpdater(Runnable uiUpdater, int interval){
UPDATE_INTERVAL = interval;
this(uiUpdater);
}
/**
* Starts the periodical update routine (mStatusChecker
* adds the callback to the handler).
*/
public synchronized void startUpdates(){
mStatusChecker.run();
}
/**
* Stops the periodical update routine from running,
* by removing the callback.
*/
public synchronized void stopUpdates(){
mHandler.removeCallbacks(mStatusChecker);
}
}
Luego puedes crear un objeto UIUpdater dentro de tu clase y usarlo así:
...
mUIUpdater = new UIUpdater(new Runnable() {
@Override
public void run() {
// do stuff ...
}
});
// Start updates
mUIUpdater.startUpdates();
// Stop updates
mUIUpdater.stopUpdates();
...
Si desea utilizar esto como un actualizador de actividad, coloque la llamada de inicio dentro del método onResume () y la llamada de detención dentro de onPause (), de modo que las actualizaciones comiencen y dejen de acuerdo con la visibilidad de la actividad.
Puede usar un controlador para publicar código ejecutable. Esta técnica se describe muy bien aquí: https://guides.codepath.com/android/Repeating-Periodic-Tasks
Timer funciona bien. Aquí, uso Timer para buscar texto después de 1.5 sy actualizar la IU. Espero que ayude.
private Timer _timer = new Timer();
_timer.schedule(new TimerTask() {
@Override
public void run() {
// use runOnUiThread(Runnable action)
runOnUiThread(new Runnable() {
@Override
public void run() {
search();
}
});
}
}, timeInterval);
Hazlo en la forma de Android con la ayuda de Handler .
Declare una clase Handler interna que no pierda Memory en su clase Activity / Fragment
/**
* Instances of static inner classes do not hold an implicit
* reference to their outer class.
*/
private static class NonLeakyHandler extends Handler {
private final WeakReference<FlashActivity> mActivity;
public NonLeakyHandler(FlashActivity activity) {
mActivity = new WeakReference<FlashActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
FlashActivity activity = mActivity.get();
if (activity != null) {
// ...
}
}
}
Declare un ejecutable que realizará su tarea repetitiva en su clase Activity / Fragment
private Runnable repeatativeTaskRunnable = new Runnable() {
public void run() {
new Handler(getMainLooper()).post(new Runnable() {
@Override
public void run() {
//DO YOUR THINGS
}
};
Inicialice el objeto Handler en su Activity / Fragment (aquí FlashActivity es mi clase de actividad)
//Task Handler
private Handler taskHandler = new NonLeakyHandler(FlashActivity.this);
Para repetir una tarea después del intervalo de tiempo de reparación
taskHandler.postDelayed (repeatativeTaskRunnable, DELAY_MILLIS);
Para detener la repetición de la tarea
taskHandler .removeCallbacks (repeatativeTaskRunnable);