Java 在Android中如何在延迟后调用方法
我希望能够在指定的延迟后调用以下方法。 在目标c中,有如下内容:Java 在Android中如何在延迟后调用方法,java,android,handler,delay,Java,Android,Handler,Delay,我希望能够在指定的延迟后调用以下方法。 在目标c中,有如下内容: [self performSelector:@selector(DoSomething) withObject:nil afterDelay:5]; 在android和java中是否有类似的方法? 例如,我需要能够在5秒后调用一个方法 public void DoSomething() { //do something here } 我建议,它允许您计划在非常特定的时间间隔调用一个方法。这不会阻塞您的UI,并在执行方
[self performSelector:@selector(DoSomething) withObject:nil afterDelay:5];
在android和java中是否有类似的方法?
例如,我需要能够在5秒后调用一个方法
public void DoSomething()
{
//do something here
}
我建议,它允许您计划在非常特定的时间间隔调用一个方法。这不会阻塞您的UI,并在执行方法时保持应用程序的响应
另一个选项是方法,这将在指定的时间长度内阻止当前线程。如果在UI线程上执行此操作,将导致UI停止响应。请参阅此演示:
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?");
}
}
注意:这个答案是在问题没有指定Android作为上下文时给出的。对于特定于Android UI线程的答案
看起来Mac OS API允许当前线程继续,并将任务安排为异步运行。在Java中,等价的函数由
Java.util.concurrent
包提供。我不确定安卓可能会施加哪些限制
private static final ScheduledExecutorService worker =
Executors.newSingleThreadScheduledExecutor();
void someMethod() {
⋮
Runnable task = new Runnable() {
public void run() {
/* Do something… */
}
};
worker.schedule(task, 5, TimeUnit.SECONDS);
⋮
}
感谢所有的好答案,我找到了一个最适合我需要的解决方案
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
}
}
科特林
处理程序(Looper.getMainLooper()).postDelayed({
//100毫秒后做点什么
}, 100)
JAVA
final Handler=new Handler(Looper.getMainLooper());
handler.postDelayed(新的Runnable(){
@凌驾
公开募捐{
//100毫秒后做点什么
}
}, 100);
在我的案例中,我无法使用任何其他答案。 我使用了本机java计时器
new Timer().schedule(new TimerTask() {
@Override
public void run() {
// this code will be executed after 2 seconds
}
}, 2000);
可以在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);
}
});
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
}
}
对于在5秒后在UI线程中执行某些操作:
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
//Do something here
}
}, 5000);
如果必须使用该处理程序,但您进入了另一个线程,则可以使用
runonuithread
在UI线程中运行该处理程序。这将使您免于请求调用Looper.Prepare()
看起来很凌乱,但这是其中一种方式。我更喜欢使用
View.postDelayed()
方法,简单代码如下:
mView.postDelayed(new Runnable() {
@Override
public void run() {
// Do something after 1000 ms
}
}, 1000);
我创建了一个更简单的方法来调用它
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);
}
要使用它,只需调用:
.CallWithDelay(5000,这是“DoSomething”)代码>这里是另一个棘手的方法:当可运行的更改UI元素时,它不会引发异常
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) {
}
}
可以这样调用动画:
view.startAnimation(new SimpleDelayAnimation(delayRunnable, 500));
动画可以附加到任何视图。以下是我的最短解决方案:
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
}
}, 100);
通过使用新引入的lambda表达式,可以使其更加清晰:
new Handler().postDelayed(() -> {/*your code here*/}, time);
使用倒计时功能非常简单。
欲知详情
如果您使用的是Android Studio 3.0及以上版本,则可以使用lambda表达式。方法callMyMethod()
在2秒后调用:
new Handler().postDelayed(() -> callMyMethod(), 2000);
如果需要取消延迟的runnable,请使用以下命令:
Handler handler = new Handler();
handler.postDelayed(() -> callMyMethod(), 2000);
// When you need to cancel all your posted runnables just use:
handler.removeCallbacksAndMessages(null);
每个人似乎都忘记在发布新的runnable或消息之前清理处理程序。否则,它们可能累积并导致不良行为
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.
您可以将其用于最简单的解决方案:
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//Write your code here
}
}, 5000); //Timer is in ms here.
否则,下面可能是另一个干净有用的解决方案:
new Handler().postDelayed(() ->
{/*Do something here*/},
5000); //time in ms
在科特林,你们这些懒惰的人:
Handler().postDelayed({
//doSomethingHere()
}, 1000)
所以这里有一些事情要考虑,因为有很多方法来保护这只猫。虽然答案都已经被选择了。我认为这一点很重要,要用正确的编码准则来重新审视,以避免任何人仅仅因为“多数选择简单答案”而走错方向
因此,首先让我们讨论一下简单的延迟后答案,它是本线程中的获胜者选择的答案
有两件事要考虑。延迟后,您可能会遇到内存泄漏、死对象、已消失的生命周期等等。因此,正确处理它也很重要。你可以通过两种方式来做到这一点
为了现代发展,我将在科特林供应
下面是一个在回调上使用UI线程的简单示例,当您点击回调时,确认您的活动仍然处于活动状态
Handler(Looper.getMainLooper()).postDelayed({
if(activity != null && activity?.isFinishing == false){
txtNewInfo.visibility = View.GONE
}
}, NEW_INFO_SHOW_TIMEOUT_MS)
override fun onPause() {
super.onPause()
mHandler.removeCallbacks(null)
}
但是,这仍然不是完美的,因为如果活动已消失,则没有理由点击回调。因此,更好的方法是保留对它的引用,并像这样删除它的回调
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)
}
}
当然,还要处理onPause上的清理,这样它就不会命中回调
Handler(Looper.getMainLooper()).postDelayed({
if(activity != null && activity?.isFinishing == false){
txtNewInfo.visibility = View.GONE
}
}, NEW_INFO_SHOW_TIMEOUT_MS)
override fun onPause() {
super.onPause()
mHandler.removeCallbacks(null)
}
现在我们已经讨论了显而易见的问题,让我们来讨论一个更干净的选项,包括现代的协同程序和kotlin:)。如果你还没有使用这些工具,你就真的错过了
fun doActionAfterDelay()
launch(UI) {
delay(MS_TO_DELAY)
actionToTake()
}
}
或者,如果您希望始终在该方法上执行UI启动,您只需执行以下操作:
fun doActionAfterDelay() = launch(UI){
delay(MS_TO_DELAY)
actionToTake()
}
当然,就像PostDelayed一样,您必须确保处理取消,以便您可以在延迟调用后执行活动检查,或者您可以像其他路由一样在onPause中取消它
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}")
}
}
}
}
//处理清理
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
}
}
如果将启动(UI)放入方法签名中,则可以在调用代码行中分配作业
因此,这个故事的寓意是对延迟的行为保持安全,确保删除回调,或者取消工作,当然,还要确认您有正确的生命周期来完成延迟回调上的项目。协同程序还提供可取消的操作
还值得注意的是,您通常应该处理协同程序可能出现的各种异常。例如,取消、异常、超时,无论您决定使用什么。如果您决定真正开始使用协同程序,这里有一个更高级的示例
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}")
}
}
我喜欢干净的东西:
这是我的实现,在方法中使用的内联代码
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
}
}, 100);
下面的一个工作时,你得到
java.lang.RuntimeException:无法在该线程内创建处理程序
尚未调用Looper.prepare()
Kotlin
&Java
多种方式
1.使用处理程序
2.使用TimerTask
甚至更短
Timer().schedule(timerTask {
TODO("Do something")
}, 2000)
或者是最短的
Timer().schedule(2000) {
TODO("Do something")
}
3.使用执行器Handler().postDelayed({
TODO("Do something")
}, 2000)
Timer().schedule(object : TimerTask() {
override fun run() {
TODO("Do something")
}
}, 2000)
Timer().schedule(timerTask {
TODO("Do something")
}, 2000)
Timer().schedule(2000) {
TODO("Do something")
}
Executors.newSingleThreadScheduledExecutor().schedule({
TODO("Do something")
}, 2, TimeUnit.SECONDS)
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//Do something
}
}, 2000);
new Timer().schedule(new TimerTask() {
@Override
public void run() {
// Do something
}
}, 2000);
private static final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
Runnable runnable = new Runnable() {
public void run() {
// Do something
}
};
worker.schedule(runnable, 2, TimeUnit.SECONDS);
Observable.timer(delay, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(aLong -> {
// Execute code here
}, Throwable::printStackTrace);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// Do someting
}
}, 3000);
fun delay(duration: Long, `do`: () -> Unit) {
Handler().postDelayed(`do`, duration)
}
delay(5000) {
//Do your work here
}
Handler().postDelayed({
// do something after 1000ms
}, 1000)
lifecycleScope.launch {
delay(DELAY_MS)
doSomething()
}
viewModelScope.lanch {
delay(DELAY_MS)
doSomething()
}
suspend fun doSomethingAfter(){
delay(DELAY_MS)
doSomething()
}
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"