Office Hours — Today, August 25

Thursday, August 23

Aug 25
3:55 PM
Mark M.
has entered the room
Mark M.
turned on guest access
4:00 PM
Mathias
has entered the room
Mathias
Hey man
Mark M.
hello, Mathias!
how can I help you today?
Mathias
I just wanted to pop in and give you an update on my geofencing issues...
Mark M.
OK
Mathias
As you might recall I was a victim to the background restrictions in Oreo. Previously I had a broadcastreveiver that called a service, but now I got the "background not allowed"
Mark M.
right
Mathias
I tried lots of different stuff, nothing worked. Interesting thing - the "offiicial" geofencing guide that still is up and was updated in may uses IntentService, but that does not work. if you take their code and run it, it doesn't work...
Mark M.
the docs are not always kept up to date
Mathias
In the end, I managed to get one thing working, which is changing my pendingintent from implicit to explicit
Mark M.
oh, you were using an implicit broadcast?
Mathias
View paste
Intent intent = new Intent(session, GeofenceTriggerReceiver.class);
        final PendingIntent proximityIntent = PendingIntent.getBroadcast(session.getApplicationContext(), 0, intent, PendingIntent.FLAG_NO_CREATE);
yeah
Mark M.
ah, yeah, that's definitely not going to work on Android 8.0+
Mathias
but this way got the broadcastreceiver to be called again
:)
Mark M.
right
4:05 PM
Mark M.
Implicit
let's try that again...
Implicit
Mathias
so anyway, I now had 2 new problems - I do 2 different async operations - 1. get a location from the locationclient and 2. call my server with a task
Mark M.
Mathias
haha
Mark M.
sorry, just wanted to drop in the link to my writeup of the implicit broadcast ban
Mathias
I solved the location client by not getting a fix. the geofencingevent has a location in the later versions of google play so I just use that and fail if there is no location
yeah I read it thanks! :)
Mark M.
I haven't used the geofencing APIs, but it certainly seems reasonable that they'd tell you where the device was when you entered a fenced area
Mathias
exactly
I tried to fix my network call by doing it synchronously. that didn't work, because now I got "Networkonmainthreadexception"...
so, I found something I've never seen before "goAsync()"
well that gives me 10 seconds for my task, so I guess I'll have to hope that most users have good enough network to make my rest call within 10 secs...
Mark M.
yeah, the docs on that are kinda hazy, which is why I usually delegate that sort of work to an IntentService (now JobIntentService (and eventually WorkManager))
Mathias
to sum up: I do everything in broadcast receiver by making It explicit, and call goAsync so that I can fire off an async task to send stuff to my server
I gotta say, Android is driving me crazy lately
Mark M.
welcome to my world
but, I'm glad you have things under control
Mathias
there are 200 ways to do everything, google changes everything every 2 weeks but never update anything, there are 1000 threads on SO for everything, for every version of a solution that doesn't work anymore, and most of all - google SUCKS at documentation. Their api docs and examples are woeful
4:10 PM
Mathias
had to get that off my chest. glad I have you and your stuff!
Mark M.
happy to be useful!
Mathias
Aaaanyway, just wanted to give you an update since you don't use geofences so much. Now off to a glass of wine and some World of Warcraft (wife asleep) :)
Mark M.
have a pleasant evening!
Mathias
you too mate
Mathias
has left the room
4:15 PM
Aaron
has entered the room
Mark M.
hello, Aaron!
how can I help you today?
Aaron
hey again Mark. Today I have 3 questions specific to code I'm working on, and one unrelated question. Here is the code in question, I will paste the questions in a moment
4:20 PM
Aaron
View paste (6 more lines)
To briefly explain the structure of my app, as context for my questions:

MainActivity adds a ViewPagerFragment which contains a TabLayout and a ViewPager. This ViewPager sets a FragmentPagerAdapter that hosts two content fragments (AllPostsFragment and HomePostsFragment, but only the former is relevant right now). AllPostsFragment contains a RecyclerView and observes a LiveData in the ViewModel, in order to set PostsAdapter with the latest data for the RecyclerView. The LiveData in the ViewModel that AllPostsFragment observes, mirrors via switchMap a LiveData exposed by the Repository. It contains the deserialized JSON data for Reddit's front page... basically 25 content links and associated data. It's being fetched by Retrofit w/ Gson adapter.

