Office Hours — Today, October 25

Tuesday, October 23

Mark M.
has entered the room
Oct 25
7:25 PM
Mark M.
turned on guest access
Ron T.
has entered the room
Mark M.
hello, Ron!
how can I help you today?
Ron T.
View paste (7 more lines)

We were wondering if you had any additional knowledge regarding the Android announcement for the new 'targetSDKVersion' compliance 

specification for both new and existing apps?

We've read a lot of Android documentation and postings and we are confused about the 'existing' apps requirement which takes effect Nov 1. 

Namely,

1. Do all of our existing PLAY apps need to comply with the 'targetSDKVersion' specification by Nov 1? 

or

2. Do existing PLAY apps need to comply with the 'tagetSDKVersion' specification only if and when an updated APK is submitted to PLAY after 

...
Mark M.
my impression is that #2 is the scenario: you're not banned, but you cannot update without complying with the targetSdkVersion requirement
and so, AFAIK, with respect to "Will our existing APKs of these apps currently in PLAY continue to be available for download/install after Nov 1?", the answer is "yes"
7:30 PM
Mark M.
that being said, IANAGNDIPOOTV (I am not a Googler, nor do I play one on TV)
I have no special insights, insider knowledge, etc.
Ron T.
Great! That is all I needed for tonight. Many thanks, over and out
Mark M.
OK!
Ron T.
has left the room
7:35 PM
Lucy
has entered the room
Mark M.
hello, Lucy!
how can I help you today?
Lucy
Hi Mark, I just logged in to ask a question and realized I might know the answer. I will tell you what it was anyway....
When a notification comes in I am using the flags "Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP" when I start the activity in order to have only one at a time.
7:40 PM
Aaron
has entered the room
Lucy
That is, when a notification comes in I start an activity and I want that to be the only activity running in the app after tapping it open.
Mark M.
you mean, the only activity in the task
(BTW, hello Aaron -- I will be with you shortly!)
Lucy
Oh, yes the only activity in the task.
Aaron
hello, thanks
Lucy
I just tried it and it seems to be working as expected. I was thinking there could be something special about activities launched from tapping a notification but maybe not after all.
Mark M.
I wouldn't say that activities started via a PendingIntent are "special"
they are different than an activity calling startActivity(), in that then we already know a task to work with (the activity's own task), whereas we do not with a PendingIntent
and so some behavior that we take for granted with activities, like each going into the same task, do not necessarily hold in the PendingIntent scenario
Lucy
I see. This is excellent insight for me. I will do some testing to make sure how many activities I have running after opening a few notifications.
Thanks Mark!
Mark M.
you're welcome!
7:45 PM
Mark M.
let me take a question from Aaron, and I'll turn back to you in a bit
Aaron: your turn! do you have a question?
Lucy
Sure, I'm all set for now. "See" you soon. :-)
Lucy
has left the room
Aaron
yes, a few, here they are:
View paste
* I transferred some layout code from layout XML files into my styles.xml, and I found that for ConstraintLayout attributes, I actually had to remove the app: prefix. For example, `<item name="layout_constraintTop_toBottomOf">`. It's not optional, either, as including `app:` breaks it. This is not the case with `android:` attributes. I still have to include those (as expected). Why does `app:` have to be specifically excluded?

* In my app, I set up the same StrictMode policies you are using in EmPubLite, and I noticed that I get a red flash when writing to SharedPreferences, even though I am using the asynchronous apply() method. Shouldn't this NOT trigger a violation? Is this one of the bugs you mention in your book?

* Why did Google design fragments to only take no-arg constructors? What is gained by requiring use of a static factory method instead? 

* I'm currently learning dependency injection. Finding a limited amount of discussion on what components should/shouldn't be injected. In particular I'm wondering about fragments, as it seems like no one injects them (it seems common to inject things into fragments, but not to inject the fragments themselves). Not sure why not. Wh
...
Mark M.
regarding your first bullet, the biggest thing is: putting layout_ attributes in a style is not particularly recommended
Aaron
I see
Mark M.
it works AFAIK, but that's not usually the sort of thing that styles get used for
in terms of the naming system, ¯\_(ツ)_/¯
regarding your second bullet, apply() should not trigger a StrictMode violation -- check LogCat to see what is getting logged (assuming that you also have penaltyLog())
note that the first time that you reference a SharedPreferences in your process, the XML for the saved preferences has to get read, and that *will* trigger a StrictMode violation if done on the main application thread
(and there is no built-in apply() equivalent to address that)
regarding your third bullet, fragments, like activities, services, and a variety of other things, get created using reflection
and they get created automatically, by code that is not yours
in the case of fragments, that occurs on configuration changes, for non-retained fragments
code that is not yours has no good way of knowing how to invoke an arbitrary constructor
7:50 PM
Mark M.
the typical workaround for that is to have some sort of "factory" that creates those objects, so you have more constructor flexibility
Java has a reputation for factories -- a running joke is needing a SomethingFactoryFactoryFactory to get the SomethingFactoryFactory to get the SomethingFactory to make you a Something
so, they probably went the reflection-based zero-argument constructor approach to avoid factories
regarding your last bullet, DI tends to get used for things that you will want to mock in testing
you rarely need to mock a fragment
and, as I covered in the third bullet, Android recreates fragments automatically in some scenarios, which might confuse a DI system
but, for example, repositories are very likely to get injected, for apps that use DI
because for isolated GUI testing, you can easily set up the DI to replace the real repository with a controllable mock, and isolate you from the server that the repository hits
so... what of all that needs clarification? :-)
7:55 PM
Aaron
regarding the styles, do you say "not usually the sort of thing" because styles are intended to be reused on multiple elements and adding layout constraints to specific elements pretty much limits it to being used on a single element?
Mark M.
that's one strong reason, yes
Aaron
what else?
Mark M.
styles are mostly for look-and-feel
positioning isn't really part of that
plus, particularly with ConstraintLayout and RelativeLayout, your layout rules often need to identify particular widget IDs
that's not very reusable, may screw up refactoring, etc.
Aaron
I see, I did this mainly to clear out my XML layout files when I was implementing data binding, so that I could focus on that, but I get your point
Mark M.
moving stuff into styles is fine, just not those sorts of positioning attributes
but, yes, layout files can get wordy
Aaron
got it
8:00 PM
Aaron
about StrictMode, I looked at the logs and I'm just getting android.os.StrictMode$StrictModeDiskReadViolation, so it sounds like that's expected. the flash occurs when I change a setting on my preferences screen, so I guess there is just a read taking place right before the write?
but the violation is not actually due to the write
Mark M.
the stack trace should point out where specifically the violation is occuring
can you post the stack trace here?
Aaron
View paste (32 more lines)
2018-10-24 23:05:14.846 5480-5480/? D/StrictMode: StrictMode policy violation; ~duration=589 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=1114175 violation=2
        at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1440)
        at java.io.UnixFileSystem.checkAccess(UnixFileSystem.java:251)
        at java.io.File.exists(File.java:807)
        at android.app.ContextImpl.ensurePrivateDirExists(ContextImpl.java:572)
        at android.app.ContextImpl.ensurePrivateDirExists(ContextImpl.java:563)
        at android.app.ContextImpl.getPreferencesDir(ContextImpl.java:519)
        at android.app.ContextImpl.getSharedPreferencesPath(ContextImpl.java:714)
        at android.app.ContextImpl.getSharedPreferences(ContextImpl.java:368)
        at android.content.ContextWrapper.getSharedPreferences(ContextWrapper.java:167)
        at android.preference.PreferenceManager.setDefaultValues(PreferenceManager.java:643)
        at android.preference.PreferenceManager.setDefaultValues(PreferenceManager.java:609)
        at com.aaronhalbert.nosurfforreddit.activities.MainActivity.onCreate(MainActivity.java:71)
        at android.app.Activity.performCreate(
...
Mark M.
it is coming from your setDefaultValues() call in onCreate() of your MainActivity
Aaron
there are two violations, I think because I have two SharedPrefs, the default, as well as a second prefs file for holding an oAuth token
ah
Mark M.
under the covers, that will need to read the XML, and hence you get the violation
Aaron
should I do that in an ASyncTask, or something?
Mark M.
well, that depends on your definition of "should" :-)
in an ideal world, yes, you would move the SharedPreferences stuff to a background thread of one form or another
however, unless you are storing two tons of stuff in your SharedPreferences, this I/O will not be very expensive
and so it is reasonably common for this sort of violation to get ignored
particularly for app startup
8:05 PM
Mark M.
now, if you were hitting the Reddit Web service API on the main application thread, you would deserve to be slapped with a trout
which is why Android has StrictMode configured out of the box for NetworkOnMainThreadException
Aaron
ok got it. yes, I don't recall seeing anything in your book or the official documentation about doing reads off the main thread
Mark M.
all disk I/O should be done on background threads
I don't distinguish between read and writes on this topic much in the book
Aaron
I definitely deserve to be hit with a trout, but not for that particular reason
OK, I see
Mark M.
SharedPreferences specifically is a bit odd, in that it offers an asynchronous API for writing but not for reading
but, then again, SharedPreferences is a bit odd in a variety of ways
almost anything from API Level 1 would be considered a bit odd nowadays
Aaron
OK, great, it makes sense
let me see if I have anything else
8:10 PM
Aaron
OK I do have one more, this one might be extra dumb as I've not tried to think it through myself yet, but I'm going to ask anyway
regarding p.479-80 in BCG
Mark M.
OK
Aaron
that findFragmentById check is a pattern you use frequently in the book
8:15 PM
Mark M.
you mean in the code snippet at the top of 479?
Aaron
yes
correct me if I'm wrong here -
if you didn't perform that check, and you just unconditionally did the transaction, what would happen is that you would accumulate OtherFragments each time there was a config change, right?
Mark M.
yes
Aaron
OK, so
in my app, I am doing this in my MainActivity onCreate
View paste
        if (savedInstanceState == null) {
            viewModel.initApp();

            getSupportFragmentManager()
                    .beginTransaction()
                    .add(R.id.main_activity_frame_layout, ViewPagerFragment.newInstance(), TAG_VIEW_PAGER_FRAGMENT)
                    .commit();
        }
