I'm trying to detect when my app was opened, put on foreground, put on background and closed.
I tried to do it like this:
ProcessLifecycleOwner.get().lifecycle.addObserver(ApplicationLifecycleTracker())
...
class ApplicationLifecycleTracker: LifecycleObserver {
#OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onMoveToForeground() {
Timber.d("APP CONTROL - RESUMED")
}
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onMoveToBackground() {
Timber.d("APP CONTROL - PAUSED")
}
#OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun onAppOpened() {
Timber.d("APP CONTROL - OPENED")
}
#OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun onAppClosed() {
Timber.d("APP CONTROL - CLOSED")
}
}
So far, I can get these events right: ON_CREATE, ON_START and ON_STOP.
But ON_DESTROY is never called when I close my application.
How can I get the callback for ON_DESTROY correctly?
Actually your activity is not finished completely. System is temporarily destroying this instance of the activity to save space.
check with function isFinishing() for track the correct status of activity
more details refer onDestroy
Related
I'm trying to observe the result of the View Collection and upstream flows stopped.
But viewModel.testFlow is still collecting while the App is in the background.
Why can't I observe the collection is stopped? Am I observing something wrong?
ViewModel:
val testFlow = flow<Int> {
for (i in 1..100) {
delay(1000)
Timber.e("testFlow: EMIT = $i")
emit(i)
}
}
Activity:
override fun onViewCreated() {
lifecycleScope.launch {
viewModel.testFlow
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
.collect {
Timber.d("testFlow: $it Collected")
}
}
}
override fun onActivityPaused(activity: Activity) {
super.onActivityPaused(activity)
Timber.e("testFlow: onActivityPaused")
}
https://medium.com/androiddevelopers/a-safer-way-to-collect-flows-from-android-uis-23080b1f8bda
You are using Lifecycle.State.STARTED state to start observing Flow, the corresponding method of the Activity when emission stops is onStop(). If onStop() method of Activity is called the emission and collecting will stop.
If you want to stop emitting and collection data when onPause method is called, you can use Lifecycle.State.RESUMED state.
When app goes to background onStop() method of Activity is called and when using Lifecycle.State.STARTED state to observe the Flow you should see the emission and collecting stop.
I am developing an app in which several Activitis bound to a sevice once they become visible to the user. During start up, each Activity needs to:
check some status flag of the service, based on which some UI elements are configured
check wether an adapters is enabled whose reference is inside the service
execute some functions of the Service
Since the applications should not get updates in the background, I bind to the service at onStart() and unbind at onStop(). I.e. in have something like this:
override fun onStart() {
super.onStart()
Intent(context, MyService::class.java).also { intent ->
bindService(intent, serviceCallback, Context.BIND_AUTO_CREATE)
}
}
Now I want to perform the above mentionned actions inside onResume.
override fun onResume() {
super.onResume()
// check flags
// check adapter status
// excute functions of service
}
The problem is that binding to a service is asynchronous and I do not have a valid reference to the Service's binder inside onResume(). Consequently, the app will crash with a nullpointer exception.
Approach 1: Using lateinit
I tried solving this problem using the lateinit keyword. I.e. I define the reference to the binder as
private lateinit var myBinder: MyService.LocalBinder
Problem: I cannot guarantee that the binder is initialized as it is asynchronous. Thus, the app will crash.
Approach 2: Waiting for callback in while loop
In my service callback, I set a flag as follows:
val serviceCallback = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
myBinder = service as MyService.LocalBinder
isServiceBounded = true
}
override fun onServiceDisconnected(arg0: ComponentName) {
isServiceBounded = false
myBinder = null
}
}
Then inside onResume, I block the Activity until the flag is true
override fun onResume() {
super.onResume()
while(!isServiceBounded){
// block and wait
}
}
Problem: Doesn't work either. The app will stop responding and crashes.
Approach 3: Using suspended functions and Kotlin coroutines
A suspended function will not continue unless it has received a return value. This, I can use it to wait for an event. So I tried something like this:
override fun onStart() {
super.onStart()
CoroutineScope(Dispatchers.Main).launch {
bindServiceAndWait(this#Activityname)
}
}
suspend fun bindServiceAndWait(context: Context): Boolean{
Intent(context, MyService::class.java).also { intent ->
bindService(intent, serviceCallback, Context.BIND_AUTO_CREATE)
}
return isServiceBounded // This is the flag from the callback
}
Problem: This suspended function does not actually wait for the callback. It just returns the current value of isServiceBounded.
I found a similar solution here, but I do not quite understand this solution as it has a global service callback (ServiceConnection) as well as a local one inside the suspended function. Also, I don't understand how to I could unbound in this provided example.
What is the proper way of doing this?
you simply can't ensure that service will be bounded until onResume gets called. why won't you introduce flag isResumed, set it in onResume (unset in onPause) and line below check if (isResumed && isServiceBounded).... yes, there is a chance that isServiceBounded = false in onResume, so same if check put in onServiceConnected
In my android application from my background service I want to launch activity with transparent background. Because of the fact that the application is transparent I always want it to be displayed on some other activity from my application. So before the launch I would need to somehow check if any activity is currently opened and if it isn't then open home activity and after that my transparent activity. But if application was already opened then I want to open new activity on top of most recent one.
How could I achieve that? Only thing I found is how to check if my application is in foreground or not. But when my app is in background I would still like to open my transparent activity atop most recent activity.
class FirebaseDbApplication : Application() {
override fun onCreate() {
super.onCreate()
}
companion object{
private var sIsChatActivityOpen = false
fun isChatActivityOpen() : Boolean {
return sIsChatActivityOpen
}
fun setChatActivityOpen(isChatActivityOpen: Boolean) {
this.sIsChatActivityOpen = isChatActivityOpen
}
}
}
// In your activity
override fun onResume() {
super.onResume()
FirebaseDbApplication.setChatActivityOpen(true)
}
override fun onPause() {
super.onPause()
FirebaseDbApplication.setChatActivityOpen(false)
}
// For checking is activity is opened or not
if (FirebaseDbApplication.isChatActivityOpen()) {
// Activity is opened
}
else{
// Activity is closed
}
Unlike Activity, which has a clear lifecycle (onCreate ... onDestroy), Application only has onCreate method. I want to handle some events when the app gets destroyed, but yet find any solution for this. I have read some topic related to this issue, they suggested me to use Service. Does anybody have another solution for this? Thanks.
You can use ProcessLifecycleOwner from architecture component library.
MyClass : LifecycleObserver
{
init
{
ProcessLifecycleOwner.get( ).getLifecycle( ).addObserver( this );
}
#OnLifecycleEvent( Lifecycle.Event.ON_CREATE)
fun onAppCreate( )
{
}
#OnLifecycleEvent( Lifecycle.Event.ON_START)
fun onAppStart( )
{
}
...
#OnLifecycleEvent( Lifecycle.Event.ON_DESTROY)
fun onAppDestroy( )
{
}
}
Sometimes my app is forced to quit and then later Android restarts it just to run a scheduled job. I can't find a callback that would correspond to this scenario: that my app got killed in the meantime, so I have to restore all my retained state.
I want to avoid a proliferation of entry points where I have to re-check whether everything is still in place. I already have onUpdate() for a widget, onCreate() for the main activity, onResume() for a view fragment, and onStartJob() for the scheduled job. Any of them could be the first thing to be called after the app is killed, so in all these places I have to repeat the initialization code.
Is there a single point where I can register a callback that will re-initialize my app state?
To be specific, I have a JobService:
class RefreshImageService : JobService() {
override fun onStartJob(params: JobParameters): Boolean {
MyLog.i("RefreshImageService start job")
updateWidgetAndScheduleNext(applicationContext)
return true
}
override fun onStopJob(params: JobParameters): Boolean {
MyLog.i("RefreshImageService stop job")
return true
}
}
The updateWidgetAndScheduleNext() call involves some state I have:
private data class TimestampedBitmap(val bitmap : Bitmap, val timestamp : Long)
private var tsBitmap: TimestampedBitmap? = null
To compute the timestamp, I have to call into further code that has its own state; that other code is called form all the entry points I mentioned. I'd like to centralize my initialization code, if possible.