1. First question is about the onItemClick callback in MainActivity. It's called by PostsAdapter whenever a row in the RecyclerView is clicked. What I want it to do is display a fragment (HelloWorldFragment for testing purposes...eventually it will be a detail view for the RecyclerView items). When I call getSupportFragmentManager on the activity as in line 46, everything works as expected. HelloWorldFragment appears and covers the screen.
...
Mark M.
OK, give me a bit to digest that
Aaron
sure thing, I hope it is manageable, let me know if you need any clarification
Mark M.
regarding #1, among other things, FragmentPagerAdapter isn't going to support what you're trying to do
you can't replace pages with FragmentPagerAdapter or FragmentStatePagerAdapter especially well
and near as I can tell, that's what you're trying to do
4:25 PM
Mark M.
if instead you are trying to replace a ViewPager with a fragment, that doesn't work, because a ViewPager is a View, and you cannot replace a View with a fragment
regarding #2, put currentListing.getData().getChildren().get(i).getData() in onBindViewHolder(), so you stop repeating those lines of code, as they are the same
whether you then create dedicated methods to retrieve individual values, or you just call getScore(), etc. directly in onBindViewHolder(), is up to you
you will tend to see more developers actually putting the binding smarts on the RecyclerView.ViewHolder subclass itself, so the RecyclerView.Adapter just tells the viewholder to bind a model object supplied by the adapter
4:30 PM
Mark M.
regarding #3, Picasso has some diagnostic options that you can opt into: https://stackoverflow.com/q/23565943/115145
Aaron
(ok I am digesting answers while you continue to type)
Mark M.
and for #4, I have no idea, as I have never called that method
I'm not completely confident in my answer to #1, as your question (and the code) is a bit confusing, as I'm coming it it fairly cold
the other three I feel better about :-)
Aaron
OK, no worries
For #1 I think that gives me enough to start a new line of inquiry, so I will do that and hopefully figure things out, if not, I'll ask a revised question another day
Mark M.
basically, you need to replace a fragment with a fragment
and since you can't really replace a fragment that is a page of the ViewPager very well, the only easy solution is to replace the whole ViewPager
4:35 PM
Mark M.
if you really want to replace the contents of a page in the ViewPager, do just that: replace the page's contents, not the page itself
Aaron
Practically speaking I'm just going to go with using the top-level fragment manager... the childFragmentManager stuff is just experimentation to try to figure out how it works
OK let me be more specific about what I am doing
my fragment_view_pager.xml is this:
View paste (4 more lines)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/view_pager_fragment_base_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".fragments.ViewPagerFragment">

    <android.support.design.widget.TabLayout
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
...
And calling this:
.replace(R.id.view_pager_fragment_base_view, HelloWorldFragment.newInstance("abc", "def"))
shouldn't that insert my HelloWorldFragment in the container that encloses ViewPager, and replace it?
Mark M.
no
at best, that might add a third thing to the LinearLayout, where that "thing" is the view hierarchy from HelloWorldFragment
you can't replace a non-fragment with a fragment
and, even if you could, which of the two things in that layout would you expect to get replaced? the TabLayout or the ViewPager? replacement is a 1:1 thing
Aaron
ok, I see, it's not clicking for me at this precise moment, still conflating something but that should be plenty to figure it out
4:40 PM
Aaron
I may have one more follow up to #2, one sec
Mark M.
if this were a FrameLayout, and you had placed a fragment in it previously, you could replace() that fragment with a different one
Aaron
OK I think I get it. will just have to check understanding after chat
about question #2
Mark M.
see pretty much any of my book examples involving RecyclerView, particularly the ones that have more than just strings for rows
4:45 PM
Aaron
OK :) the only remaining question is, you provided good guidance on how to improve the efficiency of what I'm doing now - but what about the possibility of exposing a LiveData from the ViewModel for each variable I want to pull out of the data object? Is that a pattern that anyone uses, or would that be bizarre?
Mark M.
that seems overly complex IMHO
Aaron
OK. Great, this will all get me on the right track
that's all I've got for you - appreciate it as always
have a good weekend!
Mark M.
you too!
Aaron
has left the room
Aaron
has entered the room
Mark M.
hello again!
Aaron
let me poke back in :D
4:50 PM
Aaron
I don't need a comprehensive code review or anything - but you mentioned some of the code was confusing - anything that particularly stood out, I would be happy to hear about, so I can work on improving it
I'm sure that is a very deep question
But anything you can offer would be helpful
Mark M.
well, mostly, it's just the volume -- I can absorb code only so quickly
depending on how the code is set up, that may be easier or more difficult
Aaron
oh, OK, I got you. I thought you meant you had noticed something particularly confusing about what I had there
Mark M.
well, for the next 8 minutes, here is some random feedback, based in part on my currently open tabs on your code:
getItemCount() in your PostsAdapter seems strange -- the rest of your code looks at getChildren(), and this does not, raising the possibility of crashes if those two things are not in sync
Aaron
good point
Mark M.
typically, the RecyclerView.Adapter itself is responsible for calling notifyDataSetChanged(), rather than having outside parties call that, so I'd move that call into setCurrentListing()
4:55 PM
Mark M.
FWIW, I never see Objects.requireNonNull() used in production code
more accurately, I have never seen it period prior to just now
usually, you want to handle null values more gracefully than blowing up :-)
Aaron
yeah the IDE had recommended that at some point, I need to go back and figure out how to correctly address what it was alerting me to
Mark M.
really? I haven't seen that quick-fix suggestion before -- perhaps they added it
viewModel.initApp() is a problem, as that will get called on every configuration change the way that you have things set up
Aaron
yeah, but it was a few weeks ago, I don't recall the details, I just accepted it at the time and have delayed returning to it
yeah I'm not handling configuration changes really at all right now. on my list
Mark M.
well, you're closer than a lot of developers, just by using ViewModel and LiveData
anyway, those are some basic thoughts
5:00 PM
Aaron
I'm hoping to get this app into decent shape, hopefully I can stand out among other applicants. getting a full-time job as soon as possible is the goal
Awesome, very helpful
til next time
Mark M.
the next chat is Tuesday at 9am US Eastern
have a pleasant day!
Aaron
you too
Aaron
has left the room
Mark M.
turned off guest access

Thursday, August 23

 

Office Hours

People in this transcript

  • Aaron
  • Mark Murphy
  • Mathias