Office Hours — Today, May 30

Thursday, May 28

May 30
3:55 PM
Mark M.
has entered the room
Mark M.
turned on guest access
Kai H.
has entered the room
Mark M.
hello, Kai!
Kai H.
HI there
Mark M.
how can I help you today?
4:00 PM
Kai H.
I have a couple of questions ;)
You could answer them if possible
Mark M.
so long as neither of them are "what was that thing floating in the Crew Dragon capsule?", I can try
Kai H.
Damn. Well, that was pretty much all I had...
Mark M.
I'
I'm sure you'll come up with something
Kai H.
Jokes aside, I am kinda reluctant to use callbacks in android, but don't really know why.
Mark M.
how are you defining "use callbacks"? do you mean implementing your own APIs that take a callback/listener sort of object?
Kai H.
I think it's because there is "it can lead to memory leaks" in the back of my head.
Eric
has entered the room
Mark M.
(hello, Eric -- I will be with you shortly!)
Eric
no problem
Mark M.
Kai: callbacks do not result in memory leaks "just because"
Kai H.
One example is to pass a callback to an Adapter that then passes it to a ViewHolder, so the original class can be notified if something in the ViewHolder is clicked.
Mark M.
so long as the original class' lifecycle matches or exceeds that of the ViewHolder, you should be fine
Kai H.
In short, I find myself implemeting Interfaces and Callbacks quite a bit and was wondering if I should try to avoid it or "if callbacks are here to stay"
Mark M.
well, things like RxJava and coroutines are designed in part to try to eliminate the need for callbacks in some cases, not just for thread management
4:05 PM
Mark M.
but otherwise, "callbacks are here to stay" in one form or fashion
asynchronous programming, whether involving threads or not, dictate something like callbacks -- other languages/frameworks might use message passing or other approaches
Kai H.
So I shouldn't feel bad when creating yet another interface to implement a callback with?
Mark M.
well, if there is a suitable existing interface, use it :-)
that includes using things like Runnable and Callable, which can be converted into lambda expressions in Java 8
and lambda expressions are the typical approach for lightweight callback structures in Kotlin
(or, more accurately, function types are the typical approach, with lambda expressions being the typical implementation)
so, worry less about using callbacks and worry more about identifying the patterns that help you avoid memory leaks when using them
and with that, let me take a question from Eric, and I'll return to you shortly
Eric: your turn! how can I help you today?
4:10 PM
Eric
I am loading a recyclerview grid using image urls I render using an api but cannot preserve my scroll position if I rotate my device.
Mark M.
Florina Mutenescu just had a Medium post on that... hold on...
Eric
I actually tried it and it did not fix it
Mark M.
OK (BTW, my apologies to Florina Muntenescu for missing a letter in her surname...)
Eric
View paste (4 more lines)
I tried:
private lateinit var cats: ArrayList<Cat?>

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    catAdapter = CatAdapter(listOf())
    rv.layoutManager = GridLayoutManager(this, COLUMNS)
    rv.adapter = catAdapter

    if (savedInstanceState != null) {
        cats = savedInstanceState.getParcelableArrayList<Cat?>(CAT_LIST)
                as ArrayList<Cat?>
        catAdapter.setItems(cats)

...
Mark M.
your other main option is to keep tabs on the scroll position and restore it yourself after the configuration change
Eric
View paste
adapter setItems:
fun setItems(cats: List<Cat?>) {
    this.cats = cats
    notifyDataSetChanged()
}
Mark M.
OK, that would hold onto your list of cats, but not the scroll position
Eric
if you're referring to https://stackoverflow.com/questions/28236390/re... I tried it too and it did not work
Mark M.
4:15 PM
ndrocchietto_ivano
has entered the room
ndrocchietto_ivano
Hello
Mark M.
(hello, Ivano -- I'll be with you shortly!)
Eric
yes florina is suggesting using a new recyclerview version containing an api to delay loading contents. I added adapter.stateRestorationPolicy = PREVENT_WHEN_EMPTY afte creating my adapter inside of onCreate and it did not work
Mark M.
Eric: the problem in your code is the catAdapter = CatAdapter(listOf())
only do that if you have no saved instance state
and only set the adapter on the RecyclerView after you have created the adapter with the saved instance state
right now, you create an adapter on an empty list, attach that adapter, then populate the list and say that the data has changed
that will blow away the scroll position that RecyclerView holds onto
(in its own saved instance state logic)
Eric
can I still use notifyDataSetChanged?
Mark M.
you won't need it, at least for your onCreate() logic
if you are using that setItems() function elsewhere, then you would still need notifyDataSetChanged()
(or, have your adapter be a ListAdapter and use submitList(), and let it calculate the necessary changes)
Eric
ok let me try. I can get back to you
Mark M.
OK, I'll take a round of questions from the others, and I will return to you in a bit
Ivano: your turn! how can I help you today?
4:20 PM
ndrocchietto_ivano
well I went trough a problem with the adapter last week, I went in production Wirth a work around although! but I would like to know what could have gone wrong. Basically on scroll the adapter started to repeat randomly the values that were inserted in the first positions
I saw is a common problem on SO, but I am wondering if you think something could be wrong in getItemViewType in this adapter
Mark M.
that's often a sign of having bugs in the binding logic when rows get recycled
ndrocchietto_ivano
View paste (79 more lines)
class CashCountAdapter(private val viewModel: CashCountViewModelInterface) :
    RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    private var cashUnitsList: List<CashCountFormType> = emptyList()
    private val headerCell = R.layout.text_header_cell
    private val countCashUnitCell = R.layout.cash_count_cash_unit_cell
    private val countOtherUnitCell = R.layout.cash_count_other_unit_cell
    private val countFreeAmountCell = R.layout.cash_count_free_amount_cell

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {

        val view = parent.inflate(viewType)

        return when (viewType) {
            headerCell -> SectionHeaderViewHolder(view)
...
ah is in onBind
Mark M.
I *think* your getItemViewType() is OK
ndrocchietto_ivano
this is the workaround that works well units_count_rv.setupRecyclerView(adapter)//.setItemViewCacheSize(30)
Mark M.
meaning that the workaround is the setItemViewCacheSize(30) call?
ndrocchietto_ivano
ok, my concern is that in the future I would like to avoid this thing, I am working at a financial app and do not want to mess up the customers with random money
yes it is
and works as a charm
4:25 PM
Mark M.
that really feels like a recycling logic bug, and your workaround might stop working if your list size exceeds 30
ndrocchietto_ivano
I see god bless android complexity, this open the space to my second qualitative question, when will be my turn again, thaniks
Mark M.
your onBindViewHolder() seems to be missing a scenario -- you have three view holder types and only two cases that I see in onBindViewHolder()
partly, that is because I missed that CashOtherUnitViewHolder extends CashUnitViewHolder
but that logic worries me a bit
personally, I would prefer a simpler structure for the view holders (I don'
(I don't see why you need that inheritance there)
ndrocchietto_ivano
do not tell me
I think coding should be dump
but my senior is a medium(sorry for the intended pun)
and is in the phase that like complexity
Mark M.
have your senior debug it, then :-)
ndrocchietto_ivano
ahahah not easy a lot of internals
but you right I can debug de alphabet SDK engineers
Mark M.
but, in general, I would focus on making sure your onBindViewHolder() calls and the effects on the view holders are working as you expect -- my guess is that your problem lies there
ndrocchietto_ivano
mmh thanks
Mark M.
let me take questions from the others, and I will be back with you in a while
4:30 PM
Mark M.
Kai: back to you! do you have another question?
4:30 PM
ndrocchietto_ivano
(okido, thanks)
Kai H.
Yes
I have someone that I want to take a look at my app, but that person has no android phone.
Do you know of a good way of dealing with that?
Mark M.
ummmm... eBay? :-)
Kai H.
I was thinking of a small android emulator or something.
Mark M.
do they just need to see it (and you drive it), or do they need to interact with it?
Kai H.
Interact. They should be able to test it, pretty much
Mark M.
the primary standalone (non-SDK) emulator that I know of is Bluestacks: https://www.bluestacks.com/
second is Genymotion: https://www.genymotion.com/
I haven't used Bluestacks, and I haven't played with Genymotion in years
but I think both are supposed to be within reach of a non-technical person to install and use
Kai H.
Thanks, I'll have a look
Mark M.
and Genymotion has a cloud offering now, I see, and I don't know what that might do for you
but something along those lines would be the direction I'd go, other than the "buy a cheap phone off eBay" route
4:35 PM
Mark M.
the downside of emulators is that size and touch-friendliness isn't as easy to tell
Kai H.
It's more about the interface of the app
Mark M.
an emulator window frequently is a lot bigger than a phone (if perhaps lower screen density)
if it's mostly a look at the aesthetics, an emulator probably is fine
but it's difficult to gauge whether some touch target is too small using an emulator, for example
but, you should have a few options, at any rate
let me take questions from the others, and hopefully there will be time for another from you shortly
Eric: back to you! do you have another question?
Eric
View paste
I tried
rv.layoutManager = GridLayoutManager(this, COLUMNS)

    if (savedInstanceState != null) {
        cats = savedInstanceState.getParcelableArrayList<Cat?>(CAT_LIST)
                as ArrayList<Cat?>
        catAdapter = CatAdapter(cats)
        rv.adapter = catAdapter
    } else {
        catAdapter = CatAdapter(listOf())
    }
but it is not working
Mark M.
move rv.adapter = catAdapter to after the if/else structure
View paste
if (savedInstanceState != null) {
    cats = savedInstanceState.getParcelableArrayList<Cat?>(CAT_LIST)
            as ArrayList<Cat?>
    catAdapter = CatAdapter(cats)
} else {
    catAdapter = CatAdapter(listOf())
}

rv.adapter = catAdapter
also, unless you have few cats, you may be better off using a ViewModel rather than the saved instance state Bundle
4:40 PM
Mark M.
I get nervous about lists in the saved instance Bundle due to their potential size, plus the need to make things Parcelable
Eric
it still is scrolling back up after rotation. good point about bundle size
I populate my list using a button to get cats
Mark M.
I'm impressed that you can get cats to respond to a button
does it dispense treats or something?
:-)
Eric
lol
ndrocchietto_ivano
(lol)
Kai H.
:D
ndrocchietto_ivano
(skinner experiment)
Mark M.
anyway, off the cuff, I do not know why this change did not help
Eric
View paste
after I get cats I load my list into our adapter using:

this.cats = cats
catAdapter  = CatAdapter(cats)
rv.adapter - catAdapter
Mark M.
that is for the initial population of the RecyclerView, before the configuration change, right?
Eric
yep
Mark M.
you could always capture information about the scroll position in your onSaveInstanceState() and use that to fix the scroll position yourself after the configuration change
that should not be needed, but perhaps there is something else that is interfering with the RecyclerView built-in behavior here
Eric
it was in my second SO link but it did not work, weird
4:45 PM
Mark M.
sorry, but I do not have another suggestion off the top of my head
Eric
I did notice if I prevent my activity from restarting it preseves my scroll positon
Mark M.
you mean via android:configChanges in the manifest?
Eric
yep
Mark M.
yeah, that's because it is still the same RecyclerView after the configuration change
there is nothing stopping you from using android:configChanges, but in many cases it creates more headaches than it solves
let me take another question from Ivano, and I'll try to get you another opportunity before the end of the chat
Ivano: back to you! do you have another question?
ndrocchietto_ivano
yep is a qualitative one
Eric
thank you
ndrocchietto_ivano
I had headaches with adapters, Eric had it as well.
Mark M.
RecyclerView is awesome, except when it is not
4:50 PM
ndrocchietto_ivano
ahahah, I have been following hybrid cross platform since the beginning, but I always thought was not worty
well now there is flutter in this ugly Dart and Fuchsia could be around the corner
Mark M.
Fuchsia has been "around the corner" for a while now
ndrocchietto_ivano
I ruined my analyst skills and I think could be the future of native,
Mark M.
one very large corner, apparently
ndrocchietto_ivano
yeah please ignore fuchsia
flutter is fast, and no grade time, native compilation, no IOS android headaches, and google is pushing hard and the community is adopting it more and more, and there are not roadblock anymore you can do everything you do with native and you should not do you can implement an activity in Dart in a native app,
do you have also the feeling that flutter in 2020 is a serious "threat" to native?
grade time*
gradle time*
Mark M.
I would not be surprised if in 2020 Flutter is 5% of new project development
ndrocchietto_ivano
thank you very much to share this with me, really appreciated Mark!
I am going to embrace a bit of his ugliness
Mark M.
Flutter is a "serious player", though it is far from being in a dominant position
ndrocchietto_ivano
agree
Eric
has left the room
Mark M.
Flutter also I think is now big enough that even if Google cut way back on its own efforts, it would continue to progress
4:55 PM
ndrocchietto_ivano
yes is my feeling and managers will prefer because can go faster in production and cut costs
I think the tip point will be when dart will be more modern in a new release
Mark M.
whether Flutter winds up really being faster and cheaper will depend a lot on team- and firm-specific situations
ndrocchietto_ivano
you are right but COVID helps on this regard to find shortcuts
could accelerate the winding up
anyway thanks
Mark M.
OK, we're just about out of time -- any final questions?
ndrocchietto_ivano
nope
Kai H.
What was that thing flying around in the cockpit of spacex?
;-)
Mark M.
looked like an inflatable bedazzled dinosaur to me
ndrocchietto_ivano
(ahah)
Mark M.
there's probably a story behind that
ndrocchietto_ivano
there is Steve Ballmer inside
5:00 PM
Mark M.
OK, that's a wrap for today's chat
next one is Tuesday at 8:30am US Eastern
Kai H.
Stay well everyone
Mark M.
have a pleasant day, and stay healthy!
Kai H.
And have a good time
ndrocchietto_ivano
thanks
Kai H.
has left the room
ndrocchietto_ivano
has left the room
Mark M.
turned off guest access

Thursday, May 28

 

Office Hours

People in this transcript

  • Eric
  • Kai Hatje
  • Mark Murphy
  • ndrocchietto_ivano