Office Hours — Today, October 11

Tuesday, October 9

Oct 11
7:25 PM
Mark M.
has entered the room
Mark M.
turned on guest access
7:45 PM
Aaron
has entered the room
Mark M.
hello, Aaron!
how can I help you today?
Aaron
hey Mark, I hope you are having a pleasant week. today I have one question about how to improve a certain piece of my app (with code, this time), another question about a specific bug, and maybe 1-2 more general questions if there is time
Mark M.
OK
Aaron
I'll go one at a time, the first one is a little lengthy but hopefully the explanation is helpful:
View paste (4 more lines)
PostsFragment contains a RecyclerView which is fed by PostsAdapter. I have a Room database that keeps the IDs of posts in the RV that have been clicked already, so they can be strikethrough formatted. 

This is currently being accomplished by PostsFragment observing the database and setting the list of clicked IDs inside of PostsAdapter, which looks at the array of IDs and applies the strikethrough to the appropriate RV rows in onBindViewHolder. 

Problem is, I currently have to do some clumsy workarounds to make it all work right. Namely, I am calling notifyDataSetChanged on PostsAdapter, from PostsFragment, every time the LiveData feeding the RecyclerView is updated - because the RV gets populated before the Room database observer receives its list of clicked posts. So if I don't redraw the RV this way, nothing is struck through when the app is first opened. 

This is a lot of redundant RV drawing, and also, my understanding is that it's not really normal to call notifyDataSetChanged from outside the adapter, but I'm not sure how else to set it up since my observers are in PostsFragment and I rely on them to time everything. 

I'm thinking this is a case when RxJava would help, b
...
Mark M.
this will take a moment
Aaron
take your time
7:50 PM
Mark M.
postsLiveData is the source of the actual posts for the adapter?
Aaron
correct
Mark M.
and your concern is the // TODO commented area in PostsFragment?
View paste
//TODO: what is a more efficient way to do this?
                //ensure that strikethroughs are performed when postsLiveData is loaded w/ data
