I'm working on a project that interacts with a BLE device. When the app is open, I actively display data transmitted from the device. However, I want to be able to receive data when the app is closed as well. Right now, I have a foreground service running that continues to receive data from the BLE device after the app is closed. I want to persist this data and update the state when the app is resumed.
Right now, I have a ViewModel
that handles the UI of the fragments. My plan was initially to pass all my data through bundles to my Service when my MainActivity is destroyed. And then, whenever I receive data from the BLE device, I store the new states in shared preferences. When MainActivity resumes, I check sharedPreferences to retrieve the state updated in the Service and we continue from there.
However, I'm not sure if this is the best way to do things, because I have quite a bit of data stored in my ViewModel (2 dataclasses, 1 List of BLE Devices, and 1 List of a BLE Service). I was wondering if there's a better way to maintain states like this, like for example a ViewModel but more server-like.
Take a look. I've created a foreground service and tested this code on API 34.
There is no need to use Bundles or Binders.
I removed the irrelevant lines. As you can see I can transfer data from MainActivity
to FGService
and vice versa by simply calling methods.
Normally both the service and the activity are running only once at a time. So using a singleton is just fine. If you plan to run the activity multiple times simultaneously you have to update the code.
To persist the data I recommend using SQLite because it's not only faster than shared prefs.
MainActivity.kt:
package com.example.myapplication
import android.content.Intent
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
companion object {
var sngltn: MainActivity? = null
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sngltn = this
startForegroundService(Intent(this, FGService::class.java))
}
fun fromFGService(data: Int) {
Log.e("moh", "MainActivity received some data from FGService: $data")
}
override fun onDestroy() {
super.onDestroy()
if (FGService.sngltn != null)
FGService.sngltn!!.fromMainActivity(123)
sngltn = null
}
}
FGService.kt:
package com.example.myapplication
import android.app.Service
import android.os.Looper
import android.util.Log
class FGService : Service() {
companion object {
var sngltn: FGService? = null
}
override fun onCreate() {
super.onCreate()
sngltn = this
if (MainActivity.sngltn != null) MainActivity.sngltn!!.fromFGService(456)
if (Looper.getMainLooper() == Looper.myLooper())
Log.e("moh", "FGService running on main thread (good)")
else
Log.e("moh", "FGService not running on main thread (bad, not as expected)")
}
fun fromMainActivity(data: Int) {
Log.e("moh", "FGService received some data from MainActivity: $data")
}
override fun onDestroy() {
super.onDestroy()
sngltn = null
}
}