Sep 15 | 8:55 AM |
Mark M. | has entered the room |
Mark M. | turned on guest access |
MyWay | has entered the room |
MyWay |
hi Mark
|
Mark M. |
hello, MyWay!
|
Mark M. |
how can I help you today?
|
MyWay |
I'm using ViewPager with ArrayPagerAdapter, anything is working fine, but I have added a badge from which users can jump to a specific Fragment selecting the User in the drawer. Now, if the Fragment exists there is no problem and I'm returning its position from a loop mAdapter.getExistingFragment(i)) checking it's title/tag (I know it in advance), else I don't know where to jump. So, the user has a list in the right drawer and he knows in advance that there are new messages from a specific User, but when he taps on one of these user in the list, I don't know always the position. How can I force the ViewPager to create the needed fragment in that istant so that I can get the position and jump to the right position? Currently I'm receveing inside the Activity, from my Service (using EventBus) a call and I'm doing this: http://pastebin.com/xwbvrsf9 but mQueryFragment is != null only if the ViewPager instantiate it.
|
Bryan | has entered the room |
Mark M. |
(BTW, hello, Bryan -- I will be with you shortly!)
|
Bryan |
Hi, np
|
Mark M. |
MyWay: well, the ViewPager doesn't create fragments
|
Mark M. |
the adapter creates fragments
|
Mark M. |
and the adapter only does so on demand
|
Sep 15 | 9:00 AM |
MyWay |
but it is the viewpager asking to do, right?
|
MyWay |
when the user swipe
|
Mark M. |
yes, but only if there is a position for it
|
Mark M. |
IOW, if your page count is 7, and you ask for position 3439, you'll crash somewhere
|
Mark M. |
or at best be ignored
|
MyWay |
what I'm trying to do is forcing it to add a new position so that I can jump the user to it
|
MyWay |
can I do it?
|
Mark M. |
you are certainly welcome to add a new entry to the ArrayPagerAdapter
|
Mark M. |
that's part of the reason I wrote it :-)
|
Mark M. |
but ViewPager itself won't ever trigger that
|
MyWay |
infact I'm adding it from the code: mAdapter.add(new SimplePageDescriptor(sQuery.toLowerCase(), sQuery));
|
Mark M. |
OK
|
MyWay |
but I still have the problem that I don't have a position returned
|
Mark M. |
add() appends to the e4nd
|
Mark M. |
er, end
|
Mark M. |
so, the position is your page count minus one
|
Mark M. |
(page count as calculated post-add)
|
Mark M. |
(which also means your new position is your page count as calculated before the add() call)
|
Mark M. |
let me take a question from Bryan while you mull that over, and I'll be back with you in a bit
|
MyWay |
but why if I'm doing a loop for (int i = 0; i < mAdapter.getCount(); i++) { after adding it
|
Mark M. |
Bryan: your turn! do you have a question?
|
MyWay |
I don't have this fragment here?
|
MyWay |
oh sorry
|
Bryan |
I have a notification who's pending intent on click goes to my MainActivity (only activity for my app), there is a function that handles that intent and then shows the correct fragment based on the type of notification. The "shows the correct fragment part" clears out the fragmentmanager backstack and then starts a new stack by inserting the starting fragment, then immediately showing the fragment they want.
|
Bryan |
right before this I clear out the backstack (if there was one), so it all starts fresh.
|
Sep 15 | 9:05 AM |
Bryan |
The problem is that sometimes, when clearing the backstack, I get a IllegalStateException: Can not perform this action after onSaveInstanceState
|
Bryan |
not everytime, just sometimes
|
Bryan |
I am not as saavy as I would like on lifecycle stuff, so I was wondering if you had any ideas to point me in the right direction
|
Mark M. |
um, well, let's back up a bit
|
Bryan |
:), sure
|
Mark M. |
by default, your PendingIntent would be creating a new instance of the activity
|
Mark M. |
presumably, you're doing something to change that behavior
|
Bryan |
let me check
|
Mark M. |
are you using Intent flags? launchMode in the manifest?
|
Bryan |
notificationBuilder.setContentIntent(PendingIntent.getActivity(this, 0, contentIntent, PendingIntent.FLAG_ONE_SHOT));
|
Mark M. |
are you adding any flags to contentIntent?
|
Bryan |
checking
|
Bryan |
View paste
|
Bryan |
then just setting data
|
Mark M. |
OK, do you have android:launchMode set in the manifest for this activity?
|
Bryan |
SingleTask
|
Mark M. |
ah, there we go
|
Bryan |
*singleTask
|
Mark M. |
do you really want to be reusing the activity in this case? or would you prefer to just wipe out the old activity (if it exists) and start a new one fresh?
|
Sep 15 | 9:10 AM |
Bryan |
I would have to think through if there were any issues, but let's say that I am open to whichever works best
|
Bryan |
I know that we had other issues when I had the launchmode to singleActivity
|
Bryan |
unfortunately, I don't remember what they were
|
Mark M. |
my gut instinct would be to start fresh, rather than trying to rework the existing activity instance
|
Bryan |
ok
|
Bryan |
what would I change to move towards that?
|
Bryan |
also, could you explain what the issue is
|
Bryan |
as you see it
|
Mark M. |
to do that, call addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) on the contentIntent before wrapping it in the PendingIntent
|
Bryan |
re: "ah, there we go"
|
Bryan |
ok
|
Mark M. |
though I have never tried this in concert with singleTask launchMode, so YMMV
|
Mark M. |
the "ah, there we go" was trying to understand why you had a back stack in the first place :-)
|
Mark M. |
in terms of what the problem is...
|
Mark M. |
while I have seen that error before, usually to me it means "you have wandered too far off the path of the Way of Fragments"
|
Bryan |
lol, that would be a fair guess
|
Mark M. |
which is why, all else being equal, I'd rather wipe out the old activity and start anew, rather than trying to retrofit the existing activity instance
|
Bryan |
ok, thanks! I will try the flag above and see how that goes!
|
Mark M. |
that being said, without code, I have no way of telling you why you might get that error, and I probably can't even *with* code, in the confines of a chat
|
Bryan |
that makes sense
|
Mark M. |
it's the sort of thing that given a mostly-working app and a way to reproduce the problem, I can probably find the culprit
|
Bryan |
yeah, we haven't found the way to reproduce at this point
|
Mark M. |
but I don't have a roster of likely culprits to offer
|
Bryan |
just got this yesterday though, so still working through it
|
Mark M. |
let me switch back to MyWay, and I'll swing back to you in a bit
|
Mark M. |
MyWay: your turn!
|
Bryan |
sounds good
|
MyWay |
I meant, I'm adding the Fragment to the adapter, then I'm looping over getCount (http://pastebin.com/FYhHjZBw (getting -1)), now from what I've understand I should find the Fragment I'm searching for (which should be the last), but it's not here, maybe that it has not been added yet?
|
Sep 15 | 9:15 AM |
Mark M. |
no, add() does not create the fragment
|
Mark M. |
add() adds the descriptor
|
Mark M. |
and makes it possible to create the fragment when the ViewPager asks for the fragment
|
MyWay |
so how can I jump to this fragment? I add it to the adapter, but then I need viewpager to ask for it
|
Mark M. |
"so how can I jump to this fragment?" -- call setCurrentPosition() on the ViewPager with the position
|
Mark M. |
whoops, sorry, setCurrentItem()
|
Mark M. |
where the position is adapter.getCount()-1
|
Mark M. |
after calling add()
|
MyWay |
ok, then I've added many descriptors by calling add()
|
MyWay |
but still not swiped or moved the viewpager
|
MyWay |
how do I find the position? :P
|
MyWay |
should I store it when I'm adding?
|
Mark M. |
as I wrote, "where the position is adapter.getCount()-1"
|
Mark M. |
where "adapter" is your ArrayPagerAdapter
|
MyWay |
yes, but it's getCount()-1 when you add only one
|
MyWay |
if I add 10 and want the 5?
|
Mark M. |
why are you adding 10 pages, based on a single click by the user?
|
MyWay |
is there a way to loop over them and search by knowing in advance the title/tag, or I should store?
|
MyWay |
it's a single click, they are irc events
|
Mark M. |
so?
|
Sep 15 | 9:20 AM |
MyWay |
if the user receives 10 messages from 10 differents users, the drawer has 10 items in the listview
|
MyWay |
then the user tap on one of them, but I've already added them to the adapter
|
MyWay |
(them all)
|
Mark M. |
then you already know the position
|
Mark M. |
after all, you added the page
|
Mark M. |
and at that time, you knew the position
|
MyWay |
so I should store it
|
Mark M. |
well, yes
|
MyWay |
ok, thank you
|
Mark M. |
let me take another question from Bryan, and I'll be back with you shortly
|
Mark M. |
Bryan: your turn! do you have another question>
|
Mark M. |
er, ?
|
Bryan |
Yes, ok, so the issue that got me to even try the clearing the back stack was this
|
Bryan |
I have a current backstack: Page 1 > Page 2 > Page 3
|
Bryan |
i get a notification with a pending intent that my activity launches a "Page 2" fragment
|
Bryan |
so then I am Page 1 > Page 2 > Page 3 > Page 2
|
Bryan |
so when I hit back twice I get "fragment already added" exception
|
Bryan |
make sense?
|
Bryan |
aka "am I thinking of that right" ?
|
Mark M. |
wait, both "Page 2" entries in your back stack are the same fragment instance?
|
Bryan |
I think so
|
Mark M. |
that's unlikely to work well
|
Bryan |
I think that is why I am getting the error, I assumed that it would handle it automatically
|
Bryan |
but that isn't the case
|
Mark M. |
having two fragment instances both backed by the same "Page 2" data would be fine
|
Sep 15 | 9:25 AM |
Bryan |
does givng it a different tag to the fragmentmanager
|
Bryan |
ensure a distince instance?
|
Bryan |
*distinct
|
Mark M. |
no
|
Bryan |
how do I ensure that?
|
Mark M. |
*you* are the one creating instances, when putting them in the FragmentManager
|
Mark M. |
so, you create new instances by calling the constructor on the fragment, or the factory method, or whatever
|
Bryan |
yeah, i wrote some functions that do that automatically, so it is the past me that is at fault here
|
Bryan |
the current me can't be held responsible
|
Mark M. |
fire up the DeLorean and slap your past you with a trout :-)
|
Bryan |
:), Ok, I will look to see if I can make sure I do a separate instance for the second part
|
Bryan |
if I can't find that
|
Mark M. |
(and, if convenient, slap the past me a few times with that trout, as I'm sure I deserve it for something)
|
Bryan |
ha
|
Mark M. |
are these pages read only? or are they forms to be filled in
|
Mark M. |
?
|
Bryan |
read only
|
Mark M. |
ah, cool
|
Mark M. |
then two fragment instances should be OK
|
Bryan |
they have buttons and whatnot, but they are just for viewing
|
Bryan |
I was trying to resuse to save memroy
|
Mark M. |
which is fine, but I don't think the back stack is sophisticated enough for that
|
Bryan |
yeah, I am finding that out. The problem is that even though I use "replace" the backstack code deep in the bowels does a remove and add
|
Bryan |
so it throws that error
|
Bryan |
seems "wrong" somehow, but who am I to say that
|
Bryan |
thanks again
|
Mark M. |
well, fragments are kinda bolted onto the side of Android
|
Mark M. |
they're odd in general
|
Mark M. |
(and don't get me started on nested fragments...)
|
Bryan |
:)
|
Sep 15 | 9:30 AM |
Mark M. |
I've long since given up on "right" and "wrong" and settled for "seems stable" and "breaks even despite the pentagram of dried bat blood I sprinkled on the floor"
|
Bryan |
good to know! I just felt like I was the only kid in class that didn't "get it"
|
Mark M. |
let's just say that while I'm not in Square's "fragments are the work of the devil" camp, I feel their pain
|
Mark M. |
let me take another question from MyWay, and I'll swing back to you shortly
|
Mark M. |
MyWay: your turn! do you have another question?
|
MyWay |
Currently when the app is in background, my Service is caching all IRC Events. As memory is not infinite, can I use onLowMemory() call to remove some event? Or it's a bad practice?
|
Mark M. |
what's your minSdkVersion?
|
MyWay |
the one of Android 4, can't remember the number
|
Mark M. |
OK, that'd be at least 14
|
Mark M. |
in which case, a typical caching approach is to use an LRU or similar approach to prevent you from blowing out your heap, then use onTrimMemory() to try to progressively "tighten your belt" while you are in the background
|
MyWay |
yes
|
Mark M. |
onLowMemory() was primarily for pre-API Level 14 devices; onTrimMemory() covers everything onLowMemory() does, with more granularity
|
MyWay |
this seems reasonable
|
Sep 15 | 9:35 AM |
Mark M. |
many developers skip the onTrimMemory() approach, most likely
|
Mark M. |
that's a "be a good citizen" thing to do
|
MyWay |
why?
|
Mark M. |
as onTrimMemory() helps the *user* but doesn't really impact your app much
|
Mark M. |
other than perhaps keeping your process alive a bit longer
|
MyWay |
ah, so they don't care
|
Mark M. |
I'd phrase it more as "it's way down on the to-do list"
|
Mark M. |
for those that know it's something that can be done, at any rate
|
MyWay |
:P
|
Mark M. |
I don't even emphasize it much in my book, though I probably should
|
MyWay |
ok, thank you
|
Mark M. |
those sorts of things that have no direct benefit on the developer (or the developer's boss) tend not to get a lot of attention
|
Mark M. |
until such time as Google drops the hammer, as in Android 6.0
|
Mark M. |
and its "war on background processing"
|
MyWay |
yes, I'm just doing this app for fun
|
MyWay |
and to learn
|
Mark M. |
and because you still use IRC :-)
|
MyWay |
ahah, yes
|
Mark M. |
*vaguely remembers IRC*
|
MyWay |
eheh
|
Mark M. |
ooo... I hadn't realized that Campfire recognized IRC slash commands like /me
|
MyWay |
:P
|
Mark M. |
anyway, let me switch back to Bryan for a bit
|
Mark M. |
Bryan: your turn! do you have another question?
|
Sep 15 | 9:40 AM |
Mark M. |
OK, if either of you have a question, go right ahead
|
MyWay |
I have an inner class, OutputArrayAdapter extending ArrayAdapter inside a Fragment, can this cause memory leaks? I always read that inner class is bad, because it keeps outer reference, but what happens with adapters' class inside fragments?
|
Mark M. |
well, that depends on the scope of your OutputArrayAdapter instance
|
Mark M. |
I assume this is an adapter for a ListView or something shown by the Fragment?
|
MyWay |
yes
|
Mark M. |
then unless you are doing something strange, you should be OK
|
Mark M. |
the problem with inner classes come when you use the inner class for something with scope outside its outer class
|
Mark M. |
for example, if you have an inner class implementation of SensorEventListener, when you register it with SensorManager, you will leak the outer class instance until you unregister it
|
MyWay |
but if I have a method which is returning the adapter, is it a problem?
|
Mark M. |
if that method is being called by something beyond the life of the fragment, potentially, yes
|
MyWay |
so I should avoid doing it
|
Mark M. |
having the method? yes
|
MyWay |
yes
|
Mark M. |
keep it within the fragment
|
Mark M. |
have the fragment expose an API for doing what needs doing
|
Mark M. |
that is better encapsulation anyway, in case you switch implementations (e.g., move to RecyclerView)
|
MyWay |
ok
|
Sep 15 | 9:45 AM |
MyWay |
if Bryan is not here, I have a last question
|
Bryan |
I am here
|
Bryan |
I have one more short question
|
Mark M. |
Bryan: go right ahead!
|
Bryan |
Is there a good resource out there to reference (more from a tutorial standpoint) for messing with the innards of fragments/backstack, etc?
|
Mark M. |
the source code
|
Mark M. |
beyond that, I can't really name anything
|
Bryan |
ok, cool, thanks Mark!
|
Bryan |
have a good one
|
Mark M. |
if either of you have a question, chime in
|
MyWay |
Always about Leaks, I've tried playing with the device monitor and MAT, e.g. I got this http://i58.tinypic.com/2yzbdwp.png and after 15 minutes (disconnection/connection/configurationChange), I got this: http://i59.tinypic.com/ff90mw.png now... I can not see differences, it seems difficult to analyze to find leak, do you have any suggestion?
|
Mark M. |
well, it may not be a "leak"
|
Mark M. |
as you noted, you are caching stuff like IRC messages
|
Mark M. |
cache growth = heap growth
|
MyWay |
yes
|
Sep 15 | 9:50 AM |
Mark M. |
in MAT, I usually focus on finding instances of my classes that should not be cached, plus looking for big things that should not be cached
|
MyWay |
but from logcat (Mint) I'm getting OutOfMemoryException on: rootView = inflater.inflate(R.layout.userlist, container, false); unfortunately the log is incomplete and I have no idea what is causing it (only a device seems to have this problem)
|
MyWay |
the list does not contain images, nothing
|
MyWay |
just a list of string (user nicknames)
|
Mark M. |
bear in mind that OOM does not mean that you are out of heap space, but that there is no single free block big enough for your request
|
Mark M. |
the Dalvik GC engine is non-compacting
|
Mark M. |
(and ART only compacts when your app is in the background)
|
Mark M. |
so your heap can be fragmented
|
MyWay |
ah
|
Mark M. |
usually, an OOM on an inflate() call is triggered by android:background
|
Mark M. |
as Android did not have a big enough block of memory for your drawable resource that you are using for the background
|
MyWay |
my background is ?android:attr/windowBackground
|
Mark M. |
any reason why you need that, versus it just having no background at all?
|
MyWay |
not that I can remember of
|
Mark M. |
try removing android:background, see if your UI still looks OK, and if it does, see if it helps with the OOM when you release an update
|
Sep 15 | 9:55 AM |
MyWay |
yes, thank you
|
Mark M. |
it's possible there's something else in the layout that would trigger an OOM on inflation, but backgrounds tend to be the biggest culprit, based on what I've seen through Stack Overflow questions
|
MyWay |
I finished the questions, thank you very much, as always
|
Mark M. |
happy to be useful!
|
MyWay |
maybe fastscroll?
|
Mark M. |
pardon?
|
MyWay |
I haven't set anything
|
MyWay |
android:fastScrollEnabled="true"
|
Mark M. |
possibly, but I haven't heard of that being an issue
|
MyWay |
ok, I will try with the background, thanks again
|
Sep 15 | 10:00 AM |
Bryan | has left the room |
MyWay |
Have a nice day, bye
|
MyWay | has left the room |
Mark M. | turned off guest access |