2017-09-13 185 views
0

在我們的項目中,我們需要在操作之前獲取一些數據(將被存儲)。如果數據是在15分鐘前獲得的,我們必須刷新它。Kotlin&Anko協同程序:返回異步

我們使用Kotlin + Anko協同程序來完成此操作。這個想法(假設數據是在某個時間點之前獲得的)是:

該方法被調用並檢查我們獲取數據的時間。 如果不到15分鐘前,請將其退回。 如果不是,請異步獲取(這是一個網絡操作),存儲並返回它。

由於在刷新數據之前我們不能做任何事情,刷新必須是同步的(通過網絡操作本身是異步的)。

我們已經驗證碼:

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 
    } 
} 

我們怎樣才能使異步(UI)外的函數等待結果阻止?這種回報是必要的,但我們不知道我們應該放在那裏。我們嘗試了Deferred對象的getCompleted()方法(返回asyncUser.getCompleted()),但它最終會因爲返回null而崩潰。

謝謝!

回答

0

我看到了幾種方法來做到這一點。一種是使用kotlinx.coroutines.experimental方法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() 
} 

根據使用的情況下,你甚至可以簡化這個到:

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

另一種方法是使用一個基本的Java 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

我試過簡化版本和CountDownLatch,兩者都很好。謝謝! –

+0

我讀到runBlocking僅用於測試目的,不適用於最終產品。 –