Jan 29 | 8:55 AM |
Mark M. | has entered the room |
Mark M. | turned on guest access |
Mat | has entered the room |
Mark M. |
hello, Mat!
|
Mark M. |
how can I help you today?
|
Mat |
Hi there Mark
|
Mat |
I have a quick question that i'd like your feedback on
|
Mark M. |
go right ahead
|
Mat |
I have a custom ApplicationSession where i store various app data. All my activities inherit from a common superclass
|
Jan 29 | 9:00 AM |
Mat |
In that superclass, in the oncreate, i take out the applicationobject and cast it into a parameter that i then can use in the activity, like so appSession = (ApplicationSession) getApplication();
|
Mat |
then, in my fragments etc. i use main.getSession since i need it in lots of different places
|
Mat |
(main) being the activity where ive added a public accessor for my application object
|
Mat |
you with me so far?
|
Mark M. |
yes
|
Mat |
then. in my ondestroy() i set it to null. I did this years ago, but as far as i can remember i think its because i've read that sometimes activity objects are recycled and i wanted to make sure that the appsession wasn't lingering
|
Mark M. |
activity objects are not recycled
|
Mark M. |
that being said, setting fields to null is not harmful
|
Mat |
however, i have started having some threaded tasks that sometimes can take 10-15 seconds to complete. these tasks need that sessionobject. Therefor if the user exits while a task is running, the object is null and the app crashes currently. I'm thinking about how to fix it
|
Jan 29 | 9:05 AM |
Mark M. |
the task should hold onto a reference to the session
|
Mark M. |
Application objects live for the duration of the process
|
Mat |
yeah i guess. But do you think its risk-free to not set that variable to null on app exit?
|
Mark M. |
it's more that what you are describing is indicative of larger code issues
|
Mark M. |
a background thread should not have *any* reference to an activity
|
Mark M. |
at most, maybe some sort of WeakReference, but that's usually not all that useful
|
Mark M. |
so long as that thread is running, the activity cannot be GC'd, even though it is destroyed
|
Mark M. |
worse, various things that you might want to do with the activity will crash, because the activity is destroyed
|
Mat |
youre right ofc
|
Mark M. |
so, while not clearing that field is not itself an issue, the fact that you're thinking in terms of accessing that field *is* an issue, IMHO
|
Mat |
its basically a thread that does a network call, and i want to update applicationsession json structures when it is done
|
Mark M. |
the thread should have a reference to the session, not the activity that perhaps kicked off that thread
|
Mat |
what you are saying is that i should try and get rid of the need for the thread to even have a reference to the activity, and just have the appsession.
|
Mat |
:)
|
Mark M. |
right
|
Mat |
i have some debt that i havent had the time to address, basically
|
Jan 29 | 9:10 AM |
Mat |
one thing that i find mystifying - how about contexts? you know where you have to do activity.getcontext to look up strings etc. Are those context obects affected by activity lifecycle?
|
Mark M. |
um, well, that depends on what "affected" means
|
Mat |
let me elaborate
|
Mat |
i have a networkhandler object, which is a way of centralizing network requests. In my activity oncreate, i create that object and keep it around for as long as the activity is alive
|
Mat |
right now, i pass in the activity to the network handler. This is bad as we just discussed, but i did it way in the beginning, and haven't had the time to look at it... i code our ios and server side code as well.
|
Mat |
in the networkhandler i use the activity reference to look up strings, show dialogs etc.
|
Jan 29 | 9:15 AM |
Mat |
i guess i could keep a reference to a context instead and use that everywhere, right, and i would still be able to use it (i.e. at least not have the app crash) if the activity has been destroyed
|
Mark M. |
I would recommend an event bus
|
Mark M. |
the networkhandler should not be showing dialogs
|
Mark M. |
the networkhandler should be raising a ThisThingHappenedEvent
|
Mark M. |
if that is of relevance to the foreground activity, it subscribes to receive such events, and it raises the dialog
|
Mat |
yeah, i've done it that way in ios. i take it you mean that the thread should to broadcasts. i have that in some instances.
|
Mark M. |
LocalBroadcastManager is an event bus, though I personally use greenrobot's instead
|
Mat |
but it was so convenient to start and stop progressdialogs in the tasks preexecute and postexecute...
|
Mark M. |
an AsyncTask, managed by a retained fragment, might show dialogs in those places
|
Mark M. |
and, actually, I was misunderstanding -- I was thinking your networkhandler was of global scope, not per-activity
|
Mat |
here's basically what happens:
|
Mat |
1. user clicks on a button to do something in say one of my tabbed fragments.
|
Mat |
2. it knows about main (the parent activity), does getNetworkHandler().doThenetworkFetch();
|
Jan 29 | 9:20 AM |
Jamshaid A. | has entered the room |
Mat |
3. The network handler is basically a centralized class to have the network logic in one place. It created an asynctask (i have lots, logintask, fetchlocationsfetch etc)
|
Mark M. |
(BTW, hello, Jamshaid -- I will be with you shortly!)
|
Jamshaid A. |
thanks
|
Mat |
3. the tasks create progressdialogs on start, removes after. all tasks have some sort of delegate interface thats supposed to deal with the outcome (success/failure)
|
Mat |
4. the fragment itself could implement that delegate, evaluate and perhaps throw up a new dialog ("unable to fetch locations, network error" or something)
|
Mark M. |
well, it's tough to really give you much advice, as your scenario is rather complex, with lots of moving parts
|
Mat |
thats how it works now basically. and the problem is that main.getappsession sometimes is null when the locationfetch asynctask wants to update the appsession via main.getAppsession.updateLocations()
|
Mark M. |
the general rule is: never touch the activity from doInBackground() or other stuff on a background thread
|
Mark M. |
so, for this, you would want to have direct access to your session inside the task, not delegate to the activity
|
Mat |
yeah well :) you gave good advice. I should make sure that all just use a context and the appsession everywhere
|
Mat |
exactly. great stuff, i'll do that
|
Mark M. |
you can't show a dialog using an Application object
|
Mark M. |
anything involving the UI needs to work with the Activity via its retained fragment
|
Mark M. |
conversely, anything on the background thread should not be referencing the activity, as you do not know what state that activity might be in at the time
|
Mark M. |
and with that, let me take a question from Jamshaid, and I'll be back with you in a bit
|
Mat |
no worries
|
Mark M. |
Jamshaid: your turn! do you have a question?
|
Jan 29 | 9:25 AM |
Jamshaid A. |
View paste
|
Jamshaid A. |
now instead i got system licenses so can create a system app
|
Jamshaid A. |
i was wondering to have a structure where this system app always stays around if the system app crashes in this scenario as all other apps are deleted
|
Jamshaid A. |
the system should just restart this single app
|
Mark M. |
um, that's not really an application development question
|
Jamshaid A. |
i hope i make sense was wondering if u coudl give me some advice on the subject
|
Mark M. |
that's an Android OS/firmware question
|
Mark M. |
hence, I cannot help you directly
|
Jamshaid A. |
true
|
Mark M. |
you would need to discuss this with whoever is responsible for building the ROM on which your app is installed
|
Mark M. |
or, learn more about Android internals than I personally know
|
Jamshaid A. |
is it possible to declare an app manifest somethign that if it crashes that it just restarts
|
Mark M. |
no
|
Jamshaid A. |
another thing is it possible to not display the exception message
|
Jamshaid A. |
incase if there is one
|
Mark M. |
that you can handle yourself, by setting up a top-level uncaught exception handler
|
Jamshaid A. |
i am able to install uninstall apps n already thought of a system where one app acts as a launcher n other services communicate using an event bus
|
Jamshaid A. |
can u elaborate a bit further how i might be able to have a top level uncaught exception handler
|
Jan 29 | 9:30 AM |
Mark M. |
well, since you really still need to collect crash data, the best solution IMHO is for you to use a library like ACRA, and set it up to not show any UI for the exception
|
Mark M. |
I have a chapter on ACRA in the book
|
Mark M. |
under the covers, ACRA (and all crash-logging libraries) use setDefaultUncaughtExceptionHandler() on Thread
|
Mark M. |
that registers an UncaughtExceptionHandler, which is notified about all unhandled exceptions
|
ramsey | has entered the room |
Jamshaid A. |
thanks i will keep that in mind n get to it then ...
|
Mark M. |
let me take a question from ramsey, and I will be back with you shortly
|
Mark M. |
ramsey: your turn! do you have a question?
|
ramsey |
If I have a class A { protected x; } and a subclass B of A. Is there a way of defining what x is outside of a lifecycle method?
|
Mark M. |
well, B can access x whenever B wants to, in terms of Java access rules
|
ramsey |
I want to define x to be a stub that I then implement in the subclasses
|
ramsey |
But I suppose I have to do it inside a method rather than as part of the definition of class B right?
|
Mark M. |
well, it depends a lot on what x is
|
ramsey |
(In this case A and B are activities)
|
ramsey |
x is a callback that I have defined
|
Jan 29 | 9:35 AM |
Mark M. |
if the declaration of the subclass/implementation of your stub require access to methods implemented on Activity or superclasses (e.g., Context), then you should not assign a value to x until onCreate()
|
Jan 29 | 9:35 AM |
ramsey |
* x is an implemenation of an interface
|
Mark M. |
if, however, x is largely independent of that sort of thing when an instance is created, you could assign a value as part of initializing the field
|
Mark M. |
for example, pretend that x is an int, not some interface of your design
|
ramsey |
sure
|
Mark M. |
x=0 is fine
|
Mark M. |
x=getInt(R....) is not
|
Mark M. |
because getInt() won't work until we get to onCreate()
|
ramsey |
But would you have to define x=0 inside a method of B
|
Mark M. |
from a Java syntax standpoint, I don't think B can assign a value to x via an initializer
|
ramsey |
or can you write class A{ protected int x;}, class B extends A { x = 2;}
|
Mark M. |
it could in a constructor, but usually we do not implement constructors on activities
|
ramsey |
OK gotcha. It seemed a silly question but I was having a mind blank
|
Mark M. |
I doubt that your proposed syntax works, though I do not recall actually trying it
|
ramsey |
no I never have but I was confusing protected methods with fields. Silly me
|
ramsey |
Thanks mark
|
Mark M. |
no worries
|
Mark M. |
let me take questions from the others, and I'll come back to you in a bit
|
Mark M. |
Mat: your turn! do you have another question?
|
Jan 29 | 9:40 AM |
Mark M. |
Mat: if you come up with another question, let me know
|
Mark M. |
Jamshaid: back to you! do you have another question?
|
Jamshaid A. |
no thanks i just got the book n learned that u have a chat sesson.i will for now follow up on the acra crash reporting thing.but i join next week
|
Jamshaid A. |
thanks
|
Mark M. |
OK
|
Mark M. |
ramsey: back to you! do you have another question?
|
Mark M. |
OK, if anyone has a question, just chime in
|
Jan 29 | 9:50 AM |
ramsey | has left the room |
Mat |
hey mate had clients calling...
|
Mark M. |
no worries
|
Mat |
i guess i don't have more questions, but here's my action plan:
|
ramsey | has entered the room |
Mat |
1. i will not set the appsession to null in ondestroy. that will take care of the crash in the short run
|
Mat |
2. go through all my code and remove references to the activity in tasks etc.
|
Mat |
3. medium-term take a look at greenrobot, it looked really neat
|
Mat |
sound ok to you?
|
Mark M. |
sounds fine
|
Mat |
cheers. have a nice weekend!
|
Mark M. |
you too!
|
ramsey |
If I want to call a method every time the app opens from a terminated state is the place to do that in the Application subclass? (This is for syncing data with a server - I've found a SyncAdapter a bit ridic to use in the past)
|
Jan 29 | 9:55 AM |
Mark M. |
what is "a terminated state"?
|
ramsey |
yeah good question. This is the brief from an iOS dev. So I imagine we'd have to say not in Recents
|
Mark M. |
um
|
Mark M. |
onCreate() on Application will be called when the process is created
|
Mark M. |
so if "a terminated state" means "the process was terminated", then onCreate() on Application is one candidate
|
ramsey |
Right. Actually I have a BaseActivity and the callback for the sync call probably needs to be defined in an activity subclass
|
ramsey |
So maybe my solution is to set a static boolean in Application and in onResume(), say, use that boolean to decide whether to call the download method?
|
Mark M. |
um, I guess
|
Mark M. |
I don't really know enough about your app to say whether that would meet your needs or not
|
Jan 29 | 10:00 AM |
Jamshaid A. | has left the room |
ramsey |
Yeah fair. Sometimes a rubber duck is just useful
|
ramsey | |
ramsey |
Thanks Mark
|
ramsey |
Have a fab weekend. So appreciate all you do
|
Mark M. |
you are very welcome, even if you did just compare me to a children's toy, I think... :-)
|
Mark M. |
anyway, that's a wrap for today's chat
|
ramsey |
haha. affectionately though
|
Mark M. |
the next one is Tuesday at 7:30pm US Eastern
|
Mark M. |
(I bet you say that to *all* the ducks...)
|
Mark M. |
this chat's transcript will be posted to https://commonsware.com/office-hours/ shortly
|
Mark M. |
have a pleasant day!
|
Mat | has left the room |
ramsey | has left the room |
Mark M. | turned off guest access |