Mar 18 | 9:50 AM |
Mark M. | has entered the room |
Mark M. | turned on guest access |
Mar 18 | 9:55 AM |
Andrey | has entered the room |
Mark M. |
hello, Andrey!
|
Andrey |
Hello Mark
|
Mark M. |
how can I help you today?
|
Andrey |
I'm back with the same question as a week ago. Now I know a little but more
|
Andrey |
First activity of my app hosts a ListFragment that contains an EditText. When its text is changed, I load suggestions the Listview using AsyncTask. When a ListView item is tapped, I open another activity.
|
Andrey |
When I go back, I need to restore the EditText contents
|
Andrey |
You told me it should be saved and restored automatically.
|
Andrey |
Turns out it does
|
Andrey |
but only if I "commit" the text by tapping inside the textbox or tapping "Done"
|
Andrey |
I need to
|
Andrey |
oh , hut the entersorry
|
Andrey |
I can save the EditText contents in onSaveInstanceState
|
Mar 18 | 10:00 AM |
Andrey |
when I go to the second activity
|
Andrey |
but when fragment's onCreate is called upon returning
|
Andrey |
there is no bundle
|
Mark M. |
how are you "returning"?
|
Andrey |
BACK button
|
Mark M. |
are you just letting the user press BACK and go through normal activity flows?
|
Andrey |
yes
|
Andrey |
if I "commit" the text I can see it restored
|
Mark M. |
are you doing anything in onBackPressed() of the second activity, or otherwise trying to control what happens on a BACK press?
|
Andrey |
no
|
Mark M. |
well, then, onCreate() of the fragment should not be happening
|
Mark M. |
because the fragment should not be recreated
|
Mark M. |
because the first activity should not be recreated
|
Mark M. |
because the first activity didn't go anywhere, except on the task stack
|
Mark M. |
are you changing orientations or something while in the 2nd activity?
|
Andrey |
oh yes, I have heard something about it
|
Andrey |
No, I have the orientation fixed
|
Andrey |
on both activities
|
Mark M. |
that does not matter, from the standpoint of configuration changes
|
Mark M. |
android:orientation only controls visual output
|
Mark M. |
if the user rotates the screen, the configuration still changes
|
Mark M. |
even if visually there is no difference in the result
|
Andrey |
are android:orientation and android:screenOrientation the same?
|
Mark M. |
oh, yes, sorry, I meant android:screenOrientation
|
Mar 18 | 10:05 AM |
Mark M. |
I rarely use that attribute and forgot its name
|
Mark M. |
so, I would focus on *why* the fragment is being called with onCreate()
|
Mark M. |
there should be no need to restore the EditText, because the EditText did not go anywhere
|
Mark M. |
it feels like something is forcing your activity to be recreated
|
Mark M. |
which should not be needed
|
Mark M. |
and depending upon how that happens, it could wipe out your saved instance state
|
Mark M. |
I cannot explain the difference between tapping "Done" or not, though
|
Andrey |
Here's now I associate the fragment with its activity
|
Andrey |
View paste
|
Andrey |
Is it correct?
|
Mark M. |
there is nothing obviously wrong with that
|
Mark M. |
assuming that you are calling it in onCreate() of the activity
|
Mark M. |
however, onCreate() of the first activity should not be called when returning to it from the second activity
|
Andrey |
yes
|
Mar 18 | 10:10 AM |
Andrey |
and all I do in the fragment is add TextChangedListener in OnCreateView
|
Andrey |
no other lifecycle methods
|
Andrey |
other that onCreateView and onActivityCreated
|
Andrey |
Actually
|
Andrey |
I don't know about the first activity's onCreate
|
Andrey |
it's fragment's onCreate where I expect to find a state bundle
|
Andrey |
that's the one I log
|
Mark M. |
then you need to determine what is triggering onCreate() of your fragment
|
Mark M. |
I would expect that to be called due to the FragmentTransaction
|
Andrey |
The one I posted before?
|
Mark M. |
yes
|
Mar 18 | 10:15 AM |
Andrey |
Assuming I can get "uncommitted" text in onSaveInstanceState()
|
Andrey |
can I save it somewhere
|
Andrey |
even in SharesPreferences
|
Mark M. |
sure, but all you are doing is avoiding debugging the real problem
|
Mark M. |
the real problem appears to be that your fragment is being re-created, when it should not be
|
Mark M. |
that, in turn, may cause you difficulty employing workarounds like the ones you describe
|
Mar 18 | 10:20 AM |
Andrey |
but when my first activity is getting on top again, isn't its onCreate() called?
|
Mark M. |
no
|
Mark M. |
onStart() and onResume() will
|
Mark M. |
but the activity should already exist
|
Andrey |
according to the scheme in developer's guide
|
Mark M. |
and hence is already created
|
Andrey |
sorry
|
Andrey |
I see it now
|
Mar 18 | 10:25 AM |
Andrey |
Stripped my app to the bare minimum and still can't see what's wrong
|
Andrey |
But I have noticed something
|
Andrey |
So I start the first activity. There is a focus in an edittext
|
Drasko | has entered the room |
Andrey |
And there's a hint
|
Drasko |
Hi, guys!
|
Mark M. |
(hello, Drasko: I will be with you shortly!)
|
Andrey |
I start typing and the text I entered is still styled as a hint
|
Andrey |
this text is not getting saved for some reason
|
Andrey |
When I tap inside, it turns black as it should be
|
Mark M. |
Andrey: what are you testing this on? emulator? device?
|
Andrey |
and it is persisted afterwards
|
Andrey |
device
|
Mark M. |
try with an x86 emulator, or another device if you have a second one
|
Mark M. |
to rule out any manufacturer-created EditText bugs
|
Mark M. |
as manufacturers have this annoying tendency to mess with EditText behavior
|
Mark M. |
and that could be part of your problem
|
Andrey |
I'll try with the emulator
|
Drasko |
genymotion is perfect solution. :)
|
Mar 18 | 10:30 AM |
Mark M. |
Andrey: I will swing back to you in a bit
|
Mark M. |
Drasko: do you have a question?
|
Drasko |
yes, but it's conceptual one.
|
Drasko |
I just wanted to ask, what are your thoughts on using ContentProvider for database access in scenario where you want to use data from it just for your app?
|
Mark M. |
personally, I'
|
Mark M. |
personally, I'm not a big fan
|
Mark M. |
I'd rather hit the database directly
|
Drasko |
why?
|
Mark M. |
as you cannot do JOINs, use aggregate functions, etc. very conveniently via a ContentProvider
|
Mark M. |
ContentProvider works a lot like a REST interface
|
Mark M. |
the consumer can only consume readily what the publisher publishes
|
Mark M. |
so, if you want to do a JOIN, you have to implement that in the ContentProvider, using some distinct Uri structure
|
Mark M. |
that's certainly doable
|
Mark M. |
but the only particular advantage I see for using a ContentProvider internally is to be able to use ContentObserver
|
Mark M. |
and I'd rather use my own event bus
|
Drasko |
so, actually, you are using loaders in your own AsyncTasks, right?
|
Mark M. |
no
|
Mark M. |
I use AsyncTasks (or something else asynchronous)
|
Mark M. |
but not loaders
|
Mark M. |
as CursorLoader only works with ContentProviders
|
Mark M. |
and the Loader abstraction sucks for anything else
|
Mark M. |
I even tried making my own loaders for SQLite (see CWAC-LoaderEx), and while it works, it's clunky
|
Mar 18 | 10:35 AM |
Drasko |
Yes, I saw it.
|
Drasko |
So you just basically just do direct queries in your AsyncTasks?
|
Mark M. |
more or less
|
Drasko |
That means that you have another piece of code to maintain, right?
|
Mark M. |
the entire program is "another piece of code to maintain"
|
Drasko |
:)
|
Mark M. |
a ContentProvider does not spring forth from the brow of Zeus
|
Mark M. |
somebody writes it
|
Mark M. |
if that somebody is me, then I have to maintain it
|
Mark M. |
if I choose to organize my code differently, to avoid the ContentProvider, then I have to maintain that code
|
Drasko |
yes, of course, I was just bringing pros for using CPs...
|
Mark M. |
a CP is not going to reduce code
|
Mar 18 | 10:40 AM |
Mark M. |
or, to the extent it does, you could accomplish the same reduction in other ways
|
Mark M. |
(e.g., consolidate query implementation in a data access layer)
|
Mark M. |
where it *does* reduce code is in cross-process communication
|
Drasko |
I understand.
|
Mark M. |
for communication within a process, you're welcome to use a CP if you want
|
Mark M. |
but, you asked me what *I* do, and I wouldn't use a CP in that case
|
Mark M. |
there are Android experts who love CP for internal use
|
Mark M. |
so my opinion is just that: my opinion
|
Drasko |
Of course, that's why I asked you, since I appreaciate your opinion.
|
Drasko |
:)
|
Mark M. |
Drasko: I will be back with you in a bit
|
Mark M. |
Andrey: do you have another question?
|
Andrey |
My database initialization is painfully slow on the emulator. I wouldn't know about the EditText behaviour for a few more minutes.
|
Andrey |
No more questions yet
|
Mark M. |
the x86 emulator should not be that bad
|
Andrey |
But I was wondering about ContentProviders thing too :)
|
Mark M. |
and if it is, and your problem is in database initialization, you may run into similar problems on some hardward
|
Mar 18 | 10:45 AM |
Mark M. |
er, hardware
|
Mark M. |
if anything, disk access on an emulator is faster than on production hardware, because most Android devices' on-board flash is cheap (and, hence, slow)
|
Mark M. |
Drasko: do you have another question?
|
Andrey |
yes, I was thinking about it too
|
Drasko |
no, thanks.
|
Andrey |
my phone is fast
|
Andrey |
if anything, it's just one-time initialization
|
Mark M. |
OK, if either of you come up with another question, just chime in
|
Andrey |
maybe user will be willing to wait
|
Andrey |
So, I shouldn't count on emulators when performance testing, should I?
|
Mark M. |
no
|
Mark M. |
at least in terms of measuring real-world performance
|
Mark M. |
in terms of measuring performance differences (i.e., is Implementation B better than Implementation A), it can still be useful
|
Mark M. |
what are you doing in this one-time initialization?
|
Mar 18 | 10:50 AM |
Andrey |
populating the database
|
Mar 18 | 10:50 AM |
Mark M. |
how are you populating it?
|
Andrey |
19000 rows
|
Andrey |
reading from the text file and doing some normalization
|
Mark M. |
gadzooks
|
Mark M. |
I wouldn't do that
|
Mark M. |
unless the only source of the text file is via some Internet operation
|
Andrey |
no, it's in the raw resources
|
Mark M. |
if you are packaging the text file with the app, I'd use SQLiteAssetHelper and ship the database already populated
|
Mark M. |
much, much faster
|
Andrey |
It would weight 3 times more
|
Mark M. |
so?
|
Andrey |
I thought it might scare some users
|
Andrey |
maybe I'm just being silly here :)
|
Mark M. |
versus scaring all of them by importing 19,000 rows on first run?
|
Mark M. |
I mean, 19,000 insert statements, even with max optimizations (transactions, etc.) is going to be slow
|
Andrey |
yes Mark
|
Andrey |
you are right, I should try SQLiteAssetHelper
|
Mark M. |
it's at least worth an experiment
|
Andrey |
I've come across it before, but decided to do it my way
|
Mar 18 | 10:55 AM |
Mark M. |
if you are going to start bumping up against hard size limits (e.g., Play Store 50MB), then SQLiteAssetHelper may not be an option
|
Andrey |
no, just about 15
|
Andrey |
I'm having some problems with Eclipse, so I'll be back with the EditText question the next time, if you wouldn't mind :)
|
Andrey |
Is it tomorrow?
|
Mark M. |
no, the next chat is Thursday at 4pm US Eastern Time
|
Drasko |
what could be solution when SQliteAssetHelper is not an option.
|
Mark M. |
Drasko: you could download the SQLite database, or package it in an APK expansion file
|
Andrey |
Okay see you Thursday
|
Drasko |
Bye.
|
Andrey |
Thanks a lot for your help Mark
|
Mark M. |
you are very welcome
|
Mark M. |
note that the chat transcript will appear on http://commonsware.com/office-hours/ in a few minutes
|
Andrey | has left the room |
Drasko | has left the room |
Mark M. | turned off guest access |