Office Hours — Today, January 30

Thursday, January 28

Jan 30
3:55 PM
Mark M.
has entered the room
Mark M.
turned on guest access
4:05 PM
trocchietto_Ivano
has entered the room
trocchietto_Ivano
Hallo Mark Happy new year!
Mark M.
Happy New Year to you as well!
how can I help you today?
trocchietto_Ivano
well I know you are not an RXJava expert, but I would try as well cause is more about Kotlin syntax
Mark M.
OK
trocchietto_Ivano
basically in my team we usually use RXJava in the views as so:
```
View paste

isLoginSuccessful
observeOn(scheduler.ui()).subscribeOn(scheduler.io())
.subscribe { isLoginSuccess ->
    if (isLoginSuccess) finishOk()
    else setValidationStateView()
}
.addTo(disposeBag)
where .addTo(disposeBag) is just a Disposable added with an extension function
4:10 PM
trocchietto_Ivano
well I wanted to surprise my team avoiding code duplication because we use 90 per cent of the cases this formula, so I created an extension(as an old java utility class)
SO that I can call just :
View paste

unknownEnvironment.rx { it->
    print(it)

}
is working really good but if I give an it I get a compile time error
first of all my extension is this
View paste

fun <T> Observable<T>.rx(predicate: () -> (Unit) = {}) {

    this.drivePredicateOnUI()
        .subscribe {
            predicate()
        }.inject()
}

fun <T> Observable<T>.drivePredicateOnUI(scheduler: BaseSchedulerProvider = SchedulerProvider()): Observable<T> = observeOn(scheduler.ui()).subscribeOn(scheduler.io())

fun Disposable.inject() {
    val disposeBag = CompositeDisposable()
    this.addTo(disposeBag)
}
Mark M.
inject() is scary -- you never dispose of that CompositeDisposable
if you do not dispose() it, you leak all the things being observed
trocchietto_Ivano
View paste
usually we have in any class or in a super class :     val disposeBag = CompositeDisposable()
Mark M.
so long as that is being disposed via a call to dispose(), that is fine
depending on where this is, that might be onCleared() of a viewmodel or onDestroyView() of a fragment
4:15 PM
trocchietto_Ivano
Is never in a VM, but always in onDestroy into the activities
we do this
View paste
   override fun onDestroy() {

        super.onDestroy()
        disposeBag.clear()
    }
Mark M.
that is fine... but the CompositeDisposable in inject() is a local variable that is lost
trocchietto_Ivano
I see but anyway, apart from that, I do not get why my extension does not accept a predicate, basically it works fine, but as soon as I give an `it` I get this error message
View paste (1 more line)
Type mismatch.
Required:
() → Unit
Found:
(Any?) → Unit
Overload resolution ambiguity. All these functions match.
public inline fun print(message: Any?): Unit defined in kotlin.io
public inline fun print(message: Boolean): Unit defined in kotlin.io
public inline fun print(message: Byte): Unit defined in kotlin.io
public inline fun print(message: Char): Unit defined in kotlin.io
public inline fun print(message: CharArray): Unit defined in kotlin.io
public inline fun print(message: Double): Unit defined in kotlin.io
public inline fun print(message: Float): Unit defined in kotlin.io
public inline fun print(message: Int): Unit defined in kotlin.io
public inline fun print(message: Long): Unit defined in kotlin.io
...
Mark M.
predicate is declared as () -> Unit
it does not take any parameters
trocchietto_Ivano
yes and I saw that in RXJava subscribe is different as
View paste
 @CheckReturnValue
    @SchedulerSupport(SchedulerSupport.NONE)
    public final Disposable subscribe(Consumer<? super T> onNext) {
        return subscribe(onNext, Functions.ON_ERROR_MISSING, Functions.EMPTY_ACTION, Functions.emptyConsumer());
    }
Mark M.
you probably want predicate to be (T) -> (Unit)
and call it as predicate(it) from inside your subscribe { }
trocchietto_Ivano
I tried but did not work
no it works
doh
thanks
Mark M.
happy to help!
trocchietto_Ivano
so Any is wrong because Any takes only an Any
and instead if I give a generic, does not matter what I am passing
4:20 PM
Mark M.
it is more that if you consistently use T, then `it` will have the right type in your lambda expression that is `predicate`
(sorry for the backticks, but I wanted to set the code off from regular words in the sentence)
trocchietto_Ivano
I see, I need to refresh my SICP in rust
no I mean in Lisp
anyway thank you cristally clear
sudokai
has entered the room
Mark M.
hello, sudokai!
sudokai: how can I help you today?
sudokai
Hello Mark!
4:25 PM
sudokai
I'm still dealing with code that uses the GPS
I was wondering if you knew of some way to wake the GPS
Mark M.
what do you mean by "wake"?
sudokai
The problem I have is those pesky battery managers that come preinstalled with the phones
So I called requestLocationUpdates, then a few minutes afterwards, I literally see the system turn off the GPS in the logcat
Mark M.
are you holding a WakeLock?
sudokai
I need to find a way to turn on the GPS
Not anymore
I did a few tests
And those battery managers don't like wakelocks one bit
If you hold a wakelock, they straight up kill your app
Mark M.
well, yeah, but at the same time, if the device goes to sleep, there go your GPS readings
I forget: are you using LocationManager or Play Services' fused location provider
sudokai
It seems that the device can go into light doze and location updates still work fine
4:30 PM
Mark M.
that sounds right, though it's been a while since I dealt with GPS in the background
sudokai
So I'm not using any wakelocks now
Once it goes into deep doze, then you don't get GPS readings anymore
Mark M.
that also sounds right
sudokai
Anyway, if my device is moving, it shouldn't go into deep doze right?
Mark M.
yes, though I am uncertain how "moving" is determined
sudokai
Also, btw, how can you wake from deep doze? AlarmManager with wakeup?
Mark M.
I would guess it is based on the accelerometer and gyroscope
um, basically, you don't wake from deep doze -- the system wakes itself up and lets apps do bits of work as the system sees fit
sudokai
So what is the ELAPSED_REALTIME_WAKEUP about?
Mark M.
it is from API Level 1
Android 1.0
and so it got neutered in Android 6.0 with the introduction of Doze mode
you can still use it
but it will not actually wake up the device if it is Doze mode
it *will* give you control at the next window when Doze mode gives apps a chance to run again
basically, alarms and jobs get postponed until the next available window
your problem, though, is that the window might be short, and you may have challenges in getting a GPS fix before the window closes
4:35 PM
sudokai
Wait, so what's the difference between ELAPSED_REALTIME and ELAPSED_REALTIME_WAKEUP then?
Mark M.
they will have differences when the device is not in Doze mode
Doze mode only kicks in after an hour or so
trocchietto_Ivano
(interesting to know)
Mark M.
but, in Doze mode, AFAIK those two are effectively equivalent
(BTW, when I use "Doze mode", I'm referring to the full Doze mode, not the light one)
(I wish they had given that light Doze mode a different name)
trocchietto_Ivano
(is a loooong wish list)
sudokai
I read about AlarmManager, and I found the information confusing, as they have been changing its behavior over the version
So, what's the minimum interval of time that's accepted now
Mark M.
15 minutes IIRC
sudokai
in Android 9+ let's say
Even with setExact?
Mark M.
AFAIK, yes
sudokai
I find the whole API very confusing
You have ELAPSED_REALTIME_WAKEUP
But then also, setExactAndAllowWhileIdle
4:40 PM
Mark M.
welcome to the evolution of APIs
at this point, the earliest edition of AlarmManager might be 15 years old
(Android 1.0 is about 12.5 years old, and work was being done before Android shipped 1.0)
trocchietto_Ivano
(And I find really frustrating that before of SDK 19 works still promptly)
Mark M.
expectations surrounding apps and battery life have changed over those years
but, for binary compatibility, older APIs are still theoretically supported, albeit with limitations
for ordinary periodic work, WorkManager is designed to hide all of the complexity
let me take another question from Ivano, and I will return to you in a bit
Ivano: hi! do you have another question?
trocchietto_Ivano
well I do not want to profit too much from you but, I made a modification to solve the Disposable issue
basically I have the super class that gives me val disposeBag =CompositeDisposable() so I pass disposeBag
but is inefficient so I am wondering if this would work without leak:
View paste

fun <T> Observable<T>.rx(
    disposeBag: CompositeDisposable = CompositeDisposable(),
    predicate: (T) -> Unit
) {

    this.driveOnUI()
        .subscribe {
            predicate()
        }.inject(disposeBag)
}
instead to pass it as so that is ugly:
Mark M.
for safety, I would get rid of the default value of disposeBag and always require one to be passed in
4:45 PM
trocchietto_Ivano
View paste
 unknownEnvironment.rx(disposeBag) { it->//passing disposeBag from superclass
                isEnvironmentUnknown.onNext(true)
                validate()
            }
you mean as above?
Mark M.
yes,
trocchietto_Ivano
this is ugly
Mark M.
with the default value, you are back to the original problem: nothing ever disposes of that CompositeDisposable, and so you leak
trocchietto_Ivano
maybe I can make a companionObject as once I had public static variables?
Mark M.
ick
trocchietto_Ivano
sorry what is ick?
Mark M.
sorry
trocchietto_Ivano
:)
Mark M.
"public static variables" is, by definition, a memory leak
trocchietto_Ivano
ahahah
Mark M.
if those are constants, that is not a problem
trocchietto_Ivano
how much street I have to pave to become an expert :)
Mark M.
but putting a CompositeDisposable in a static scope would be rather scary IMHO, though with great care you can perhaps pull it off
trocchietto_Ivano
(because you create a global instance that could never be garbage collected I guess)
Mark M.
and, if it is never cleared or disposed, you leak everything that you observe using that CompositeDisposable
I would just pass in disposeBag
trocchietto_Ivano
wow
okidoki
I will do
maybe can use an abbreviation, thanks
coding is really cool
4:50 PM
Mark M.
sudokai: do you have another question?
sudokai
Yes, so if I want to run anything regularly
In intervals shorter than 15min
My only chance is handler.postDelayed?
Mark M.
use a foreground service to try to keep your process around, and use an in-process timing solution
I would not use postDelayed(), though
plenty of others
ScheduledExecutorService, Completable.timer() from RxJava, etc.
sudokai
> I would not use postDelayed(), though
Mark M.
and, you will need your WakeLock
sudokai
Why not?
Mark M.
it's not really designed for this
and, unless you go through the hassle of setting up a Handler on a background thread, it will give you control on the main application thread, which you probably do not want
ScheduledExecutorService has been around from before Android and works fine for getting control periodically within a running process
sudokai
ScheduledExecutorService won't wake the device though
Right=
4:55 PM
sudokai
?
Mark M.
correct
sudokai
So, regarding doze
is it the same as deviceIdleMode?
Mark M.
no
at least, not as how I would think of it -- I don't know that Google uses "deviceIdleMode" as a term
idle means "the screen turned off", basically
sudokai
Well, it appears in PowerManager
isDeviceIdleMode
Mark M.
ah, OK
from the description, that might match Doze mode
sudokai
I swear to god, Android is so confusing
Mark M.
background work is one of the worst areas
sudokai
I just need something that fires periodically and can wake it up
trocchietto_Ivano
(try my daughter)
sudokai
haha
trocchietto_Ivano
:)
5:00 PM
Mark M.
your definition of "periodically" is fairly frequent
sudokai
Mark, do you have any tips on battery usage?
On reducing battery usage
There's so little documentation about this
Mark M.
um, don't do what you're trying to do :-)
sudokai
I would pay big bucks for a training course on this alone
trocchietto_Ivano
have a nice day everyone
sudokai
Yeah, but I need to do the work
Mark M.
see you, Ivano!
sudokai
if I can't keep the gps on, at least I want to let the user know
So I need to check fairly frequently
Mark M.
in the end, what you are trying to do is not good for the battery
and that's why Android and device manufacturers are fighting you
sudokai
it sucks, because it's my use case
Mark M.
so, "reducing battery usage" is now mostly a system thing
and you need to live within the system, and to a large extent, that means avoiding the sorts of apps that need to consume lots of battery
sudokai
I need to track people's locations realtime
5:05 PM
sudokai
I swear to god, Google Maps uses some private API to wake the GPS
Mark M.
sorry, but I have generally avoided this area for quite some time, in part because IMHO it's a lost cause
sudokai
Yeah, I understand, most apps do not need this
Mark M.
I asked earlier: are you using LocationManager or Play Services' fused location provider?
sudokai
Both :)
Not at the same time of course
But I implemented both
Mark M.
I would expect you to have better luck with Play Services
sudokai
Some phones work better with one of them
Yeah, they use some tricks
Unfortunately, they also have bugs
They show wrong locations sometimes
Mark M.
¯\_(ツ)_/¯
sudokai
Kilometers away
I've been chasing them on the issue tracker for over a year
They say it's fixed, then it regresses again
And it's worse than ever
Mark M.
fortunately, background location access is not something I have ever needed to worry about, and as such, I don't have great advice for you
sudokai
lol
Mark M.
my best recommendation is to find an existing open source project that seems to work well, then dive into it and see what hacks they are using
sudokai
Lucky you
Mark M.
but, at this point, I do need to wrap up this chat
sudokai
Thanks
I hope next time we talk about something else
This is burning me out
:D
Mark M.
I wish you luck!
sudokai
Thanks!
Mark M.
the next chat is Tuesday at 7:30pm US Eastern
have a pleasant day/evening/whatever!
sudokai
You too!
trocchietto_Ivano
has left the room
sudokai
has left the room
Mark M.
turned off guest access

Thursday, January 28

 

Office Hours

People in this transcript

  • Mark Murphy
  • sudokai
  • trocchietto_Ivano