Note that there are some explanatory texts on larger screens.

plurals
  1. POIs AsyncTask really conceptually flawed or am I just missing something?
    primarykey
    data
    text
    <p>I have investigated this problem for months now, came up with different solutions to it, which I am not happy with since they are all massive hacks. I still cannot believe that a class that flawed in design made it into the framework and no-one is talking about it, so I guess I just must be missing something.</p> <p>The problem is with <code>AsyncTask</code>. According to the documentation it </p> <blockquote> <p>"allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers."</p> </blockquote> <p>The example then continues to show how some exemplary <code>showDialog()</code> method is called in <code>onPostExecute()</code>. This, however, seems <strong>entirely contrived</strong> to me, because showing a dialog always needs a reference to a valid <code>Context</code>, and an AsyncTask <em>must never hold a strong reference to a context object</em>.</p> <p>The reason is obvious: what if the activity gets destroyed which triggered the task? This can happen all the time, e.g. because you flipped the screen. If the task would hold a reference to the context that created it, you're not only holding on to a useless context object (the window will have been destroyed and <em>any</em> UI interaction will fail with an exception!), you even risk creating a memory leak.</p> <p>Unless my logic is flawed here, this translates to: <code>onPostExecute()</code> is entirely useless, because what good is it for this method to run on the UI thread if you don't have access to any context? You can't do anything meaningful here.</p> <p>One workaround would be to not pass context instances to an AsyncTask, but a <code>Handler</code> instance. That works: since a Handler loosely binds the context and the task, you can exchange messages between them without risking a leak (right?). But that would mean that the premise of AsyncTask, namely that you don't need to bother with handlers, is wrong. It also seems like abusing Handler, since you are sending and receiving messages on the same thread (you create it on the UI thread and send through it in onPostExecute() which is also executed on the UI thread).</p> <p>To top it all off, even with that workaround, you still have the problem that when the context gets destroyed, you have <em>no record</em> of the tasks it fired. That means that you have to re-start any tasks when re-creating the context, e.g. after a screen orientation change. This is slow and wasteful.</p> <p>My solution to this (as <a href="https://github.com/mttkay/droid-fu/" rel="noreferrer">implemented in the Droid-Fu library</a>) is to maintain a mapping of <code>WeakReference</code>s from component names to their current instances on the unique application object. Whenever an AsyncTask is started, it records the calling context in that map, and on every callback, it will fetch the current context instance from that mapping. This ensures that you will never reference a stale context instance <em>and</em> you always have access to a valid context in the callbacks so you can do meaningful UI work there. It also doesn't leak, because the references are weak and are cleared when no instance of a given component exists anymore.</p> <p>Still, it is a complex workaround and requires to sub-class some of the Droid-Fu library classes, making this a pretty intrusive approach.</p> <p><strong>Now I simply want to know:</strong> Am I just massively missing something or is AsyncTask really entirely flawed? How are your experiences working with it? How did you solve these problem?</p> <p>Thanks for your input.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload