Quindi ci sono alcune cose da considerare qui in quanto ci sono tanti modi per scuoiare questo gatto. Sebbene le risposte siano già state tutte selezionate, selezionate e scelte. Penso che sia importante che questo venga rivisitato con linee guida di codifica adeguate per evitare che qualcuno vada nella direzione sbagliata solo a causa della "risposta semplice selezionata dalla maggioranza".
Quindi prima discutiamo la semplice risposta post ritardata che è la risposta selezionata dal vincitore in generale in questa discussione.
Un paio di cose da considerare. Dopo il ritardo post, è possibile riscontrare perdite di memoria, oggetti morti, cicli di vita che sono andati via e altro ancora. Quindi anche gestirlo correttamente è importante. Puoi farlo in un paio di modi.
Per motivi di sviluppo moderno, fornirò a KOTLIN
Ecco un semplice esempio dell'uso del thread dell'interfaccia utente su un callback e della conferma che l'attività è ancora attiva e funzionante quando si raggiunge il callback.
Handler(Looper.getMainLooper()).postDelayed({
if(activity != null && activity?.isFinishing == false){
txtNewInfo.visibility = View.GONE
}
}, NEW_INFO_SHOW_TIMEOUT_MS)
Tuttavia, questo non è ancora perfetto in quanto non vi è alcun motivo per rispondere al callback se l'attività è andata via. quindi un modo migliore sarebbe quello di mantenere un riferimento ad esso e rimuovere i suoi callback come questo.
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)
}
}
e ovviamente gestire la pulizia su onPause in modo che non colpisca la richiamata.
override fun onPause() {
super.onPause()
mHandler.removeCallbacks(null)
}
Ora che abbiamo discusso dell'ovvio, parliamo di un'opzione più pulita con le moderne coroutine e kotlin :). Se non li usi ancora, ti stai davvero perdendo.
fun doActionAfterDelay()
launch(UI) {
delay(MS_TO_DELAY)
actionToTake()
}
}
o se vuoi fare sempre un lancio dell'interfaccia utente con quel metodo puoi semplicemente fare:
fun doActionAfterDelay() = launch(UI){
delay(MS_TO_DELAY)
actionToTake()
}
Ovviamente proprio come PostDelayed devi assicurarti di gestire l'annullamento in modo da poter fare i controlli delle attività dopo la chiamata di ritardo o puoi annullarlo in onPause proprio come l'altro percorso.
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}")
}
}
}
}
// gestisce la pulizia
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
}
}
Se si inserisce l'avvio (UI) nella firma del metodo, il lavoro può essere assegnato nella riga del codice chiamante.
così la morale della storia è quella di essere al sicuro con le tue azioni ritardate, assicurati di rimuovere i tuoi callback, o di annullare i tuoi lavori e, naturalmente, conferma di avere il giusto ciclo di vita per toccare gli elementi sul tuo callback ritardato completo. Le Coroutine offre anche azioni annullabili.
Vale anche la pena notare che in genere è necessario gestire le varie eccezioni che possono derivare dalle coroutine. Ad esempio, una cancellazione, un'eccezione, un timeout, qualunque cosa tu decida di utilizzare. Ecco un esempio più avanzato se decidi di iniziare davvero a utilizzare le coroutine.
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}")
}
}