java - otra - Cómo llamar a un método después de un retraso en Android
mandar a llamar un metodo de otra clase en java (24)
Abajo uno funciona cuando llegas,
java.lang.RuntimeException: no se puede crear un controlador dentro del hilo que no haya llamado a Looper.prepare ()
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
}
}, 100);
Quiero poder llamar al siguiente método después de un retraso específico. En el objetivo c había algo como:
[self performSelector:@selector(DoSomething) withObject:nil afterDelay:5];
¿Hay un equivalente de este método en Android con java? Por ejemplo, necesito poder llamar a un método después de 5 segundos.
public void DoSomething()
{
//do something here
}
Aquí está mi solución más corta:
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
}
}, 100);
Así que hay algunas cosas que considerar aquí ya que hay muchas maneras de pelar a este gato. Aunque ya se han dado todas las respuestas seleccionadas y elegidas. Creo que es importante que esto se revise nuevamente con las pautas de codificación adecuadas para evitar que alguien vaya en la dirección equivocada solo por la "respuesta simple seleccionada por la mayoría".
Entonces, primero discutamos la respuesta posplazada simple que es la respuesta ganadora seleccionada en general en este hilo.
Un par de cosas a considerar. Después de la demora posterior, puede encontrar fugas de memoria, objetos muertos, ciclos de vida que han desaparecido y más. Por lo tanto, manejarla correctamente también es importante. Puedes hacer esto de dos maneras.
Por el bien del desarrollo moderno, lo suministraré en KOTLIN
Este es un ejemplo simple de cómo usar el subproceso de la interfaz de usuario en una devolución de llamada y confirmar que su actividad sigue activa y activa cuando la recibe.
Handler(Looper.getMainLooper()).postDelayed({
if(activity != null && activity?.isFinishing == false){
txtNewInfo.visibility = View.GONE
}
}, NEW_INFO_SHOW_TIMEOUT_MS)
Sin embargo, esto todavía no es perfecto, ya que no hay razón para golpear su devolución de llamada si la actividad ha desaparecido. por lo tanto, una mejor manera sería mantener una referencia a él y eliminar sus devoluciones de llamada como esta.
private fun showFacebookStylePlus1NewsFeedOnPushReceived(){
A35Log.v(TAG, "showFacebookStylePlus1NewsFeedOnPushReceived")
if(activity != null && activity?.isFinishing == false){
txtNewInfo.visibility = View.VISIBLE
mHandler.postDelayed({
if(activity != null && activity?.isFinishing == false){
txtNewInfo.visibility = View.GONE
}
}, NEW_INFO_SHOW_TIMEOUT_MS)
}
}
y, por supuesto, manejar la limpieza en el onPause para que no llegue a la devolución de llamada.
override fun onPause() {
super.onPause()
mHandler.removeCallbacks(null)
}
Ahora que ya hemos hablado de lo obvio, hablemos de una opción más limpia con las modernas rutinas y kotlin :). Si no los estás usando todavía, realmente te los estás perdiendo.
fun doActionAfterDelay()
launch(UI) {
delay(MS_TO_DELAY)
actionToTake()
}
}
o si desea hacer siempre un inicio de UI en ese método, simplemente puede hacer:
fun doActionAfterDelay() = launch(UI){
delay(MS_TO_DELAY)
actionToTake()
}
Por supuesto, al igual que el PostDelayed, debe asegurarse de manejar la cancelación para poder realizar las comprobaciones de actividad después de la demora en la llamada o puede cancelarla en onPause al igual que en la otra ruta.
var mDelayedJob: Job? = null
fun doActionAfterDelay()
mDelayedJob = launch(UI) {
try {
delay(MS_TO_DELAY)
actionToTake()
}catch(ex: JobCancellationException){
showFancyToast("Delayed Job canceled", true, FancyToast.ERROR, "Delayed Job canceled: ${ex.message}")
}
}
}
}
// manejar la limpieza
override fun onPause() {
super.onPause()
if(mDelayedJob != null && mDelayedJob!!.isActive) {
A35Log.v(mClassTag, "canceling delayed job")
mDelayedJob?.cancel() //this should throw CancelationException in coroutine, you can catch and handle appropriately
}
}
Si coloca el inicio (UI) en la firma del método, el trabajo se puede asignar en la línea de código que llama.
por lo tanto, la moraleja de la historia es estar a salvo con sus acciones demoradas, asegurarse de eliminar sus devoluciones de llamada o cancelar sus trabajos y, por supuesto, confirmar que tiene el ciclo de vida correcto para tocar los elementos de su devolución de llamada demorada. Los coroutines también ofrecen acciones cancelables.
También vale la pena señalar que normalmente debe manejar las diversas excepciones que pueden venir con las coroutinas. Por ejemplo, una cancelación, una excepción, un tiempo de espera, lo que decida usar. Este es un ejemplo más avanzado si decide comenzar realmente a utilizar coroutines.
mLoadJob = launch(UI){
try {
//Applies timeout
withTimeout(4000) {
//Moves to background thread
withContext(DefaultDispatcher) {
mDeviceModelList.addArrayList(SSDBHelper.getAllDevices())
}
}
//Continues after async with context above
showFancyToast("Loading complete", true, FancyToast.SUCCESS)
}catch(ex: JobCancellationException){
showFancyToast("Save canceled", true, FancyToast.ERROR, "Save canceled: ${ex.message}")
}catch (ex: TimeoutCancellationException) {
showFancyToast("Timed out saving, please try again or press back", true, FancyToast.ERROR, "Timed out saving to database: ${ex.message}")
}catch(ex: Exception){
showFancyToast("Error saving to database, please try again or press back", true, FancyToast.ERROR, "Error saving to database: ${ex.message}")
}
}
Es muy fácil usar el CountDownTimer
. Para obtener más detalles, https://developer.android.com/reference/android/os/CountDownTimer.html
import android.os.CountDownTimer;
// calls onTick every second, finishes after 3 seconds
new CountDownTimer(3000, 1000) {
public void onTick(long millisUntilFinished) {
Log.d("log", millisUntilFinished / 1000);
}
public void onFinish() {
// called after count down is finished
}
}.start();
Esta es otra manera complicada: no lanzará una excepción cuando los elementos de la IU de cambio ejecutables.
public class SimpleDelayAnimation extends Animation implements Animation.AnimationListener {
Runnable callBack;
public SimpleDelayAnimation(Runnable runnable, int delayTimeMilli) {
setDuration(delayTimeMilli);
callBack = runnable;
setAnimationListener(this);
}
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
callBack.run();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
}
Puedes llamar a la animación así:
view.startAnimation(new SimpleDelayAnimation(delayRunnable, 500));
La animación se puede adjuntar a cualquier vista.
Gracias por todas las excelentes respuestas, encontré la solución que mejor se adapta a mis necesidades.
Handler myHandler = new DoSomething();
Message m = new Message();
m.obj = c;//passing a parameter here
myHandler.sendMessageDelayed(m, 1000);
class DoSomething extends Handler {
@Override
public void handleMessage(Message msg) {
MyObject o = (MyObject) msg.obj;
//do something here
}
}
He creado un método más simple para llamar a esto.
public static void CallWithDelay(long miliseconds, final Activity activity, final String methodName)
{
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
try {
Method method = activity.getClass().getMethod(methodName);
method.invoke(activity);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}, miliseconds);
}
Para usarlo, solo llame: .CallWithDelay(5000, this, "DoSomething");
Me gustan las cosas más limpias: aquí está mi implementación, código en línea para usar dentro de su método
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
}
}, 100);
Mejor versión:
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
}
}, 100);
No pude usar ninguna de las otras respuestas en mi caso. Utilicé el Timer java nativo en su lugar.
new Timer().schedule(new TimerTask() {
@Override
public void run() {
// this code will be executed after 2 seconds
}
}, 2000);
Para ejecutar algo en el hilo de la interfaz de usuario después de 5 segundos:
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
//Do something here
}
}, 5000);
Prefiero usar el método View.postDelayed()
, código simple a continuación:
mView.postDelayed(new Runnable() {
@Override
public void run() {
// Do something after 1000 ms
}
}, 1000);
Puedes hacerlo mucho más limpio usando las expresiones lambda recién introducidas:
new Handler().postDelayed(() -> {/*your code here*/}, time);
Puedes usar Handler dentro de UIThread:
runOnUiThread(new Runnable() {
@Override
public void run() {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
//add your code here
}
}, 1000);
}
});
Puedes usar esto para la solución más simple:
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//Write your code here
}
}, 5000); //Timer is in ms here.
Si no, a continuación puede ser otra solución útil limpia:
new Handler().postDelayed(() ->
{/*Do something here*/},
5000); //time in ms
Si está utilizando Android Studio 3.0 o superior, puede usar expresiones lambda. El método callMyMethod()
se llama después de 2 segundos:
new Handler().postDelayed(() -> callMyMethod(), 2000);
En caso de que necesite cancelar la ejecución retrasada, use esto:
Handler handler = new Handler();
handler.postDelayed(() -> callMyMethod(), 2000);
// When you need to cancel all your posted runnables just use:
handler.removeCallbacksAndMessages(null);
Si tiene que usar el controlador, pero está en otro hilo, puede usar runonuithread
para ejecutar el controlador en el hilo de la interfaz de usuario. Esto lo salvará de las excepciones lanzadas al solicitar que llame a Looper.Prepare()
runOnUiThread(new Runnable() {
@Override
public void run() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 1 second
}
}, 1000);
}
});
Parece bastante desordenado, pero este es uno de los caminos.
Sugiero el Timer , le permite programar un método para ser llamado en un intervalo muy específico. Esto no bloqueará su interfaz de usuario y mantendrá su aplicación de manera segura mientras se ejecuta el método.
La otra opción, es la wait(); método, esto bloqueará el hilo actual por el tiempo especificado. Esto hará que su interfaz de usuario deje de responder si lo hace en el subproceso de la interfaz de usuario.
Una solución adecuada en Android:
private static long SLEEP_TIME = 2 // for 2 second
.
.
MyLauncher launcher = new MyLauncher();
launcher.start();
.
.
private class MyLauncher extends Thread {
@Override
/**
* Sleep for 2 seconds as you can also change SLEEP_TIME 2 to any.
*/
public void run() {
try {
// Sleeping
Thread.sleep(SLEEP_TIME * 1000);
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
//do something you want to do
//And your code will be executed after 2 second
}
}
Vea esta demostración:
import java.util.Timer;
import java.util.TimerTask;
class Test {
public static void main( String [] args ) {
int delay = 5000;// in ms
Timer timer = new Timer();
timer.schedule( new TimerTask(){
public void run() {
System.out.println("Wait, what..:");
}
}, delay);
System.out.println("Would it run?");
}
}
todo el mundo parece olvidarse de limpiar el Controlador antes de publicar un nuevo archivo o mensaje en él. De otra manera podrían acumularse y causar mal comportamiento.
handler.removeMessages(int what);
// Remove any pending posts of messages with code ''what'' that are in the message queue.
handler.removeCallbacks(Runnable r)
// Remove any pending posts of Runnable r that are in the message queue.
Nota: esta respuesta se dio cuando la pregunta no especificaba Android como contexto. Para una respuesta específica al hilo de la interfaz de usuario de Android, mira aquí.
Parece que la API de Mac OS permite que el hilo actual continúe, y programa la tarea para que se ejecute de forma asíncrona. En Java, la función equivalente la proporciona el paquete java.util.concurrent
. No estoy seguro de qué limitaciones podría imponer Android.
private static final ScheduledExecutorService worker =
Executors.newSingleThreadScheduledExecutor();
void someMethod() {
⋮
Runnable task = new Runnable() {
public void run() {
/* Do something… */
}
};
worker.schedule(task, 5, TimeUnit.SECONDS);
⋮
}
Aquí está la respuesta en Kotlin, perezosos, perezosos:
Handler().postDelayed({
//doSomethingHere()
}, 1000)
final Handler handler = new Handler();
Timer t = new Timer();
t.schedule(new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
//DO SOME ACTIONS HERE , THIS ACTIONS WILL WILL EXECUTE AFTER 5 SECONDS...
}
});
}
}, 5000);