similar thing, except instead of searching for the fragment, I am checking the bundle status
it seems to produce the same outcome, i.e., preventing an accumulation of fragments
Mark M.
yes
in fact, I used to do it that way
Aaron
but I am not quite sure how it differs functionally from what you are doing
oh?
Mark M.
well, in the end, you should get the same results
from an educational standpoint, I felt that it was better to check for the fragment's existence, rather than assume its existence based on the savedInstanceState Bundle's condition
Aaron
ah, ok
Mark M.
from a practical standpoint, what you should have should work
Aaron
well that's good, because I couldn't figure out what would be different between the two, in terms of outcome
great
Mark M.
but since you are not using the Bundle in that if() block, checking whether that Bundle is null is therefore relying on side effects
8:20 PM
Mark M.
in the real world, there should be no difference
Aaron
ok great, this reminds me of one other thing I wanted to check: where does an Activity store the state of its fragments during a configuration change? in the savedInstanceState bundle, or somewhere else?
I think I asked this once before and forgot to write down the answer.
Mark M.
I was about to say...
Aaron
:X
Mark M.
this is probably a gross simplification, but basically the FragmentManager gets retained across the configuration change
Aaron
I'll find the chat transcript
that's all I've got - thanks a lot
Mark M.
you're welcome!
8:25 PM
Aaron
should have this app done(TM) soon(TM)
8:25 PM
Mark M.
hey, I always measure "soon" on geologic time scales, just for that reason
Aaron
yeah... it's been kind of frustrating because the breadth of the tools/features I'm trying to include is so wide, I'm not really getting a chance to learn anything more than superficially, but I feel that the breadth-first approach is going to be the quickest way to snag a first job in this field so I can start getting paid to learn, but we'll see if I was right about that
but this app should have pretty much everything, Retrofit, Glide, MVVM architecture, data binding, DI, some unit tests. hopefully it will stand out
Mark M.
I wish you luck with it!
Aaron
I am out, have a good one!
thanks!
8:30 PM
Mark M.
the next chat is Saturday at 4pm US Eastern
this chat's transcript will be posted to https://commonsware.com/office-hours/ shortly
have a pleasant day!
Aaron
has left the room
Mark M.
turned off guest access

Tuesday, October 23

 

Office Hours

People in this transcript

  • Aaron
  • Lucy
  • Mark Murphy
  • Ron Thomas