Отож, тут слід врахувати кілька речей, оскільки існує стільки способів зняти шкіру з цією кішкою. Хоча відповіді всі вже надані вибрані та обрані. Я думаю, що важливо, щоб це було переглянуто за допомогою правильних правил кодування, щоб уникнути того, щоб хтось пішов у неправильному напрямку саме через "обрану більшістю просту відповідь".
Тож спочатку давайте обговоримо просту відповідь із затримкою після публікації, яка є загальною відповіддю на цю тему.
Пару речей. Після затримки повідомлення можна зіткнутися з витоком пам’яті, мертвими предметами, життєвими циклами, що відійшли, та ін. Тому важливим є також поводження з ним належним чином. Це можна зробити двома способами.
Заради сучасного розвитку я поставляюсь у 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}")
}
}