I been struggling a lot thinking about where to place Android Services in the new Android recommended Architecture. I came up with many possible solutions, but I cannot make up my mind about which one is the best approach.
I did a lot of research, and I couldn't find any useful guideline nor tutorial. The only hint I found about where to place the Service in my app architecture is this one, from #JoseAlcerreca Medium post
Ideally, ViewModels shouldn’t know anything about Android. This improves testability, leak safety and modularity. A general rule of thumb is to make sure there are no android.* imports in your ViewModels (with exceptions like android.arch.*). The same applies to presenters.
According to that, I should place my Android Services on the top of my Architecture Components hierarchy, at the same level as my Activities and Fragments. That's because Android Services are part of the Android framework, so ViewModels shouldn't know about them.
Now, I will explain briefly my scenario, but only to make the panorama clearer, not because I want an answer for this specific scenario.
I have an Android Application that has a MainActivity with many fragments in it, all of them tied together in a BottomNavBar.
I have a BluetoothService bound to myActivity and one of its fragments (because I want the Service to have the same lifecycle as the Activty but I also want to interact with it directly from my fragment).
The fragment interacts with the BluetoothService to get two types of information:
Information about the state of the Bluetooth connection. Doesn't need to be persisted.
Data that comes from the Bluetooth Device (it is a Scale, so weight and body composition in this case). Needs to be persisted.
Here are the 3 different architectures I can think of:
LiveData inside AndroidService
UPDATE: This is the approach I personally went with at the time because it worked well and allowed me to get it done relatively fast. However, I suggest following the updated answer by Jeel Vankhede for what seems to be a more "idiomatic" implementation.
The LiveData with the state of the connection and with the weight
measurements coming from the Bluetooth Device are inside the BluetoothService.
The Fragment can trigger operations in the BluetoothService (scanDevices for example)
The Fragment observes the LiveData about the state of the connection
and adapts the UI accordingly (for example, enable a button if the
state is connected).
The Fragment observes the LiveData of the new weight measurements. If a new weight measurement comes from the BluetoothDevice, the Fragment then tells its own ViewModel to save the new data. It is done via a Repository class.
Shared ViewModel between fragment and AndroidService
The Fragment can trigger operations in the BluetoothService (scanDevices for example)
The BluetoothService updates the Bluetooth related LiveData in the shared ViewModel.
The Fragment observes the LiveData in its own ViewModel.
Service ViewModel
The Fragment can trigger operations in the BluetoothService (scanDevices for example)
The BluetoothService updates the Bluetooth related LiveData in its own ViewModel.
The Fragment observes the LiveData in its own ViewModel and the BluetoothService ViewModel.
I am pretty sure I should place them on top of the architecture and treat them just like an Activity/Fragment, because BoundServices are part of the Android Framework, they are managed by the Android OS and they are bound to other Activities and Fragments. In that case, I don't know what's the best way to interact with LiveData, ViewModels and Activities/Fragments.
Some might think that they should be considered as a DataSource (since in my case it's getting data from a scale using Bluetooth), but I don't think this is a good idea, because of all what I've said in the previous paragraph and specially because of what it says here:
Avoid designating your app's entry points—such as activities,
services, and broadcast receivers—as sources of data. Instead, they should only coordinate with other components to retrieve the
subset of data that is relevant to that entry point. Each app
component is rather short-lived, depending on the user's interaction
with their device and the overall current health of the system.
So, finally, my question is:
Where should we place our Android (Bound) Services and what is their relation with the other architectural components? Is any of these alternatives a good approach?
Updated:
After getting suggestion from #Ibrahim Disouki (Thank you for that) I dig deeper and found out something interesting! Here's background.
O.P. seeks for solution "Where Service component of Android Framework stands considering Android Architecture Components". So, here's out the box(SDK) solution.
It stands at the same level as Activity/Fragment. How? If you're extending Service class though rather than that, start extending LifecycleService. Reason behind that is simple that previously we had to rely on Activity/Fragment lifecycle in order to receive updates/do some contextual operations on Service. But now it's not the case.
LifecycleService now has it's own lifecycle registry/maintainer called ServiceLifecycleDispatcher which takes care of lifecycle of service which also makes it LifecycleOwner.
It leaves us in condition that from now on, You can have a ViewModel to LifecycleService doing operations for itself & if you're following proper app architecture and having repository pattern leaves you to single source of truth!
In context of O.P. LifecycleService now can have ability to maintain it's ViewModel to do business logic related to repository layer, and later on another lifecycle aware component like, Activity/Fragment can also consume/reuse same ViewModel to have their specific operations to it.
Please note that by doing so, you're in state of having two different LifecycleOwners (Activity & LifecycleServie) which means you can't share view models between LifecycleService & other lifecycle aware components. If you don't like approach then be good with old callback kind of approach having callbacks back to Activity/Fragment from service when data is ready to serve etc.
Obselete:
(I suggest not to read through)
In my opinion, Service should be on same level as Activity/Fragment, because it's Framework component & not MVVM. but because of that Service doesn't implements LifecycleOwner and it's Android Framework Component, it shouldn't be treated as data source because it can be entry point to application.
So, dilemma here is that sometimes (In your case), Service acts as data source which provides data from some long running task to UI.
So what it should be in Android Architecture Component? I think you can treat it as LifecycleObserver. because, no matter what you do in background, you'll need to consider about lifecycle of the LifecycleOwner.
Why? because, we usually do bind it to LifecycleOwner (Activity/Fragments) & to do long running tasks off the UI. So, it can be treated like LifecycleObserver. In such a way we made our Service as "Lifecycle aware component" !
How you can implement it?
Take your service class and implement LifecycleObserver interface to it.
When you bind your service to Activity/Fragment, during your service connection of your service class, add your service to your activity as LifecycleObserver by calling method getLifecycle().addObserver(service class obj)
Now, Take an interface in service class to provide callback from service to your UI and every time your data changes, check that if your service has at least on Lifecycle event create or resume to provide callback with.
In such a way, we won't require LiveData to update to from service and even no ViewModel (Why do we need it for service? We don't need configuration changes to survive on service lifecycle. And main task to VM is that to consist data between lifecycles).
Side Note: If you think you're having long running background operations, then consider using WorkManager. After using this library, you'll feel like Services should be marked as deprecated by now! (Just a random thought)
One way to avoid direct contact with an Android service while still being able to use it is through an interface object. This is part of the "I" for Interface Segregation in the acronym, SOLID. Here is a small example:
public interface MyFriendlyInterface {
public boolean cleanMethodToAchieveBusinessFunctionality();
public boolean anotherCleanMethod();
}
public class MyInterfaceObject implements MyFriendlyInterface {
public boolean cleanMethodToAchieveBusinessFunctionality() {
BluetoothObject obj = android.Bluetooth.nastySubroutine();
android.Bluetooth.nastySubroutineTwo(obj);
}
public boolean anotherCleanMethod() {
android.Bluetooth.anotherMethodYourPresentersAndViewModelsShouldntSee();
}
}
public class MyViewModel {
private MyFriendlyInterface _myInterfaceObject;
public MyViewModel() {
_myInterfaceObject = new MyInterfaceObject();
_myInterfaceObject.cleanMethodToAchieveBusinessFunctionality();
}
}
Given the above paradigm, you are free to place your services in a package that's outside your packages that contain POJO code. There is no "right" location to put your services -- but there are definitely WRONG places to put them (e.g. where your POJO code goes).
What if we bind/unbind to/from service from activity or multiple activities as usual in onStart/onStop, then we have singleton instance that holds Bluetooth related manager (I use nordic lib for ble manager) . That instance is in service so that we can disconnect for example when service is destroyed because ui unbound from it and reconnect to ble when service is created. We also inject that ble manager singleton into viewmodel to make interaction and data listening easier via livedata or rx or similar reactive data provided by ble manager, for example for connection state. This way we can interact from viewmodel with ble, subscribe to characteristics etc and service is there to provide scope that can survive over multiple activities and basically knows when to connect or disconnect. I have tried this approach in my app and so far it works ok.
Sample project
https://github.com/uberchilly/BoundServiceMVVM
In my opinion using LiveData in servise is comfortable
class OneBreathModeTimerService : Service() {
var longestHoldTime = MutableLiveData<Int>().apply { value = 0 }
...
}
Then in fragment
override fun onCreate(savedInstanceState: Bundle?) {
mServiceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, binder: IBinder) {
mOneBreathModeService = (binder as OneBreathModeTimerService.MyBinder).service
mOneBreathModeService!!.longestHoldTime.observe(this#OneBreathModeFragment, androidx.lifecycle.Observer {
binding.tvBestTime.text = "Best $it"
})
}
override fun onServiceDisconnected(name: ComponentName) {}
}
I am not pro in LiveData, but what can be wrong with such approach?
This question confuse me a long time. I don't think bind service should have a viewModle , as we known , the service are not view layer !
By the way, Service need to start/bind,unbind at activity
Finally, I think a easy and not bad way is the LiveData inside AndroidService. But not use Livedata to send data, use custom callback method.
Live data only send the newest data every time, if you need got the complete data also the page is onPause, there is a mistake.( Now, we can use kotlin flow)
Also We not just receive data from ble(bluetooth low energe) device, we also need send data to ble device.
There is a simple project code:
https://github.com/ALuoBo/TestTemp/blob/main/bluetooth/src/main/java/com/lifwear/bluetooth/BLECommService.java
How about treating your service like this?
This is the question worth to be asked on the behalf of the new developers in Android.
Idea is to provide a deep understanding to why the framework is written as such.
Also, developers face dangling pointers, illegal states and such run-time crashes, and they do not have a clue that why it is happening.
Programmers now a days heavily use call back and factory patterns. Use of delegate class objects reduce the need for Singleton classes, and the need of multiple inheritance in languages like C, C++.
Developers thrill when they come to understand Handler based message passing between components.
Which one of these methods is more reliable to know that the context of the Fragment, should no longer be used by its components, or outside from the Activity that is parenting it:
onStop()
onDetach()
onDestroyView()
onDestroy()
Best Regards.
Kindly go through this link to understand the lifecycle of Fragments
It says that while your current fragment (you can track using getter and setter in Application extended class) is in dying phase, getView(), and getActivity() will return null. So you should not be using these methods and be cautious of the concerned life cycle callbacks (again can be tracked using boolean getters and setters in the abstract BaseFragment/BaseActivity sub-classes of the regular concrete Fragments and Activity classes).
source
I am tracking all of these methods, to stop using getView() of fragment. I logically feel onDestroy(), is the most suitable method for this purpose.
I am using the trackers in the same way in this answer:
https://stackoverflow.com/a/52017405/787399
This inheritance strategy greatly helps and improves the meaning of the Activity and Fragments life-cycles. I fact it is so power full that you can have those features that are not implicitly provided: Like you can handle system back press (managed in the BaseActivity in onBackPressed() method) whenever back is pressed on the Fragment, and you can block the back pressed event call, till some condition is met, or place an OK_Cancel confirmation alert, that whether you want to really exit the current fragment.
Happy coding :-)
What is an Abstract Activity in android? This question was asked at one of the interview. I tried searching about this at androidxref unfortunately not able to found.
Can any one help to answer this , Thanks!!
There is no such term in Android system called AbstractActivity.
Abstract activity is any activity which has been marked as abstract.
And like any other abstract java class, it cannot be instantiated and hence it will fail if passed as intent to startActivity() method. Also Android Studio will not allow you to declare such activity in the manifest file.
These abstract activities are mostly used by some android libraries to declare abstract methods and provides any method implementations useful for its task like login mechanism.
One of the advantage of this approach over an interface is that it can make use of activity callback methods.
As in comments the purpose of AbstractActivity is same as abstract class in java, which cannot be used directly(direct instance creation is not possible).
Using abstract activity you can define a group functionality for app activity screens.
For example,
LoginScreen: Abstract activity holding some functions defined
UserLoginScreen: specific ui/function for common user
AdminLoginScreen: specific ui/function for admin user
I am new to android development.
So I have a question about activities.
On Google developer, they say you have to make a class which is inheriting from the class Activity.
So far so good. Now I am thinking an Activity is a class, which leads to my major problem.
So when activity is a class how can it invoke all the live cycle methods.
In Java, I learnt there must be an object of a class to invoke methods and actions. So when activity is not an object but a class, how is this possible.
Kindest regards
Jan
When a user starts your app the android operating system will instantiate an object based on your class which must be a subclass of Activity.
The operating system will use that object and call the lifecycle hooks (e.g. onCreate, onResume, ...) which you implented in your activity subclass when one of the related lifecycle events happens.
Here it is clearly mentioned under CREATING AN ACTIVITY header, that system calls the callback methods, based on which event has occurred. Suppose user is interacting with your activity, then using the object created by the OS for that activity, all the callback methods will be executed. Please refer.
I have an android application with a number of activities.
I have a singleton class holding my main data model which all activities access to get data.
The problem is that sometimes the android GC decides to destroy my singleton when the app in the background (when you press the home button).
Is there anyway that I can bypass this?
I've had this exact problem in a current application of mine, which needs to retain a large amount of data in various 'singleton' classes. The problem I encountered was as in your case; i.e. sometimes when bringing the application back to the foreground, some of the static 'singleton' classes have been destroyed.
The problem, I believe, is that the 'lifetime' of such classes can never be well defined or predicted. After all, it's a class sat there holding a reference to itself, so it's susceptible to being garbage collected when the system wants to grab some resources.
You're probably already aware that extending android.app.Application is a well-known alternative to using conventional Singletons. The solution that worked for me is to hold the actual instances of data singleton classes within an extension class of android.app.Application, whose lifecycle is well defined. Any other class that wants to access those singletons can obtain them using a getter in the Application class.
So for example I have a class called AppState that extends Application, that holds the instances within:
import android.app.Application;
public class AppState extends Application {
...
// "Singleton" instances that this Application extension looks after
private MSData singletonInstanceMSData;
public AppState() {
...
singletonInstanceMSData = new MSData();
...
// ---------------- Singleton instance control ----------------
public MSData getMSData(){
return singletonInstanceMSData;
}
// I also provide the means to 'reset' the instances on startup (this is
// something I need to do for my application - you may or may not need to)
public void resetControllerSpecificData(){
singletonInstanceMSData.reset();
...
Don't forget you'll need to modify your manifest if you extend Application.
AFAIR, lifespan os singleton is lifespan of his classloader - also complete VM . When user hit home button, your application goes in backgorund and is probably destroyed - you can not do anything against it. Your best bet is to save whatever is necessary in your onPause() callback ( or just use write through in every change of datza if you really paranoid )