我如何才能 运行 一个可以访问我的数据库并可以对其进行 运行 操作但不会阻塞 UI 线程的服务
How can I run a service the would have access to my database and could run operations on it, but won't stuff up the UI thread
我正在构建一个应用程序,它需要浏览本地存储的一组照片,我将这些照片导入房间数据库,并尝试检测每张照片是否包含人脸。
我已经把所有东西都整理好了,我唯一的问题是如何 运行 这个操作,这可能需要一段时间,在一个不会塞满 UI 线程的服务中。
起初我想使用 JobIntentService
但不能,因为我无法在后台线程上 observeForever,并且不能使用简单的观察者,因为我没有 lifecycleOwner 给 Observer
.
我最终只使用了一项服务,一旦操作开始,我的 UI 就几乎卡住了,如果我尝试做任何事情,应用程序就会崩溃。
我可能试过 IntentService
但我不能在 onHandleIntent
中使用观察者,因为它是一个工作线程,它不允许我,当我 运行 操作在 onStartCommand
下就一样了。
我觉得我被这个东西的架构所困,我会很感激任何想法。谢谢。
这是我的服务:
class DetectJobIntentService : Service() {
private val TAG = "DetectJobIntentServi22"
lateinit var repo: PhotoRepository
lateinit var observer : Observer<MutableList<Photo>>
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val options = FirebaseVisionFaceDetectorOptions.Builder()
.setClassificationMode(FirebaseVisionFaceDetectorOptions.ACCURATE)
.setClassificationMode(FirebaseVisionFaceDetectorOptions.ALL_CLASSIFICATIONS)
.setMinFaceSize(0.15f)
.build()
val detector = FirebaseVision.getInstance()
.getVisionFaceDetector(options)
repo = PhotoRepository(application)
observer = Observer {
for (file in it) {
val image = FirebaseVisionImage.fromFilePath(application, Uri.parse(file.uri))
AsyncTask.execute {
detector.detectInImage(image).addOnSuccessListener { list ->
if (list.isNotEmpty()) {
file.hasFaces = 1
repo.update(file)
} else {
file.hasFaces = 2
repo.update(file)
}
}
}
}
}
repo.getAllPhotos().observeForever(observer)
val notificationIntent= Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0)
val notification = NotificationCompat.Builder(this, getString(tech.levanter.anyvision.R.string.channel_id))
.setContentTitle("Detecting faces..")
.setContentText("64 photos detected")
.setSmallIcon(tech.levanter.anyvision.R.drawable.ic_face)
.setContentIntent(pendingIntent)
.build()
startForeground(1, notification)
return START_NOT_STICKY
}
override fun onDestroy() {
super.onDestroy()
repo.getAllPhotos().removeObserver(observer)
}
}
看到你的代码是用 Kotlin 写的,我建议你试试 Kotlin Coroutines。这将使您能够分派昂贵的操作,即查询数据库,使网络 requests/calls 关闭到其他线程,从而不会阻塞 UIThread
。 Coroutines
帮你免去callbacks
的麻烦。此外,Google 刚刚弃用了 AsyncTask
API 以支持 Coroutines
作为多线程目的的方式。
我正在构建一个应用程序,它需要浏览本地存储的一组照片,我将这些照片导入房间数据库,并尝试检测每张照片是否包含人脸。 我已经把所有东西都整理好了,我唯一的问题是如何 运行 这个操作,这可能需要一段时间,在一个不会塞满 UI 线程的服务中。
起初我想使用 JobIntentService
但不能,因为我无法在后台线程上 observeForever,并且不能使用简单的观察者,因为我没有 lifecycleOwner 给 Observer
.
我最终只使用了一项服务,一旦操作开始,我的 UI 就几乎卡住了,如果我尝试做任何事情,应用程序就会崩溃。
我可能试过 IntentService
但我不能在 onHandleIntent
中使用观察者,因为它是一个工作线程,它不允许我,当我 运行 操作在 onStartCommand
下就一样了。
我觉得我被这个东西的架构所困,我会很感激任何想法。谢谢。
这是我的服务:
class DetectJobIntentService : Service() {
private val TAG = "DetectJobIntentServi22"
lateinit var repo: PhotoRepository
lateinit var observer : Observer<MutableList<Photo>>
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val options = FirebaseVisionFaceDetectorOptions.Builder()
.setClassificationMode(FirebaseVisionFaceDetectorOptions.ACCURATE)
.setClassificationMode(FirebaseVisionFaceDetectorOptions.ALL_CLASSIFICATIONS)
.setMinFaceSize(0.15f)
.build()
val detector = FirebaseVision.getInstance()
.getVisionFaceDetector(options)
repo = PhotoRepository(application)
observer = Observer {
for (file in it) {
val image = FirebaseVisionImage.fromFilePath(application, Uri.parse(file.uri))
AsyncTask.execute {
detector.detectInImage(image).addOnSuccessListener { list ->
if (list.isNotEmpty()) {
file.hasFaces = 1
repo.update(file)
} else {
file.hasFaces = 2
repo.update(file)
}
}
}
}
}
repo.getAllPhotos().observeForever(observer)
val notificationIntent= Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0)
val notification = NotificationCompat.Builder(this, getString(tech.levanter.anyvision.R.string.channel_id))
.setContentTitle("Detecting faces..")
.setContentText("64 photos detected")
.setSmallIcon(tech.levanter.anyvision.R.drawable.ic_face)
.setContentIntent(pendingIntent)
.build()
startForeground(1, notification)
return START_NOT_STICKY
}
override fun onDestroy() {
super.onDestroy()
repo.getAllPhotos().removeObserver(observer)
}
}
看到你的代码是用 Kotlin 写的,我建议你试试 Kotlin Coroutines。这将使您能够分派昂贵的操作,即查询数据库,使网络 requests/calls 关闭到其他线程,从而不会阻塞 UIThread
。 Coroutines
帮你免去callbacks
的麻烦。此外,Google 刚刚弃用了 AsyncTask
API 以支持 Coroutines
作为多线程目的的方式。