【发布时间】:2016-01-06 10:21:49
【问题描述】:
我正在开发的应用程序正在显示当地电车的时间表。数据是从网站获取的,应该每 30 秒刷新一次。为了在后台执行 fetch,我以更适合 scala 的方式重新实现了 AsyncTask。
摘自class RichFuture[T](future: Future[U]),它通过隐式转换丰富了Future:
def mapUI[U](func: (T) ⇒ U)(implicit activity: Activity, ec: ExecutionContext): Future[U] = {
val promise = Promise[U]
future andThen {
case Success(value) ⇒
activity.runOnUiThread(new Runnable {
override def run(): Unit = {
try {
promise.success(func(value))
} catch {
case t: Throwable ⇒ promise.failure(t)
}
}
})
case Failure(fail) ⇒
promise.failure(fail)
}
promise.future
}
这基本上取代了 AsyncTask which does not work in scala。完整的课程可以在github 看到。不过我认为这无关紧要。
fetch 函数函数如下所示:
def fetchSchedule(): Unit = {
implicit val ec: ExecutionContext = ExecutionContext.fromExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
Schedule.fetch(station) mapUI { schedules ⇒
Log.w("Jenastop", "Schedules are fetched")
/* Display results in UI */
} recoverUI {
case t: Throwable ⇒
/* Display error in UI */
}
}
调用fetchSchedule的地方是这样的:
protected override def onResume(): Unit = {
super.onResume()
Log.w("Jenastop", "Resume started")
// Setup timer that refreshes the data every 30
// seconds.
timer = new Timer
timer.scheduleAtFixedRate(new TimerTask {
override def run(): Unit = fetchSchedule()
}, 0, 30000)
Log.w("Jenastop", "Resume finished")
}
现在的问题是:每当我将 Activity 置于后台并尝试恢复它时,它都会冻结,直到获取时间表为止。当我第一次启动活动时不会发生这种情况,但只有当我尝试从后台恢复它时才会发生。
从后台恢复时的日志输出是这样的:
01-06 11:19:06.694 5280 5280 W Jenastop: Resume started
01-06 11:19:06.694 5280 5280 W Jenastop: Resume finished
01-06 11:19:07.974 5280 5280 I Choreographer: Skipped 71 frames! The application may be doing too much work on its main thread.
01-06 11:19:07.974 5280 5280 W Jenastop: Schedules are fetched
/* UI unfreezes */
在 THREAD_POOL_EXECUTOR 中的任务完成之前,UI 似乎一直处于阻塞状态。我该如何规避呢?
【问题讨论】:
-
一个小细节。而不是
try { promise.successful(...) } catch ... },你应该简单地运行promise.complete(Try(func(value)))。 -
不是 Android 专家。所以
Schedule.fetch拥有未来,对吧?您是否有理由必须使用AsyncTask.THREAD_POOL_EXECUTOR?根据我的经验,您可以使用自定义池轻松阻止期货。如果您使用默认的执行上下文,您可以在未来的正文中使用blocking { }来避免此类情况。 -
因为您使用 inside
Schedule.fetch的 Jsoup 可能会阻塞。使用异步 http 库可能会更好。同样,我对此一无所知,但也许this blog 有助于这样做。 -
在 android 上避免使用 scala 池的主要原因是与某些设备的兼容性。它并不总是有效。 blog.scaloid.org/2013/11/…
-
Jsoup 预计会被阻止。出于这个原因,我在线程池中而不是在 UI 线程中运行它。 UI 线程也被阻塞了,我不知道为什么。
标签: android scala android-asynctask