我希望能够在指定的延迟后调用以下方法。 在objective c中,有这样的东西:
[self performSelector:@selector(DoSomething) withObject:nil afterDelay:5];
在android和java中是否有类似的方法? 例如,我需要能够在5秒后调用一个方法。
public void DoSomething()
{
//do something here
}
我希望能够在指定的延迟后调用以下方法。 在objective c中,有这样的东西:
[self performSelector:@selector(DoSomething) withObject:nil afterDelay:5];
在android和java中是否有类似的方法? 例如,我需要能够在5秒后调用一个方法。
public void DoSomething()
{
//do something here
}
当前回答
科特林
Handler(Looper.getMainLooper()).postDelayed({
//Do something after 100ms
}, 100)
Java
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
}
}, 100);
要导入的类是android.os.handler。
其他回答
所以这里有几件事要考虑,因为有这么多方法来剥这只猫的皮。尽管答案都已经给出了。我认为重要的是,要用适当的编码指南重新审视这个问题,以避免任何人仅仅因为“多数选择的简单答案”而走向错误的方向。
因此,首先让我们讨论一下简单的Post Delayed answer,这是在这个线程中胜出的答案。
有几件事需要考虑。在post延迟之后,您可能会遇到内存泄漏、死对象、生命周期消失等等。所以正确处理也很重要。有几种方法可以做到这一点。
为了现代发展,我将在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
}
}
如果您将启动(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}")
}
}
注意:这个答案是在问题没有指定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);
⋮
}
你可以使用新引入的lambda表达式让它更简洁:
new Handler().postDelayed(() -> {/*your code here*/}, time);
好吧,如果你使用Java,你总是可以使用遗留的Thread.sleep()。
new Thread(() -> {
try {
Thread.sleep(millis); //delay in milliseconds
} catch (Exception e) {
e.printStackTrace();
}
yourMethod();
}).start();
这里唯一的问题是你不能做任何UI更新,因为它是一个单独的线程。
谢谢你的回答,我找到了一个最适合我需要的解决方案。
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
}
}