Aaron
yes, but more broadly, I just suspect the overall way in which I am applying the strikethrough formatting is too convoluted
7:55 PM
Aaron
I think that call to notifyDataSetChanged is probably the worst part of it, but I think it's probalby not the only issue
Mark M.
IMHO, your problem lies elsewhere, but you are seeing the pain here
Aaron
very possible
that is actually the kind of answer I am looking for, so please feel free to elaborate
Mark M.
hang on
Aaron
np
Mark M.
you have divided your repository along data source lines
well, no, actually that's not really true: you just have NoSurfRepository, right?
Aaron
yes, I just have that repository, and the only state that I really keep are the IDs of clicked posts. I don't store or cache any of the content from Reddit
Mark M.
right
I would argue that it is the repository's job to stitch together the data from the disparate data sources
your fragment and adapter should be getting an idealized object model, with the data needed, in a structure that makes it easy to render that data
8:00 PM
Mark M.
all the hard stuff goes in the repository
so, when you ask the repository to give you posts, the post objects that it supplies should have a field that indicates whether they were read or not
Aaron
that makes sense
Mark M.
your PostsAdapter should wind up be *much* simpler
er, being much simpler
in the repository, you will still have two separate reactive sources: Retrofit and Room
Aaron
yes that makes a lot of sense
great, OK
Mark M.
that's where your RxJava idea comes into play
as RxJava provides a much richer "library" of ways to assemble multiple reactive sources into a single outbound stream
LiveData, by contrast, offers nothing in that area
this is why I expect that most developers will use RxJava in their repository, converting them to LiveData for UI use, so the reactive results become lifecycle-aware
Aaron
yes, I am trying to think through how I might do it, but I am having a little trouble thinking it through in a concrete enough way without actually working with code
any suggestions about how I can approach it without RxJava for now? I mean, I guess I could take this opportunity to start learning it
but I am trying to proceed incrementally with learning and upgrading how I am doing different things
8:05 PM
Mark M.
sorry, this is slow, as I don't know your code that well
so, you are using traditional callbacks with Retrofit, and using those to populate a MutableLiveData, right?
Aaron
correct
technically there are 2 similar MutableLiveDatas
Mark M.
when you call methods like requestAllSubredditsListing() on your repository, are those calls being made on the main application thread?
(with you relying on Retrofit for handling the background thread?)
Aaron
yes
Mark M.
OK
first, I think there is a LiveData adapter for Retrofit, if you wanted to get rid of the callback + MutableLiveData part
Aaron
ok, interesting
Mark M.
basically, instead of your RetrofitInterface having methods that return Call<Whatever>, they would return LiveData<Whatever>
Aaron
right
Mark M.
you register it similarly to how you register your Gson adapter
there is definitely an RxJava adapter for Retrofit, and I'm reasonably certain somebody has created a LiveData one
8:10 PM
Mark M.
regardless, one way or another, you have a LiveData of Retrofit results, and a LiveData of Room results
Aaron
yes
Mark M.
what you want is to stitch those together and have a LiveData of the combined results, with posts knowing whether they have been read or not
IIRC, we talked about MediatorLiveData in a recent chat
Aaron
yeah
Mark M.
and I said that one place where that gets used is in transformations
Transformations.map() and Transformations.switchMap() both use a MediatorLiveData (again, IIRC)
and in "Android's Architecture Components", I show how to write a filter() transformation much the same way
Aaron
(yes, I remember, and I actually implemented some Transformations in my ViewModel to create a viewstate as you mentioned, which helped me move a lot of logic out of my fragments)
ok, I've skimmed the piece about the filter, yes
Mark M.
yeah, I thought I saw something like that when I skimmed your code
your stitch-the-data-together situation is basically another place for a transformation
the function takes in the two LiveData objects and returns a LiveData representing the combined result
in RxJava, this transformation function is called zip()
you could create your own LiveData zip() equivalent
Aaron
ok, cool, that gives me a great starting point
Mark M.
it might be a bit tricky, but at the same time, somebody might have written up how to do it, given that it is a standard RxJava "operator" that somebody might have applied to LiveData
8:15 PM
Mark M.
BTW, here is the Retrofit LiveData adapter: https://github.com/leonardoxh/livedata-call-ada...
Aaron
are you saying that the filter() transofmration shares some similarities with what you are suggesting re: zip(), or are you just mentioning filter() insofar as it's an example of a custom transformation more generally?
Mark M.
it's an example of a custom transformation
Aaron
ok
Mark M.
this GitHub issue points to a couple of gists with zip() implementations for LiveData, though I think they are in Kotlin
Aaron
ok, cool, and thanks for the links
by all means, post anything else if you are typing it, but let me also ask my second question before time runs out
Mark M.
go right ahead!
Aaron
for this one I need some advice about where/how to debug
I am using the AppCompat night mode
as an option in my settings
it seems to work fine and as expected except for one case
when I go BACK from a WebView and return to PostsFragment, some of the text and other resources are wrong. take a look at this screenshot
as you can see, the text and refresh button are the wrong color
8:20 PM
Aaron
I am not sure why this is happening and TBH I am not sure how to start figuring it out
any suggestions?
Mark M.
well, I haven't looked at all at AppCompat's night mode support
what is the basic implementation: separate themes?
IOW, how are you telling AppCompat what you want in night mode versus, um, non-night mode?
Aaron
versioned resources with a -night suffix
which seem to work fine in general... except after a WebView is displayed
Mark M.
OK, that's standard night mode
if I had to guess, it's a bug somewhere in AppCompat
see if you can reproduce it in a simple project
and then see if you can reproduce it when using the latest-and-greatest appcompat version (if you're not on the latest already)
Aaron
that is what I was afraid of. if that turns out to be the case, what is a good alternative way to implement night mode?
Mark M.
if you can reproduce the problem, consider filing a bug report with the sample project
um, frankly, there isn't a good alternative way to implement night mode
there are two possibilities that I see:
1. AppCompat knows that it should be in night mode but is misapplying the resources somehow
2. AppCompat does not know that it should be in night mode
-night resources, though, are a system thing, not an AppCompat thing
8:25 PM
Aaron
I see
Mark M.
which means unless Google did something really strange, option #2 should not be possible
I cannot rule out Google doing something really strange
they do that on days whose names end in "y"
Aaron
=>
Mark M.
BTW, how are you testing this? hardware or an emulator?
Aaron
both
same problem on both
Mark M.
OK, that eliminates environment as a source of problems
Aaron
I think I just need to do some heavy duty reading about themes/resources
Mark M.
my limited night mode experience means that I don't really have great answers for you
possibly, though I doubt it
insofar as problems there should be consistent
IOW, they would be broken all of the time, not just on specific forms of navigation
I assume that this is going from PostsFragment to some display fragment with a WebView?
Aaron
NoSurfWebViewFragment
Mark M.
so, from PostsFragment to NoSurfWebViewFragment?
Aaron
sorry, PostsFragment->PostFragment->NoSurfWebViewFragment
8:30 PM
Aaron
list of reddit posts -> one reddit post -> external link associated with that post
Mark M.
those screenshots look like they would be from PostsFragment (lists), not PostFragment
Aaron
sorry, yes, they are. what I mean is ,the navigation flow works as above ^
but yes, the problem happens in PostsFragment, after BACK is pressed on PostFragment
Mark M.
is PostFragment also exhibiting the problem?
Aaron
no
Mark M.
does your overflow menu in PostsFragment lead to other fragments?
Aaron
I do not want to keep you past the normal time; I appreciate your help but I can poke around more and return later
um, yes, I think so
yes
Mark M.
see if navigation through those paths exhibit the same probelm
er, problem
Aaron
what would that indicate?
Mark M.
basically, you're assuming that the WebView is part of the problem, which may be the case, or it may not
Aaron
ok I got you
I will try that line of investigation
thanks a lot!
Mark M.
another test would be to temporarily wire PostFragment to not launch NoSurfWebViewFragment, but instead show something else (e.g., settings)
and see if the problem occurs that way
Aaron
ok, I will see if I can rule WebView in or out as being part of the problem
Mark M.
your WebView-is-the-culprit theory may be true, but it's worth considering alternatives
right
Aaron
agreed
Mark M.
regardless, if you do come up with a reproducible scenario and file a bug report, support libraries are relatively decent about getting bug fixes
8:35 PM
Mark M.
so, the "how do I get night mode working?" might be a matter of just waiting for a bug fix
and with that, let's call it a wrap for today
Aaron
ok, much appreciated
talk later
Mark M.
next chat is Saturday at 4pm US Eastern
have a pleasant evening!
Aaron
sounds good, you too
Aaron
has left the room
Mark M.
turned off guest access

Tuesday, October 9

 

Office Hours

People in this transcript

  • Aaron
  • Mark Murphy

Files in this transcript