Answers:
Handler().postDelayed({
//Do something after 100ms
}, 100)
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
}
}, 100);
removeCallbacks(Runnable r)
中即可Handler
。
import android.os.handler
在我的情况下,我无法使用其他任何答案。我改用了本地Java Timer。
new Timer().schedule(new TimerTask() {
@Override
public void run() {
// this code will be executed after 2 seconds
}
}, 2000);
注意:当问题未将Android指定为上下文时,将给出此答案。对于特定于Android UI线程的答案,请点击此处。
看起来Mac OS API允许当前线程继续运行,并安排任务以异步方式运行。在Java中,java.util.concurrent
程序包提供了等效功能。我不确定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);
⋮
}
ScheduledFuture<?>
return by 的引用worker.schedule()
并调用其cancel(boolean)
方法。
ScheduledExecutorService
。
感谢所有出色的答案,我找到了最适合我需要的解决方案。
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
}
}
Kotlin
和Java
许多方式
Handler
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
Executors.newSingleThreadScheduledExecutor().schedule({
TODO("Do something")
}, 2, TimeUnit.SECONDS)
在Java中
Handler
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//Do something
}
}, 2000);
Timer
new Timer().schedule(new TimerTask() {
@Override
public void run() {
// Do something
}
}, 2000);
ScheduledExecutorService
private static final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
Runnable runnable = new Runnable() {
public void run() {
// Do something
}
};
worker.schedule(runnable, 2, TimeUnit.SECONDS);
How to call a method after a delay in Android
。因此,我对此表示关注。要点。否则,java泄漏是开发人员需要单独理解的一个重要主题。
观看此演示:
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?");
}
}
如果必须使用处理程序,但是又进入另一个线程,则可以使用runonuithread
它在UI线程中运行。这将使您免于引发的异常要求致电Looper.Prepare()
runOnUiThread(new Runnable() {
@Override
public void run() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 1 second
}
}, 1000);
}
});
看起来很凌乱,但这是其中的一种。
我更喜欢使用View.postDelayed()
方法,下面是简单的代码:
mView.postDelayed(new Runnable() {
@Override
public void run() {
// Do something after 1000 ms
}
}, 1000);
如果您使用的是Android Studio 3.0及更高版本,则可以使用lambda表达式。callMyMethod()
2秒后调用该方法:
new Handler().postDelayed(() -> callMyMethod(), 2000);
如果您需要取消延迟的可运行对象,请使用以下方法:
Handler handler = new Handler();
handler.postDelayed(() -> callMyMethod(), 2000);
// When you need to cancel all your posted runnables just use:
handler.removeCallbacksAndMessages(null);
我建议使用Timer,它允许您安排要在特定时间间隔内调用的方法。这不会阻止您的UI,并在执行该方法时使您的应用保持共振。
另一个选择是wait();。方法,这将在指定的时间长度内阻止当前线程。如果在UI线程上执行此操作,将导致UI停止响应。
您可以将其用于最简单的解决方案:
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
您可以使用新引入的lambda表达式使它更加简洁:
new Handler().postDelayed(() -> {/*your code here*/}, time);
所以这里有几件事情要考虑,因为有很多方法可以给这只猫换皮。尽管答案已经全部选定。我认为重要的是要使用适当的编码指南重新进行研究,以避免任何人仅由于“多数选择的简单答案”而走错了方向。
因此,首先让我们讨论简单的“延迟发布”答案,这是该主题中获胜者整体选择的答案。
需要考虑的几件事。发布延迟之后,您可能会遇到内存泄漏,死对象,已经消失的生命周期等。因此,正确处理它也很重要。您可以通过两种方法来完成此操作。
为了现代发展,我将在KOTLIN中提供
这是在回调上使用UI线程并确认您的活动在命中回调时仍然有效的简单示例。
Handler(Looper.getMainLooper()).postDelayed({
if(activity != null && activity?.isFinishing == false){
txtNewInfo.visibility = View.GONE
}
}, NEW_INFO_SHOW_TIMEOUT_MS)
但是,这仍然不是很完美,因为如果活动消失,则没有理由打回您的回调。因此更好的方法是保留对它的引用,并删除这样的回调。
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上进行清理,以免打回回调。
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
}
}
如果将launch(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}")
}
}
我创建了更简单的方法来调用此方法。
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, this, "DoSomething");
performSelector
。这是最好的方法。
当您获得以下作品时,
java.lang.RuntimeException:无法在尚未调用Looper.prepare()的线程内创建处理程序
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
}
}, 100);
使用Kotlin,我们可以通过执行以下操作来实现
Handler().postDelayed({
// do something after 1000ms
}, 1000)
使用非常容易CountDownTimer
。有关更多详细信息,请参见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();
每个人似乎都忘了在发布新的可运行对象或消息之前先清理处理程序。否则,它们可能会积累并导致不良行为。
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.
这是另一种棘手的方法:当可运行的更改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));
动画可以附加到任何视图。
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
}
}
类似的解决方案,但使用起来更清洁
将此功能写在类之外
fun delay(duration: Long, `do`: () -> Unit) {
Handler().postDelayed(`do`, duration)
}
用法:
delay(5000) {
//Do your work here
}
do
是一种内置方法,因此我们必须使用`来将其用作变量名
do
这样3秒的延迟后
在Android中,我们可以编写以下kotlin代码来延迟执行任何功能
class MainActivity : AppCompatActivity() {
private lateinit var handler: Handler
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
handler= Handler()
handler.postDelayed({
doSomething()
},2000)
}
private fun doSomething() {
Toast.makeText(this,"Hi! I am Toast Message",Toast.LENGTH_SHORT).show()
}
}