Reputation: 176
I have been developing this Android app for some time and have realized that my Activities are way too bloated so I have been trying to switch to MVVM with Clean Architecture but am running into an issue. I have this BluetoothLe service that provides the data to my application and it seems like I can only bind to my service from my Activities which is a problem because I am trying to separate the presentation from the data layer.
Here is some code from my activity which uses the service:
@AndroidEntryPoint
class DeviceActivity: AppCompatActivity() {
...
override fun onCreate(savedInstanceState: Bundle?) {
// No NightMode allowed.
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
super.onCreate(savedInstanceState)
binding = ActivityDeviceBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
setSupportActionBar(binding.myToolbar)
if (intent.extras!!.get("btDeviceName") != null) {
deviceName = intent.extras!!.get("btDeviceName").toString()
binding.deviceTitle.text = deviceName
}
setupActionBar()
// Binding to the service via gattServiceIntent.
val gattServiceIntent = Intent(this, BluetoothLeService::class.java)
bindService(gattServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE)
...
}
// Code to manage Service lifecycle.
private val serviceConnection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(componentName: ComponentName?, service: IBinder?) {
bluetoothService = (service as BluetoothLeService.LocalBinder).getService()
bluetoothService?.let { bluetooth ->
// Call functions on service to check connection and connect to devices
if (!bluetooth.initialize()) {
Log.e("blah", "Unable to initialize Bluetooth.")
finish()
}
// Perform device connection
if (bluetoothDevice != null) {
bluetooth.connect(bluetoothDevice!!)
}
}
}
override fun onServiceDisconnected(name: ComponentName?) {
bluetoothService = null
}
}
Then I listen for the data via update receiver:
// Connect to device after registering for the receiver.
private fun registerBluetoothLeServiceReceiver() {
try {
registerReceiver(gattUpdateReceiver, makeGattUpdateIntentFilter())
if (bluetoothService != null) {
connectToBluetoothDevice()
}
} catch (e: Exception) {
Log.d(TAG, "onResume: $e Couldn't register receiver.")
}
}
private val gattUpdateReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
BluetoothLeService.ACTION_GATT_CONNECTED -> {
connected = true
updateConnectionState(context.resources.getString(R.string.connected))
}
BluetoothLeService.ACTION_GATT_DISCONNECTED -> {
connected = false
updateConnectionState(context.resources.getString(R.string.disconnected))
leaveActivity()
binding.progressBarCyclic.visibility = GONE
}
// When services are discovered on the device, we request gatt to update the mtu size.
BluetoothLeService.ACTION_MTU_UPDATED -> {
bluetoothService?.enableNotification()
}
// We write the characteristic only when notifications have been enabled.
BluetoothLeService.ACTION_NOTIFICATION_ENABLED -> {
bluetoothService?.writeGattCharacteristic()
}
// This is where the data stream is received.
BluetoothLeService.ACTION_DATA_AVAILABLE -> {
val byteArr = intent.getByteArrayExtra("byteArray")
Log.d(TAG, "onReceive: ${byteArr.contentToString()}")
if (byteArr != null) {
// Firmware versions greater than 3634 have different data streams.
binding.recyclerviewDevices.visibility = View.VISIBLE
if (isLessThan3634 && boardVersion == 2.1) {
dataProcessor.processData(byteArr)
} else {
dataProcessor.processData(byteArr, 1)
}
}
}
}
}
}
After this is a bunch of data manipulation and processing which I would much rather do in my ViewModel or another class for separation purposes.
Is there a way that I can get my service to bind to a repository or something that will allow me to separate the presentation and data layers so I can listen for data in something other than my Activity?
Upvotes: 0
Views: 1161
Reputation: 91
I think you will need to add a new android module and name it "device" that implements your Bluetooth datasource and inject this module in your data layer. This article could help you
https://five.agency/android-architecture-part-1-every-new-beginning-is-hard/
Upvotes: 2