Office Hours — Today, February 26

Tuesday, February 24

Feb 26
7:20 PM
Mark M.
has entered the room
Mark M.
turned on guest access
7:25 PM
Guido
has entered the room
Mark M.
hello, Guido
how can I help you today?
Guido
Hi Mark
Susheel
has entered the room
Susheel
Hi Mark
Guido
I've got a question about fragments going through configuration change.... I prepared it earlier today so I'm going to paste it here
Mark M.
hello, Susheel!
Susheel
Hi Guido
Guido
Hi Susheel
Susheel
I'll go after Guido
Guido
View paste
I have a ListFragment reading from a DB many records using AsyncTask.This fragment will need to be instantiated many times with different queries - basically I need multiple lists readily available.
I can't decide what is the best strategy for handling configuration change.
In their simplest implementation each strategy has side effects:
1) setRetainInstance seems not to keep the selected items/action mode when in CHOICE_MODE_MULTIPLE_MODAL
2) Saving Instance State will force me to reload the DB as the cursor is not persisted
3) As for retain a Model Fragment it would have to handle multiple instances of cursor
I will probably have to implement one of these anyway and work around the limitations, but i can't decide which one is the best option, any suggestion - or any other option?
Mark M.
"setRetainInstance seems not to keep the selected items/action mode when in CHOICE_MODE_MULTIPLE_MODAL" -- your views get rebuilt; setRetainInstance() has nothing to do with this on its own
Guido
oh I see, I didn't get this, so the class is retained but the view gets rebuilt?
Mark M.
correct
onCreateView() gets called again
as you need fresh widgets to go with the fresh activity
Guido
yes, that's right
7:30 PM
Mark M.
all setRetainInstance() does for you is say that non-widget data members could be held onto across the configuration change
for widget state like this, option #2 (onSaveInstanceState()) is the best answer, as that not only survives configuration change, but handles the recent-tasks list and such as well
for your model data, for something of this complexity, I'd lean towards #3 or a singleton data manager
the latter would be if the same model data is needed by multiple components (multiple activities, or activities plus services, etc.0
er, etc.)
Svetlin S.
has entered the room
Guido
OK and would I need to persist also the adapters or the cursors only?
Svetlin S.
Hello everyone.
Mark M.
hello, Svetlin -- I will be with you after Susheel!
Svetlin S.
Thanks.
Mark M.
Guido: I use "persist" specifically to refer to file-based storage
in which case, your data is already persisted
Guido
yep sorry... that's right
Mark M.
if you mean "retained", in terms of the model fragment, then I'd retain the cursors (the model data)
Guido
yep, that's what I meant :-)
thanks!
Mark M.
Susheel: your turn! do you have a question?
Susheel
View paste
I am writing a file to my external usb flash drive using the code in this stack overflow question. 
http://stackoverflow.com/questions/28228335/eacces-permission-denied-file-not-found
I am able to write the file but when I disconnect the flash drive keeping the device turned on 
and when I connect it back in and then try to write the file, I get a EACCES-permission-denied-file-not-found error. 
But if I do not disconnect the flash drive I am able to write to it multiple times without the error.
7:35 PM
Mark M.
um, well
that's probably something for you to take up with a manufacturer or something
first, flash drives like that aren't part of the Android SDK, at least pre-4.4
Susheel
right
but the same thing happens to my externally mounted sdcard
Mark M.
which, again, is not part of the Android SDK
Susheel
oh really
ok
Mark M.
removable media, pre-4.4, was outside the scope of the Android SDK
Susheel
gotcha
Mark M.
the sole exception is a device that uses removable media for external storage
and there haven't been many of those since Android 3.0
so, by and large, the rules of the game for removable media are up to the manufacturer
Susheel
Perfect, thanks :)
I have another question but I will wait for my turn.
Mark M.
sorry I didn't have a better answer for you
Susheel
That's cool, thanks
Mark M.
Svetlin: your turn! do you have a question?
Svetlin S.
Yes.
I'm working on a handset which will run only one application.
The handset connects to external devices using services.
I implemented a Watchdog service started on boot to "oversee" them.
Using AlarmManager.
Now I need to consistently check the status of those service (list, (re)start) etc.
Inside the Watchdog, periodically.
7:40 PM
Svetlin S.
I've come up with the idea of having a Pojo, ServiceManager which will provide the needed callbacks (registration of services, invoking operations on them etc.) to the Watchdog.
So far OK?
Mark M.
I'm baffled as to why all of this isn't being done in custom firmware, but, beyond that, I'm with you
Svetlin S.
Let me copy in Pastebin.
BTW the plan is eventually the app to run on a normal phone/tablet handset.
Mark M.
wait
"the app"?
singular?
all of these services are in one app?
Svetlin S.
The device will run just this app.
Mark M.
then I'm really lost
Svetlin S.
Yes, some are local, some remote (in another process). E.g. Bluetooth, RemoteSync etc.
Mark M.
ok
7:45 PM
Svetlin S.
It is a normal approach for a medical device running a custom Android version.
7:45 PM
Svetlin S.
Using ActivityManager in the ServiceManager does not seem to work out well, because the Watchdog has to run and take action even if the device is asleep.
Mark M.
I don't see how ActivityManager helps or harms in this are
er, in this area
if you want to check on the status of services periodically, and you want to do so even if the device is asleep, you'll use a _WAKEUP alarm
Svetlin S.
I can't get my services using it, including inside a ServiceTestCase.
Mark M.
I haven't used ActivityManager much, and I have never used getRunningServices(), so I have no idea what the expected behavior should be
other than I'd be stunned if waking the device out of sleep mode somehow affected that behavior
if you have these so tightly coupled, you might consider using the binding pattern
your "watchdog" simply binds to each of the services and does some AIDL equivalent of a "ping" or status check or whatever
Svetlin S.
There is the problem of the context, so that ActivityManager works called from an Activity, not so much from IntentService.
I hear you.
That's why I decided to put a static inside the controlled Service so that it reports its state.
Mark M.
in your case, you'd leave off BIND_AUTO_CREATE, so you would know if the service was not already created, so you could use startService() to get it running more durably
7:50 PM
Mark M.
but that is not useful across process boundaries
Svetlin S.
Let me pastebin what I tried.
Mark M.
actually, let me take questions from the others
and I'll be back with you in a bit
as this has gone on a little long
Svetlin S.
Sure!
Mark M.
Guido: your turn! do you have another question?
Guido
yes please
View paste (5 more lines)
Still the same app as before, it has a single activity and several fragments - like your EU4YOU sample - but I've got a problem with the back button
If I start a fragment and then replace with a different one, when I press back the app disappears rather than going back to the previous fragment, I used the
beginTransaction()
.replace()
.addToBackStack()
.commit()
as in your example, but something else is missing I guess...

