Так что здесь есть несколько вещей, которые нужно учитывать, так как есть много способов снять кожу с этой кошкиХотя ответы уже все были выбраны и выбраны.Я думаю, что важно вернуться к этому с надлежащими руководящими принципами кодирования, чтобы никто не пошел в неправильном направлении только из-за «простого выбранного большинства ответа».
Итак, сначала давайте обсудим простой ответ с задержкой после ответа, который является выбранным победителем ответомв целом в этой теме.
Несколько вещей, чтобы рассмотреть.После задержки вы можете столкнуться с утечками памяти, мертвыми объектами, ушедшими жизненными циклами и многим другим.Поэтому правильное обращение с ним также важно.Вы можете сделать это несколькими способами.
Ради современной разработки я приведу в KOTLIN
Вот простой пример использования потока пользовательского интерфейса при обратном вызове и подтверждения того, чтоВаша активность все еще жива и здорова, когда вы нажмете свой обратный вызов.
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)
}
Теперь, когда мы обсудили очевидное, давайте поговорим о более чистом варианте с современными сопрограммами и котлином :).Если вы еще не используете их, вы действительно упускаете.
fun doActionAfterDelay()
launch(UI) {
delay(MS_TO_DELAY)
actionToTake()
}
}
или если вы хотите всегда запускать пользовательский интерфейс для этого метода, вы можете просто сделать:
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) в сигнатуру метода, задание может быть назначено в вызывающей строке кода.
, поэтому мораль истории заключается в том, чтобыбудьте осторожны с вашими отложенными действиями, убедитесь, что вы удалили свои обратные вызовы или отменили свою работу, и, конечно, подтвердите, что у вас есть правильный жизненный цикл, чтобы прикоснуться к элементам вашего обратного обратного вызова.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}")
}
}