Office Hours — Today, April 4

Tuesday, April 2

Apr 4
7:20 PM
Mark M.
has entered the room
7:25 PM
Mark M.
turned on guest access
Paul R.
has entered the room
Paul R.
Greetings again.
Mark M.
hello!
how can I help you today?
Paul R.
I have two questions for you tonight. First up is performance. On my phat, fully loaded MacBook Pro a kotlin program I wrote takes 2 seconds to load ~2Million JSON records from a web site.
Mark M.
I'm impressed you can download a JSON document that large in 2 seconds
Paul R.
When I run that code via a library on an Android app on a Pixel 3 XL it takes ~15 seconds, and on a Nexus 6, fully two minutes.
The disparate times seem out of whack to me. I would have guessed something like, 2s, 5s, 20s would be reasonable. Apparently not the case. What's your take?
7:30 PM
Mark M.
when you say "load", what exactly do you mean? you're going to be hard-pressed to have heap space for ~2 million model objects
Paul R.
Why is that?
Mark M.
um, because heaps aren't that big
say, for example, you have a 64MB heap
that leaves you with 32 bytes per model object
while it is certainly possible to have a model object that small that is still useful, frequently JSON will have string properties and stuff that will bump your average up
Paul R.
With a 3G Android device, can I not set the heap to, say, 1G?
Mark M.
so, if you really are loading 2 million model objects into memory simultaneously, IMHO slow speed is the least of your worries -- the OutOfMemoryErrors would be somewhat more catastrophic
no
unless you build your own custom ROM
or root the device, perhaps
Paul R.
I was getting OOM errors until I used the "useLargeHeap" attribute.
Mark M.
there is no guarantee of how large that "large heap" will be
Paul R.
Then it garbage collected like crazy on the N6.
Mark M.
it is probably trying to free up memory from past JSON parsing steps or something
Paul R.
So what would you do to make these ~2M records accessible fast and easy?
Mark M.
eliminate 99% of them
7:35 PM
Mark M.
I mean, seriously, downloading and parsing 100+MB is not going to be pleasant
and so I'd start with reconsidering why you are downloading and parsing 100+MB of JSON data
Paul R.
These are records that back narrowing choices, like movie names in my app. Can't be eliminated.
Mark M.
but, why download and parse JSON? why not package this data in your app as a SQLite database?
Paul R.
I hate databases. :-)
Especially SQL ones.
You've got me thinking. I might load the strings and defer parsing.
They are small, always < 100 characters
Mark M.
OK, if you're not putting the data into SQLite... then what *are* you doing with the data? please tell me you are not re-parsing the JSON on every app run
7:40 PM
Paul R.
If I could get the re-parsing down to < 2s on every app run (which are infrequent) I would accept that.
Mark M.
neither the network nor on-board flash is likely to be fast enough to sustain what you want
Paul R.
But yes, cacheing the data into a db is viable.
The data changes once per day at the source site, fwiw.
Eric
has entered the room
Mark M.
how big is your intended user base?
(BTW, hello, Eric -- I will be with you shortly!)
Eric
hey
Paul R.
Could be large.
I certainly want it to be large.
Mark M.
downloading 100+MB daily is going to make you unpopular with people on metered data plans
and I have difficulty believing that the entire dataset is being changed daily
I mean, you could rewrite half your app in C/C++, so that your JSON is only ever touched by native code, as you eliminate the heap limits... but I think you have far more profound data management issues than the speed of the JSON parsing
Paul R.
It's an upscale user base. Not for billions of users. Such a problem to have.
7:45 PM
Paul R.
Are these profound issues speed or space or both?
Mark M.
bandwidth and speed, IMHO
I mean, you're talking terabytes a month of bandwidth charges if your user base gets appreciable
at ~3GB/month per user
well, actually, I'm not taking GZip into account, which I assume you have enabled for your Web service and HTTPS client
so, the bandwidth hopefully won't be that bad
but, still, the thought of downloading and parsing that much JSON daily makes me cringe
Paul R.
Interestingly enough, with Kotlin coroutines, the delta between reading in the data from a file or from the next is negligible.
(reading and parsing)
next -> net
Mark M.
that will depend a lot on the network connection
Paul R.
Yes, mine is fast (1G)
Mark M.
anyway, let me take a question from Eric, and I will swing back to you in a bit
Eric: your turn! do you have a question?
Paul R.
That's fair.
Eric
I have an activity with a framelayout that acts as a container for dynamically added fragments. One such fragment has swipeable tabs, so it contains 2 fragments itself. When a menuItem is clicked, I want to add or remove these inner fragments. I am using the childFragmentManager to do so and get an error complaining "can't change container ID of <inner fragment>". Since these inner fragments were added with a FragmentPagerAdapter I didn't use the childFragmentManager directly to add them.
Mark M.
FragmentPagerAdapter has always sucked at dealing with trying to add/remove/replace pages
7:50 PM
Mark M.
that's why I wrote ArrayPagerAdapter back in the day
you may need to roll your own PagerAdapter that can handle your needs
Eric
yeah I created a custom FragmentPagerAdapter
Mark M.
OK, well, that adapter needs to be using the childFragmentManager, if it will manage fragments that are inside another fragment
beyond that, based on the error, it seems like your FragmentTransaction has some container issues
Eric
yes it is using that
am I able to use the same framelayout container?
Mark M.
I thought you were changing a page in the ViewPager
Eric
no
Mark M.
"When a menuItem is clicked, I want to add or remove these inner fragments" -- what are the inner fragments?
I thought those were the ones referred to as "2 fragments itself" in the preceding sentence
Eric
when I click on a menuItem in the toolbar, I want to go from showing 2 tabs to one of the fragments in the tab (I want to replace the parent fragment with the child fragment)
7:55 PM
Eric
the parent fragment is the tab fragment
the child fragment is one of two in the parent tab fragment
Mark M.
"I want to replace the parent fragment with the child fragment" -- you would need to completely remove the child fragment before adding it to a new container, I think
I have never tried what you are attempting (move a nested fragment out to be a top-level fragment), but once a fragment is managed, AFAIK you need to unmanage it before you can switch containers
Eric
am I able to use the framelayout that is currently occupied by my parent fragment? This container is in an activity. It holds a tab fragment. The tab fragment has child fragments. So I want to replace the tab fragment with its child. Do you understand
Mark M.
in theory, what you want can work -- it is mostly a question of what fragments you need to remove along the way
I would start by removing *everything* -- remove the child fragments from the tab fragment, remove the tab fragment from the FrameLayout
then add the desired fragment to the FrameLayout
and see if that runs
Eric
the stacktrace seems to indicate I can't use the same container
8:00 PM
Mark M.
from the error message you cited, my assumption is that the fragment is already *in* a container
Eric
"can't change the container id of the child fragment"
Mark M.
and you need to remove it from that container before putting into another container
Eric
hmm alright
Mark M.
it's entirely possible that there is something about nested fragments that prevents this sort of reuse, and you will wind up needing to create a new instance of the fragment
that would be the fallback plan
Eric
wait but container is it currently in?
Mark M.
the container represented by the tab fragment
Eric
the nested fragment is part of tabs, which does not explictly have a container, no?
ah
Mark M.
ViewPager is a container (subclass of FrameLayout IIRC)
Eric
how do i remove it from the container, then?
I don;t know how to acccess this special container?
Mark M.
you remove it from the PagerAdapter, I think
somewhere, your custom PagerAdapter should be committing FragmentTransactions for adding and removing the fragments
ViewPager itself knows nothing about fragments -- it works in terms of Views
let me take another question from Paul, and I will switch back to you in a little bit
Paul: your turn! do you have another question?
8:05 PM
Eric
ok
8:05 PM
Paul R.
yes
I have a Kotlin object that has an init block. I would like to "inject" a parameter into this init block for testing. First, is my scenario clear and second, do you have a solution?
Mark M.
init blocks don't get parameters, only constructors do
Paul R.
object as in singleton
Mark M.
are you using a dependency injection framework?
Paul R.
Can the block reference a companion variable?
Mark M.
probably, though I haven't tried it
Paul R.
Me either, at least not yet.
Mark M.
companion objects are roughly analogous to Java statics, so I would think it would work
but if you're not using dependency injection, that may be a better answer anyway
personally, I've been using Koin for Kotlin projects
Paul R.
I'll play with that idea. Any other thoughts?
Mark M.
you could have some sort of secondary constructor that is used in testing
(I am assuming that you cannot provide this parameter via the regular constructor for some reason)
8:10 PM
Paul R.
Would "secondary constructor kotlin" be a good search expression for Google, do you think?
Mark M.
I cover it in "Elements of Kotlin", but yes, that should work from a search expression standpoint
having full-text search of my books is handy on occasion :-)
Paul R.
Ah, you are imaging an factory to create the object. No?
an -> a
Mark M.
I was assuming that your test was creating the object
Paul R.
Not till now. :-)
Mark M.
if this object is several layers removed from the test code... definitely look into Koin or other dependency injection, as that is precisely the problem that they were created to solve
I'll be covering Koin some in *Elements of Android Jetpack* and *Exploring Android*, though my pace is slow at the moment
BTW, the official docs for secondary constructors are part of https://kotlinlang.org/docs/reference/classes.html
Paul R.
I'll take a look at Koin and ping you later if need be.
Mark M.
I am eminently pingable
except, not literally, due to my firewall configuration
8:15 PM
Mark M.
anyway, let me take another question from Eric, and I'll return to you if there is time
Eric: back to you! do you have another question?
Paul R.
A quick look tells me that is promising.
I'm all set now. Thanks.
Mark M.
you're welcome!
Paul R.
has left the room
Eric
yea it has a problem removing the inner fragment and gives the same error
Mark M.
what is "it"? the PagerAdapter?
Eric
childFragmentManager
childFM.beginTransaction().remove(adapter.getItem(position)).commit()
Mark M.
is the PagerAdapter using the childFragmentManager?
Eric
yes
Mark M.
then I cannot explain the error
Eric
it has to because the fragments inside the tablayout are nested
Mark M.
agreed
Eric
ok
Mark M.
"can't change the container id of the child fragment" simply does not make sense for a remove() operation
are you also removing the fragment from the PagerAdapter? perhaps it is trying to re-add it as a page
Eric
no
8:20 PM
Mark M.
you will need to do that, as you do not want the PagerAdapter to be working with this fragment anymore
and the PagerAdapter should be doing the remove() as part of that work
Eric
ok ill add a method to it that removes the fragment from the list
goodnight
Mark M.
have a pleasant evening!
Eric
has left the room
8:25 PM
Mark M.
turned off guest access

Tuesday, April 2

 

Office Hours

People in this transcript

  • Eric
  • Mark Murphy
  • Paul Reilly