To get it to work I tried to implement onBackPressed() this way - found on S.O. - :
    @Override
    public void onBackPressed() {
        if (getFragmentManager().getBackStackEntryCount() > 0) {
            getFragmentManager().popBackStack();
        } else {
            this.finish();
...
I realise it can be due to multiple factors but I wonder if you have an idea where to start from...
or just knowledge of some "popular" mistakes...
Mark M.
I don't think the back stack is designed to handle situations where you replace what was supposed to removed on a BACK press
in fact, that feels like a UX or code smell
oh, well, wait
never mind
I have a better picture for what you're doing
but I don't think the framework-supplied back stack will work well here
Guido
ok
Mark M.
it's designed for simpler scenarios, like EU4You
there, we only have two fragments, and either both are showing, or just the master
an example of your scenario would be master/detail, with N possible detail fragments
such as a shopping cart, with different fragments for different types of products (books versus movies versus boxes of laundry detergent)
7:55 PM
Mark M.
and there I would expect to have to handle the BACK stuff myself in onBackPressed(), though simply "knowing" whether the detail is showing and how to remove it
Guido
ok, that clarifies my problem then
Mark M.
in terms of the action mode stuff, are you referring to your own action mode, or a system-supplied one (e.g., EditText)?
Guido
in one fragment type is system supplied in a ListView and in the other one is custom becasue I have a RecyclerView
Mark M.
ListView doesn't have an action mode
EditText does, and WebView kinda does
but very few other widgets have one built in
(actually, TextView does if you make it selectable)
for your own action mode, I can see where onBackPressed() would need to know about it and finish() the action mode
Guido
oh I see what you mean
Mark M.
so it'd be: if action mode, then finish() it; else if detail showing, remove() it; else super.onBackPressed()
where the latter will do your finish() for the activity for you, along with anything else that normal BACK processing might need
doing finish() yourself is *probably* OK, but I just chain to super.onBackPressed(), so I know I'm not forgetting anything :-)
Guido
yep, sounds great
Mark M.
now, I may be off on your detail fragment handling, as I don't have a complete picture of what you're doing
8:00 PM
Mark M.
but let me take questions from the others, and I'll be back with you in a bit
Susheel: your turn! do you have another question?
Susheel
Going back to my previous question, when I replug the flash drive I'm able to view the contents of the flashdrive using a filemanager app. Does that mean that I should also be able to write a file to it? Or is that not sufficent info and should I still contact the manufacturer about it?
Guido
alright great
Mark M.
"Does that mean that I should also be able to write a file to it?" -- off the cuff, I would expect so
particularly if this file manager is a third-party one
not a pre-installed one
a third-party file manager should have no more capabilities than does your app
(modulo the device being rooted and that file manager leveraging that where your app does not)
Susheel
Ok. So do you think for some reason when I unplug the device the file path is being broken or something like that? Is that possible?
because when I restart it works well
until I unplug
Mark M.
aw, heck, on this Ubuntu notebook that I'm using, I sometimes have to reboot as the system freezes when I unmount the external hard drive I use for backups
*anything* can go haywire when dealing with removable storage as far as I am concerned :-)
then again, my last name is Murphy, and so I'm used to problems like this...
Susheel
Oh I see that makes sense...haha
Mark M.
so, while an Android device should be stable and well-behaved when unmounting and re-mounting removable media, that can have bugs just like anything else
Susheel
ok
Mark M.
and probably more than its fair share, given that device manufacturers can kinda do what they want
Susheel
Right
Mark M.
and some device manufacturers can get awfully creative when given that amount of flexibility
Susheel
No kidding
Mark M.
so, if you're not seeing stable results, that's definitely something you'll have to take up with the manufacturer
Susheel
Got it. Thank you Mark!
8:05 PM
Mark M.
(or reseller or whoever handles that support for the hardware in question)
Svetlin: your turn!
Svetlin S.
Thanks, let me continue from where I stopped.
I went over the binding pattern, and it looks it will do the job.
My problem is, other people with less experience are writing some of the services.
Mark M.
sounds like they need a good book :-D
Svetlin S.
That's why I'm trying to get away with the least possible changes to their code.
Please take a look at the static in http://pastebin.com/AFHT47Ab
In AuthenticatorService.
The idea is to have "state" variables describing the state a service is in.
I know you are against "constantly" running services, but in this case it is a matter of life/wellbeing that if a service stops, it is restarted ASAP.
Mark M.
for dedicated hardware, that's fine
it gets to be a bigger problem on off-the-shelf stuff used by ordinary people for other things
but, again, this is only an issue for remote processes
Svetlin S.
How so?
Mark M.
anything inside the same process as the watchdog won't stop unless you stop it or Android terminates that whole process
8:10 PM
Svetlin S.
I thought that's the case only if the service runs in "foreground"?
Mark M.
no
now, there's the case where the user goes into Settings and manually stops an individual service, but I am assuming that's not a worry for dedicated hardware
Svetlin S.
Hm. Anyway, opinion on the static?
Mark M.
you mean the singleton-ish instance of AuthenticatorService?
Svetlin S.
Yes.
Mark M.
IMHO it is not doing anything for you
Susheel
has left the room
Svetlin S.
I'm aware stopService is async, so onDestroy will not get called immediately, anything else?
Mark M.
but, if you want it, you're not leaking anything
Svetlin S.
Also, the service may mis-behave and get stopped because the hardware it is attached to mis-behaves.
Mark M.
but there your singleton won't help you
say for example you crash with an unhandled exception
assuming that it doesn't take down the whole process, Android might get rid of the individual service
but it's not going to call onDestroy()
because it assumes that your crashed service has lost its proverbial marbles
and it's just going to let go of it
and so your singleton will still point to it
Svetlin S.
Correct. OK then, the way to go is to have an interface basically implementing the binding pattern for all services?
8:15 PM
Svetlin S.
Then the ServiceManager will undertake this actions on behalf of the Watchdog?
Mark M.
well, the first thing is to have robust exception handling in all your code in the service :-)
the nice thing about the binding pattern approach is that your watchdog/ServiceManager neither knows nor cares what is or is not in your process
it just knows that it tries to bind and uses that to get state information
and if the attempt to bind fails, then the service collapsed for some reason, and so we need to startService() it again
that behavior is identical whether the service in question is in your process or in a :remote process
you could even create a ManagedService base class that handles all of the common stuff for the binding, and have the other developers inherit from it instead of Service
Svetlin S.
Yes. Thanks, very useful indeed. I also have a question about Service unit testing.
Mark M.
let me swing back to Guido first
Guido: your turn! do you have another question?
Svetlin S.
I think I'll do exactly that. Any sample code to share ;-)
Oops, sorry.
Mark M.
(Svetlin: not really, as I don't do a lot with binding -- yours is one of the few use cases where I find binding to be valuable)
Guido
no Mark, unless you have anything else to add, I think I'm good with your suggestions
Mark M.
OK
Svetlin: back to you
Svetlin S.
Are there any problems with this sort of testing?
8:20 PM
Guido
Thanks Mark, have a good night
Svetlin S.
View paste (20 more lines)
public class AuthenticatorServiceTest extends ServiceTestCase<AuthenticatorService> {

    private static String TAG = AuthenticatorServiceTest.class.getSimpleName();
    private AuthenticatorService mAuthenticatorService;

    public AuthenticatorServiceTest() {
        super(AuthenticatorService.class);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();
    }

    @Override
...
Mark M.
Guido: see you later!
Guido
has left the room
Mark M.
Svetlin: well, startService() is asynchronous
actually, perhaps not in ServiceTestCase
Svetlin S.
Really?! I'm very confused then, I thought it calls either onCreate or onStartCommand which are on the UI thread?
Mark M.
yes, but unit testing code is not on the UI thread
that's why you have to do the whole wait-for-idle-sync stuff in UI testing
personally, I haven't used ServiceTestCase
Svetlin S.
ServiceTestCase provides both a mock application and a mock context, correct?
Mark M.
if I understand the docs correctly, yes
I usually test what's inside the service separately, using something like AndroidTestCase if I need a Context for that
Svetlin S.
So from the point of view of ServiceTestCase isn't it that the behavior is the same "as if" it is running on a mock UI thread?
Mark M.
beats me
I can tell you that the activity TestCase classes don't work that way
Svetlin S.
The instrumented or the plain ones?
Mark M.
certainly ActivityInstrumentationTestCase2 has its test methods running on another thread
and, from what I can tell, the equivalents you run using AndroidJUnitRunner for JUnit4 support do the same
8:25 PM
Mark M.
my testing life is dominated by standard JUnit and AndroidTestCase, with sporadic uses of ActivityInstrumentationTestCase
(er, ActivityInstrumentationTestCase2)
I don't mess with the other Android test case base classses
that's not to say they're bad
Svetlin S.
I'm using JUnit3 for now. I wish there was somewhere a complete example of how to use ServiceTestCase?
Mark M.
I just don't use them
there's probably some floating around the CTS somewhere
Svetlin S.
CTS is what (sorry)?
Mark M.
Compatibility Test Suite
Svetlin S.
OK, I'll take a look.
Mark M.
it is what device manufacturers have to pass in order to qualify for the Google proprietary apps
a search on "extends ServiceTestCase" on Google turns up surprisingly few hits, though some may be useful to you
Svetlin S.
Got it. Thank you so much for your time, Mark, appreciated.
Mark M.
based on the hit count, it would appear I'm not the only one who skips ServiceTestCase...
Svetlin S.
Yeah, seems like it.
Thanks again. We actually met at the Google I/O a couple of years ago, BTW.
Thanks for the Warescription, appreciated.
Mark M.
you are very welcome
though I've skipped the past three I/O's
time flies when you're having fun and/or writing Android code :-)
8:30 PM
Svetlin S.
Me too, that was back in 2011, I think, when it was worth going...
Have a good one, bye.
Mark M.
that's a wrap for today's chat
the transcript will be posted to http://commonsware.com/office-hours/ shortly
the next chat is Tuesday at 4pm US Eastern
have a pleasant day!
Svetlin S.
has left the room
Mark M.
turned off guest access

Tuesday, February 24

 

Office Hours

People in this transcript

  • Guido
  • Mark Murphy
  • Susheel
  • Svetlin Stanchev