Office Hours — Today, September 2

Thursday, August 28

Sep 2
7:20 PM
Mark M.
has entered the room
Mark M.
turned on guest access
7:25 PM
Gabriele
has entered the room
Mark M.
hello, Gabriele
how can I help you today?
Gabriele
hi Mark :)
I have some issue with viewpager/fragments, I did some error, probably
I'm getting: java.lang.NullPointerException: Attempt to write to field 'android.support.v4.app.FragmentManagerImpl android.support.v4.app.Fragment.mFragmentManager' on a null object reference
this is the code I have inside my FragmentActivity:
View paste
setContentView(R.layout.main);

		ViewPager mPager = (ViewPager) findViewById(R.id.pager);
		mPager.setAdapter(new mChatAdapter(getSupportFragmentManager()));
Mark M.
that sounds like something is trying to update mFragmentManager via reflection on a Fragment, but the Fragment is null
can you post the full stack trace?
Gabriele
sure
7:30 PM
Gabriele
View paste (36 more lines)
09-02 19:27:38.970    2612-2612/? E/memtrack﹕ Couldn't load memtrack module (No such file or directory)
09-02 19:27:38.970    2612-2612/? E/android.os.Debug﹕ failed to load memtrack module: -2
09-02 19:27:41.710    2636-2636/? E/memtrack﹕ Couldn't load memtrack module (No such file or directory)
09-02 19:27:41.710    2636-2636/? E/android.os.Debug﹕ failed to load memtrack module: -2
09-02 19:27:43.841    2646-2646/net.fr0g.mchat E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: net.fr0g.mchat, PID: 2646
    java.lang.NullPointerException: Attempt to write to field 'android.support.v4.app.FragmentManagerImpl android.support.v4.app.Fragment.mFragmentManager' on a null object reference
            at android.support.v4.app.BackStackRecord.doAddOp(BackStackRecord.java:394)
            at android.support.v4.app.BackStackRecord.add(BackStackRecord.java:389)
            at android.support.v4.app.FragmentPagerAdapter.instantiateItem(FragmentPagerAdapter.java:99)
            at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:832)
            at android.support.v4.view.ViewPager.populate(ViewPager.java:982)
            at android.support.v4.view.ViewPager.populate(ViewPager.ja
...
Lucy
has entered the room
Mark M.
is there a scenario in which your PagerAdapter might return a null Fragment?
Lucy
Hello! Joining my first Office Hours
Mark M.
(BTW, hello, Lucy -- I will be with you shortly!)
Lucy
No rush. Observing to start.
Gabriele
View paste (2 more lines)
uhm, to me the only returning (maybe) null seems this: private Fragment getFragmentByType(Class type) {
		Fragment currentFrag = null;

		for (WeakReference<Fragment> ref : fragmentList) {
			Fragment f = ref.get();
			if (f != null) {
				if (((Object) f).getClass() == type) {
					currentFrag = f;
					return currentFrag;
				}
			} else { //delete from list
				fragmentList.remove(f);
			}
		}

...
maybe I wrote a wrong main.xml? Can this be the reason?
hi Lucy :)
Mark M.
well, that code will return null if the WeakReference has been culled already
that code looks a bit odd in general
it will also return null if it cannot find anything in the list of the proper type
Gabriele
I think it's still not called, will try to remove it
yes, it wasn't the cause, but I've removed it anyway
7:35 PM
Gabriele
can I paste the entire xml?
maybe I did some stupid error there
EGHDK
has entered the room
Mark M.
I wouldn't, as I don't see how that could cause this error
Gabriele
ok
hi EGHDK
Mark M.
I'd put logging in getItem() in your FragmentPagerAdapter to see if it is returning null in some scenario
let me take questions from the others, and I'll be back with you in a bit
Lucy: your turn! do you have a question?
EGHDK
Hello, everyone. No questions from me for now.
Lucy
Hi Gabriele :-)
Gabriele
sure, thank you Mark
Lucy
Well..I have a tiny app in mind that is very simple. Its a tiny app for my friend's business. I want to bundle just a few audio things into it. So far I'm going to follow the advice in "Get Your Media On".
Mark M.
OK
Lucy
I see the various locations that audio files can be stored. If they are not "large" I'm tempted to go with storing them in /raw. Unless that's really an anti-pattern.
Mark M.
no, res/raw/ is fairly typical for short audio clips
I wouldn't put a symphony in there
Lucy
OK cool. I will write the app initially referring to there. Can always change it once I have everything else in place.
Mark M.
yes
really, the biggest issue is whether your app will be too big with all the media
7:40 PM
Mark M.
and "too big" is in the eyes of the user
Lucy
Yeah, that's what I'm worried about. There is a video I'd like to include. But the user would view it only once or twice. I thought about fetching it upon a button click, store it and then automatically delete it.
Mark M.
or play it back as a stream, depending on the video hosting
Lucy
If I gave buttons to delete the audio and download again...maybe that would be ok?
In that case, the audio would not be from /raw. I'd have to put it on SD card.
This app is my first Android app. :-)
Mark M.
well, not an SD card, only because few devices have one
EGHDK
Mark, theres no way to delete an asset once it has been downloaded with an apk? So theres no way to delete anything in lets say res/raw?
Mark M.
you will need to put it on internal storage or external storage in most cases
Lucy
Oh yes. OK, internal storage...as in data/data.
Mark M.
assets/ and res/raw/ are read-only at runtime; they cannot be modified or deleted
internal storage is sometimes data/data/ -- do not rely upon that
use proper methods, like getFilesDir(), to learn where it is on any given environment
Lucy
OK cool, I'll probably do internal storage. Thank you!
Mark M.
those are links to a pair of blog posts of mine that try to explain storage a bit more
(and eventually I will blend that material more into the book...)
let me take questions from the others, and I'll be back with you in a bit
Lucy
Terrific! I've been studying and studying and now I'm trying to get ready to actually do something.
Thanks, I'm all set for now.
Mark M.
EGHDK: your turn! do you have a question?
EGHDK
Yes.
I have a simple application with just 3 activities. I'm interested in using parse.com for it's backend capabilities.
Anyway, parse requires me to create an application class and override oncreate in it.
Mark M.
:: grumble ::
7:45 PM
EGHDK
I put a simple toast notification in the onCreate of the Application class, and I get that toast at times that I don't expect it.
Mark M.
personally, I'd use Log statements, just in case there's something with UI processing that is affecting matters
EGHDK
I'll lock my device. Put it in my pocket. Turn it back on again. Enter password... and bam. Toast shows. Even though the app isn't in the foreground. What gives?
Mark M.
Android recreated the process for some reason
could be an alarm from AlarmManager scheduled by the Parse code
EGHDK
Yeah, but I get that toast every time. Exactly. I don't have anything from parse in there. I commented it out just to check.
Mark M.
:: shrug ::
without knowing your app, I cannot tell you why Android is recreating your process
EGHDK
Had me curious about the lifecycle. I thought one application class per process... and one process per application (unless you specify otherwise)
Mark M.
you might have a START_STICKY or START_REDELIVER_INTENT service, for example
EGHDK
No services...
Mark M.
there is one Application instance per process, and by default one process per app
EGHDK
I'll create a total dummy application, and add the toast in that Applications onCreate and see what happens. Just to make sure its nothing else. Thanks.
So Application is a singleton essentially?
Mark M.
yes
EGHDK
Thoughts on storing data in it?
Mark M.
I'd rather use regular static data members
as you can have N of those, lazy-initialized, etc.
Application is handy for a few things related to cache management, as a central onTrimMemory() handler, for example
7:50 PM
EGHDK
Wouldn't it make more sense to just put them in an application class? Where would you use a static data member? Create a custom class just to store it?
Mark M.
that depends on the nature of the data
EGHDK
True. Okay. Thanks
Mark M.
let me take questions from the others, and I'll be back with you in a bit
Gabriele: your turn! do you have another question?
Gabriele
Mark, the problem was inside getItem, I was returning a wrong null there
for now I don't, thank you :)
Mark M.
OK, glad to hear you found the problem
Lucy: your turn! do you have another question?
Lucy
No technical questions yet. Thanks!
Mark M.
OK
EGHDK: back to you -- do you have another question?
7:55 PM
EGHDK
Yeah, so another issue I'm having is with memory leaks.
According to effective java, they are "unintentional object retention"
Mark M.
much as a water leak is "unintentional liquid dispersal"
Gabriele
ahah
EGHDK
So they show an example of an array, and basically they are poping off the last element, but it's still in the array, so it's a memory leak.
Mark M.
um, that doesn't make a lot of sense
for example, you can't pop things off of a Java array
you can pop things off of an ArrayList, but then the object is no longer in the ArrayList
EGHDK
Yeah, but I think they do it by "hand" to explain the point.
Mark M.
um, OK
EGHDK
They create a method called pop
and write the code in it
What I'm really asking is... "Well if the activity get's "finished" doesn't everything in it also get GC'd?"
8:00 PM
Mark M.
yes, which gets me back to the "that doesn't make a lot of sense" point
if their array was in a static data member, and you accidentally had stuff in the array that you forgot about, *then* you have a memory leak
or if their array were otherwise ineligible for garbage collection, such as a thread still being able to reach it
EGHDK
Hmm... you don't think it would be wise for me to post the example would it?
Mark M.
unless they have published the code under an open source license, I would not post it
EGHDK
Alright, yeah so I guess it's hard to explain. But mostly.... since an Activity is an "object", if it get's finished does that mean it's GCd?
Mark M.
not necessarily
let's switch to the physical world for a bit
imagine a chain
a chain is made of interlocking links
if the chain is not connected to anything, you can collect it and throw it in the garbage
(which would be a waste of a perfectly good chain, but I digress...)
now, suppose that one end of the chain is nailed to a wall
at this point, none of the links can be collected and put in the garbage, because they all connect, directly or indirectly, to the wall
(and we'll assume the garbage can is on the far side of the room, and you're really too tired to move it)
but, you take a bolt cutter and snip one of the links, part-way along the chain
8:05 PM
Mark M.
the part from that point downwards is now disconnected from the wall, and you can collect it and put it in the garbage
switching back to the world of garbage collection in an object-oriented language...
there are certain objects whose scope is considered "static"
in Java, this includes static data members and threads
those objects cannot be garbage collected, by definition
anything they hold onto cannot be garbage collected, because those objects are reachable from a static reference
anything that *those* objects hold onto cannot be garbage collected, because those objects are indirectly reachable from a static reference
ad nauseum
here, the objects are the links of the chain, and static references are the nail in the wall
while an Activity is running (i.e., it has not yet been finish()ed), it is being held in a list of running activities somewhere in framework code
once it is finish()ed and destroyed, it is removed from that list
EGHDK
Gotcha. So when it's running it's being referenced to... in some list somewhere.
Mark M.
now, it is eligible for garbage collection if and only if nothing else can reach it
EGHDK
Okay, so lets say nothing else can reach it.
Mark M.
at that point, it is eligible for garbage collection
EGHDK
Is there anything in the activity that could keep the Activity from being GCd?
Lucy
And if and only if it gets GC'ed? Is it possible it may not get GC'ed?
Mark M.
EGHDK: you said "lets say nothing else can reach it"
either that is true, or it is not
if it is true, then nothing can prevent it from being garbage collected, though how quickly that will occur in Android will vary
8:10 PM
EGHDK
So just because let's say I have a static data member in my Activity, can my instance of my Activity be GCd?
Mark M.
Lucy: something else could have a reference to the activity that prevents it from being garbage collected, like a thread
Lucy
Thank you
Mark M.
EGHDK: that depends on what the static data member holds
EGHDK
Lets just say an int
Mark M.
then no
but, if it held the activity, or a widget in the activity, then that would prevent if from being garbage collected
EGHDK
Okay, so why the widget?
Gabriele
why the integer not, Mark?
Mark M.
because the widget has a reference to the activity
EGHDK
Button = (Button) findViewById(R.id.button); doesn't have an activity reference?
Mark M.
Gabriele: an Integer does not hold onto anything other than an int primitive
EGHDK: that is a Java statement, not an object, a variable, or a data member
inside android.view.View, there is a data member that points to the activity
Button inherits from View
(indirectly)
EGHDK
Yes.
Mark M.
if you put the Button in a static data member, the Button cannot be garbage collected (it is a link nailed to the wall)
EGHDK
But so when I call set contentView() I'm giving the view an activity?
Mark M.
you are connecting a view to its activity, and vice versa
an activity holds onto the root view (which represents the top of the view hierarchy for the activity's UI)
EGHDK
Urg... but how? Where am I actually doing that?
Mark M.
and each View has a reference back to the activity
8:15 PM
Mark M.
it is part of the implementation of Activity, View, LayoutInflater, etc.
(BTW, Gabriele and Lucy, if you have a question on a different topic, let me know -- I'm letting this discussion run because you both indicated you were out of questions)
EGHDK
So if all I did was `static Button myButton` defined in my class, then somewhere I actually set it to a button, and then the activity calls finish(), it will never be GC'd because of that static view?
Lucy
Sure, I think I thought of a new flavor of my previous question...
Gabriele
I have one, but this topic is interesting, too :P
Mark M.
EGHDK: correct
Lucy
I'm also enjoying that topic. My question is basic anyway I think...
Mark M.
EGHDK: let me take these other questions, and we can circle back to this in a bit
EGHDK
No prob
Mark M.
Gabriele: let's take your question, as you're next in line
Gabriele
Mark, with ViewPager, if the user is using a "small" screen, I'd like to use right-swipe to get the username list (remember my irc chat app?), if he's using a bigger screen (tablet) I'd like to show both the chat messages and the username list. The first one is easy achivied with ViewPager, but the second? Should I replace the ViewPager with two fragments aside, if the screen is bigger?
Mark M.
that's a reasonable pattern
the biggest thing is that trying to change approaches in a configuration change is tricky
so for example, if in landscape you wanted them side by side, but in portrait you wanted them in pages in a ViewPager, you'll need my ArrayPagerAdapter or your own PagerAdapter
FragmentPagerAdapter does not play nice with the other kids
and FragmentStatePagerAdapter inherits that behavior from FragmentPagerAdapter
Gabriele
ah, nice to know
Mark M.
I seem to recall covering this scenario in the book, though I'm a bit fuzzy on that
Gabriele
so in this case, I have two completely different approaches for small and bigger screen, it seemed strange to me
Mark M.
well, think of it as you have two fragments, and just different ways of using them
8:20 PM
Mark M.
it's really not that different from other variations on the master/detail pattern
check out the advanced ViewPager chapter, and I cover stuff in there that should help you
Gabriele
ok, thank you, I will check inside the book if I find something, too
yes, thanks
Mark M.
Lucy: your turn! you had another question?
Lucy
I want the user to be able to watch a video that they will only watch once or twice. The video won't be hosted on YouTube but I was thinking I could have the file that is the video, it could be hosted on the business web site as a resource. Then I'd download the video as a file on the fly, user watches it, then I delete automatically (at some appointed time). Does that sound reasonable?
Mark M.
well, download-then-watch is slow for the user, as they have to wait for the download
if your plan is to delete the video automatically, I'd stream it, which does not imply YouTube
Lucy
Hm. Good point. To stream it, the user would have to be connected to the internet in that moment though?
Mark M.
correct, but I kinda assumed that "download the video on the fly"
meant that the user somewhere said "I want to view the video"
and the downloading implies Internet access
Lucy
Oh yeah, good point. :-) Maybe that's OK. For the audio snippets I will keep them local.
For the audio I don't want the user to need internet access. OK! Thanks!
Mark M.
downloading is fine if the user might watch the video several times, but I'd only download it on user request if the file is big, as they may not want to pay for the bandwidth
Lucy
Oh! Great point on bandwidth.
That's all my questions.
Mark M.
OK
EGHDK: back to you
EGHDK
What else are common things that hold onto an activity, that I may not know about right away? Besides views?
Mark M.
fragments do
EGHDK
Since I never pass an activity into a view arguement, I didn't know that they held onto it.
Mark M.
anything that has getActivity() will
8:25 PM
Mark M.
you pass a Context into any View constructor
EGHDK
Really?
Mark M.
and that Context usually is an Activity
EGHDK
Where?
Mark M.
it's the first parameter, if not the only parameter, on every constructor on every subclass of View
that's because all constructors on View take a Context, and you have to chain to the superclass' constructor from your own
in the case of layout inflation (e.g., setContentView(R.layout.main)), LayoutInflater invokes the proper constructors and passes the Activity into them
EGHDK
Okay, so set Content View knows to pass in the activity?
setContentView()
Mark M.
setContentView() is a method on activity
er, Activity
it creates a LayoutInflater, which handles converting R.layout.main into the View hierarchy
EGHDK
Gotcha.
Mark M.
LayoutInflater is the one calling the constructors on the various subclasses of View
and LayoutInflater is the one passing the Activity in as the Context to the constructors
EGHDK
So calling setContentView() has access to the activity how? That's the only part I'm confused with? Why don't I do setContentView(Context, R.id)?
Mark M.
setContentView() is a method on Activity
Activity inherits from Context
hence, in the implementation of setContentView(), the "this" object is the Activity instance
8:30 PM
Mark M.
and that's a wrap for today's chat
EGHDK
Gotcha. So because I call setContentView ON an Activity it has access to the object that called it
Mark M.
the transcript will be posted to http://commonsware.com/office-hours/ shortly
EGHDK: correct
EGHDK
so it doesn't have to specifically request a context?
Lucy
has left the room
EGHDK
Okay, I'll look into it thanks!
Gabriele
thank you, Mark
Mark M.
a quick note: Version 6.0 of the book will be released in ~14 hours
EGHDK
Is this the big pivot?
Gabriele
oh, nice :P
Mark M.
the next office hours chat is slated for Thursday morning at 9am US Eastern Time
EGHDK: it's the Android Studio portion of the pivot, yets
er, yes
have a pleasant day!
Gabriele
you too, Mark, thanks!
Gabriele
has left the room
EGHDK
has left the room
Mark M.
turned off guest access

Thursday, August 28

 

Office Hours

People in this transcript

  • EGHDK
  • Gabriele
  • Lucy
  • Mark Murphy