In my old app, this is the way how I perform time-consuming I/O operations in AppWidgetProvider's onUpdate function.
public class MyAppWidgetProvider extends AppWidgetProvider {
private static ExecutorService thread_executor = java.util.concurrent.Executors.newFixedThreadPool(1);
#Override
public void onUpdate(
Runnable runnable = ...
thread_executor.execute(runnable);
I don't think that is a good way, especially comes to Android 8.
I like LiveData concept, as we need not handling threading explicitly. Yet, it enables us to perform time-consuming operation, without blocking Main thread.
I was wondering, is it possible to use LiveData, and attach an Observer to perform time-consuming I/O operation (Like reading from SQLite database), within AppWidgetProvider?
I'm not really sure how to do that, as I have no idea how I can get an LifecycleOwner in AppWidgetProvider, to observe LiveData.
Yes, it is possible for you to use LiveData from within an AppWidgetProvider. There are two ways (that I know) for you to get a LifecycleOwner:
You can call ProcessLifecycleOwner.get().
You can replicate the example from this answer.
Both methods work, it's up to you to choose which one you want to use.
BUT:
You don't need a LifecycleOwner, you can use liveData.observeForever(Observer). In fact, it might introduce some bugs if you use a LifecycleOwner: When the owner moves to the DESTROYED state, your observer won't be called 1.
You shouldn't forget to call liveData.removeObserver(Observer).
Related
I am coming from the embedded world and I am quite new to Kotlin. I know there is some mechanism I can inherit and use in my class, but I don't know the name exactly for this mechanism for Android.
What I am looking for is:
I have my Activity and this one instantiates my CustomClass
My CustomClass perform some background tasks like handling BLE asynchronous communication
CustomClass does not know when some packets will be received.
Once the package is received, the CusomClass should call back the Activity and give the data by means of this mechanism.
What would be the best option to perform these callbacks?
P.s.: My apologies, I looked extensively but I don't even know the name to start my search.
You can use LiveData for this purpose. essentially its an observable data holder, so when you change its data all of its obsrevers get notified.
this enables you to write reactive code and reduce tightly coupled logic. its also lifecycle aware, so your activity only gets notified if its active.
A general idea would be to do following
In your CustomClass declare a LiveData object
class CustomClass{
// Declare a LiveData object, use any type you want String, Int etc
val myData: MutableLiveData<String> = MutableLiveData("")
private fun onBleNotification(notification: String){
// post to live data, this will trigger all the observers
myData.postValue(notification)
}
...
}
In your Activity, observe the LiveData object
onCreate(savedInstanceState: Bundle?){
...
customClass.myData.observe(this, androidx.lifecycle.Observer{
//Do anything with received command, update UI etc
})
}
You can also use event bus or braodcast receiver or interface to achieve your purpose. But the idea given in other answer (liva data, viewmodel) is recommended.
I have some more complex logic for data provided by my ViewModel to the UI, so simply exposing the data via LiveData won't do the job for me. Now I've seen in the Android docs that I can implement Observable on my ViewModel to get the fine-grained control I need.
However in the documentation it also says:
There are situations where you might prefer to use a ViewModel
component that implements the Observable interface over using LiveData
objects, even if you lose the lifecycle management capabilities of
LiveData.
How intelligent is the built-in Android data binding? Will it automatically unregister it's listeners when necessary (e.g. on configuration changes where the View is destroyey) so that I don't have to care about the lost lifecycle capabilities? Or do I have to watch the Lifecycle of the View and unregister it's listeners? (=do manually what LiveData normally does for me).
How intelligent is the built-in Android data binding? Will it automatically unregister it's listeners when necessary (e.g. on configuration changes where the View is destroyey) so that I don't have to care about the lost lifecycle capabilities? Or do I have to watch the Lifecycle of the View and unregister it's listeners? (=do manually what LiveData normally does for me).
So I did some tests. I implemented androidx.databinding.Observable on my ViewModel and did a configuration change with the following log calls:
override fun removeOnPropertyChangedCallback(
callback: androidx.databinding.Observable.OnPropertyChangedCallback?) {
Log.d("APP:EVENTS", "removeOnPropertyChangedCallback " + callback.toString())
}
override fun addOnPropertyChangedCallback(
callback: androidx.databinding.Observable.OnPropertyChangedCallback?) {
Log.d("APP:EVENTS", "addOnPropertyChangedCallback " + callback.toString())
}
I saw that addOnPropertyChangedCallback was invoked for each time my viewmodel was referenced in a layout binding expression. And not once did I see removeOnPropertyChangedCallback invoked. My initial conclusion is that AndroidX databinding is dumb and does not automagically remove the listener.
FYI: the callback type was ViewDataBinding.WeakPropertyListener
However, I took a peek at ViewDataBinding.java source code and found that it is using Weak References to add the listener.
So what this implies, is that upon a configuration change, Android OS should be able to garbage collect your Activity/Fragment because the viewmodel does not have a strong reference.
My advice: Don't add the boilerplate to unregister the listeners. Android will not leak references to your activities and fragments on configuration changes.
Now, if you choose not to use LiveData, consider making your viewmodel implement LifecycleObserver so that you can re-emit the most recent value when your Activity/Fragment goes into the active state. This is the key behavior you lose by not using LiveData. Otherwise, you can emit notifications by using the PropertyChangeRegistry.notifyCallbacks() as mentioned in the documentation you shared at some other time. Unfortunately, I think this can only be used to notify for all properties.
Another thing... while I've not verified the behavior the source code seems to indicate that weak references are used for ObservableField, ObservableList, ObservableMap, etc.
LiveData is different for a couple of reasons:
The documentation for LiveData.observe says that a strong reference is held to both the observer AND the lifecycle owner until the lifecycle owner is destroyed.
LiveData emits differently than ObservableField. LiveData will emit whenever setValue or postValue are called without regard to if the value actually changes. This is not true for ObservableField. For this reason, LiveData can be used to send a somewhat "pseudo-event" by setting the same value more than once. An example of where this can be useful can be found on the Conditional Navigation page where multiple login failures would trigger multiple snackbars.
Nope. ViewModel will not unregister Observable subscription automatically. You can do it manually though. It is pretty easy.
Firstly you create CompositeDisposable
protected var disposables = CompositeDisposable()
Secondly, create your Observable(it may be some request or UI event listener) subscribe to it and assign its result to CompositeDisposable
disposables.add(
someObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ data ->
// update UI or some ObservableFields for view/databinding
}, { exception ->
// handle errors here
})
)
The last thing you should do is to override ViewModel's method onCleared() like this:
override fun onCleared() {
super.onCleared()
disposables.clear()
}
This way all subscription added to your CompositeDisposable will be cleared automatically
Edit
I showed only the example. You may add triggers in onConfigurationChanged or onCreate or onResume to clear subscriptions as well - but it is dependent on specific usecases of an app. I gave just a general one.
Hope it helps.
DataBinding would not do the unregistering for you. Its simply help bind your layout file and the ViewModel. It is the viewModel that will protect you from device's configuration change. You still need to apply onSavedViewState() in your base activity or fragment as viewModel does not cover that. As per unregistering, LiveData does that.
As #Pavio already taught you how to create Observable, that is RxJava working. I would suggest using kotlin's coroutines and viewModel with LiveData to get the best out of your situation. Rx has a learning curve to it, although it does offer hundred of operators for all sorts of operations. If you really want to learn the kotlin way, look into kotlin flows and channels.
If i was in your place, I would solve my problem with ViewModels, LiveData and Coroutines.
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?
I am building an Android Java class which implements the LifecycleObserver interface.
This is the constructor:
public MyObserver(AppCompatActivity activity) {
this.mActivity = new WeakReference<AppCompatActivity>(activity);
activity.getLifecycle().addObserver(this);
}
Is it necessary to ever call removeObserver, using something like:
#OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void destroyListener() {
if (this.mActivity.get() != null) {
this.mActivity.get().getLifecycle().removeObserver(this);
}
}
Or, can I observe forever?
TL;DR: Nope.
According to this link here, where a user asked your question on the android-lifecycles Github repo. The answer of a Google developer to this questions was:
Yes, that's the whole point of the new lifecycle-aware components, no
need to unsubscribe/remove observers.
TL;DR: You're better off explicitly removing the observer when you are done with it, or use something that handles this automatically, such as LiveData.
Lifecycle is an abstract class. So, technically, you have no idea what the implementation is and what the rules of the game are.
The one concrete Lifecycle is LifecycleRegistry. It has strong references to the observers. So now you are counting on the LifecycleRegistry being garbage-collected in a timely fashion, such as when the activity is destroyed. For FragmentActivity, that appears to be the case. So in practice, for the now-current version of all this stuff, you could get away without unregistering the observer and suffer few ill effects, if any.
But that's not part of the Lifecycle contract. Arguably, any decent implementation of Lifecycle (or things that use LifecycleRegistry) should cleanly handle the case where you fail to unregister... but I wouldn't risk it.
I'm using LifecycleRegistry in a singleton object that manages audio sounds.
After adding LeakCanary it detected a memory leak because of this issue.
However, calling removeObserver, the memory leak never appeared again.
So it may be true that when using LiveData + LifecycleRegistry you don't need to unregister. But if it's a custom component using LifecycleRegistry, my experience shows that calling removeObserver is a must to avoid memory leaks.
I have typical AsyncTask that I want to properly decouple from my Activity classes and UI logic.
I think of doing it this way:
Make listener interface
public interface MyTaskListener {
void onTaskProgress(...);
void onTaskDone(...);
}
Make my Activity implement MyTaskListener and pass this reference on task creation.
Call listener methods inonPreExecute(), onProgressUpdate() and onPostExecute().
But may be I'm reinvetning the wheel and Android framework has something better already implemented? I think of something like EventBus pattern where all interested parties can register for particular event types that I can fire from my AsyncTask.
The interface is most clean way of doing this, because your task class is 'sealed', knows nothing about surrounding environment (does not access any stuff from outer class which quite tempting when you use inner classes) and communicates back with generic channel.