2017-09-13 4 views
0

In unserem Projekt müssen wir einige Daten erhalten (die gespeichert werden), bevor Sie Operationen ausführen. Falls die Daten vor mehr als 15 Minuten abgerufen wurden, müssen wir sie aktualisieren.Kotlin & Anko Koroutinen: Rückkehr außerhalb Async

Wir verwenden Kotlin + Anko Coroutinen, um das zu tun. Die Idee (unter der Annahme, dass die Daten zu einem früheren Zeitpunkt erhalten wurden) lautet:

Die Methode wird aufgerufen und überprüft, wann wir die Daten bekommen haben. Wenn es vor weniger als 15 Minuten war, wird es zurückgegeben. Falls nicht, besorge es asynchron (es ist eine Netzwerkoperation), speichere es und gib es zurück.

Da wir nichts tun können, bevor die aktualisierten Daten abgerufen werden, muss die Aktualisierung synchron sein (auch wenn die Netzwerkoperation selbst asynchron ist).

Wir haben diesen Code:

fun Context.retrieveInfo(api: Api?): User? { 

    try { 

    // For sake of simplification the real conditional check is removed 
    if (time > 15) { 

     val context = this 
     val asyncUser = async(UI) { 
      val obtainData: Deferred<Data?> = bg { 
       api?.obtainData(sphelper.getDefaultUser(context)) 
      } 

      val obtainedData = storeAndRetrieve(obtainData.await(), context) 
      [email protected] obtainedData 
     } 

// ??????? 

    } else { 
     val input = ObjectInputStream(this.openFileInput("data.dat")) 
     return input.readObject() as Data 
    } 
    } catch (e: Exception) { 
    return null 
    } 
} 

Wie können wir die Funktion Warten auf das Ergebnis außerhalb der Asynchron (UI) machen blockieren? Diese Rückkehr ist notwendig, aber wir haben keine Ahnung, was wir dort hinstellen sollten. Wir haben es mit der Methode getCompleted() des Deferred-Objekts versucht (return asyncUser.getCompleted()), aber es stürzt am Ende ab, weil es null zurückgibt.

Vielen Dank!

Antwort

0

Ich sehe ein paar Möglichkeiten, dies zu tun. Eine davon ist die kotlinx.coroutines.experimental Methode verwenden runBlocking:

val user = runBlocking(CommonPool) { 
    val asyncUser = async(UI) { 
     val obtainData: Deferred<String> = bg { 
      ... 
     } 

     val obtainedData = storeAndRetrieve(obtainData.await(), context) 
     [email protected] obtainedData 
    } 
    [email protected] asyncUser.await() 
} 

auf Anwendungsfall abhängig, können Sie sogar in der Lage sein, zu vereinfachen, dies zu:

val asyncUser = runBlocking { 
    async(CommonPool) { 
     val obtainedData = storeAndRetrieve(api?.obtainData(sphelper.getDefaultUser(context)), context) 
     [email protected] obtainedData 
    }.await() 
} 

Ein anderer Weg ist es, eine grundlegende Java verwenden CountDownLatch:

var asyncUser: String? = null 
val c = CountDownLatch(1) 
async(UI) { 
    val obtainData: Deferred<String> = bg { 
     ... 
    } 

    val obtainedData = obtainData.await() 
    asyncUser = obtainedData 
    c.countDown() 
} 
c.await() 
+0

Ich habe die vereinfachte Version und die CountDownLatch ausprobiert und beide funktionieren gut. Vielen Dank! –

+0

Ich habe gelesen, dass runBlocking ist für Testzwecke, nicht ideal für Endprodukte. –

Verwandte Themen