Still adjusting to the changes in Android 4.0 regarding AsyncTask.
If I understand right, the default behavior of execute is changing to one single thread pool with only one thread? With the reason cited that programmers are not capable of handling a bigger threadpool (I'm paraphrasing).
Does that mean, that absent some code changes, all asynctasks inside a process will only happen sequentially?
So therefore, if I have a service running DownloadDictionaryTask in the background, and the user chooses a menu item that starts CheckDiskSpaceTask, the progress bar will cycle without any progress because the task never makes progress?
A user and I could briefly reproduce a situation where, as far as I could tell, no asynctasks were running, yet my AsyncTask would not even start. In this case, I couldn't even get one thread. Alas, I cannot reproduce that situation, which appeared to fix itself without any code changes.
But in any case, this isn't really acceptable to have only one asynctask task run at once. But there is no central way to control that behavior, is there? I would have to replace 83 instances of task.execute with task.executeonExecutor. Since the above method is only available in SDK>11, this isn't a one line change - it's more like 10-20 lines of code with reflection, and some extensive testing.
In my opinion, this a deplorable punishment for those developers who have dutifully followed the AsyncTask pattern, which, to this day, the Android platform has encouraged.
Or perhaps I am reading this wrong. Maybe all DownloadDictionaryTasks share one pool, and all CheckDiskSpaceTasks share another pool. In that case, the rule is that only one task *of the same concrete type* can run at once. This rule, I can probably live with, as I've used my own threading pools for tasks that are truly data parallel.
> Still adjusting to the changes in Android 4.0 regarding AsyncTask.
> If I understand right, the default behavior of execute is changing to one
> single thread pool with only one thread? With the reason cited that
> programmers are not capable of handling a bigger threadpool (I'm
> paraphrasing).
> Does that mean, that absent some code changes, all asynctasks inside a
> process will only happen sequentially?
> So therefore, if I have a service running DownloadDictionaryTask in the
> background, and the user chooses a menu item that starts
> CheckDiskSpaceTask, the progress bar will cycle without any progress
> because the task never makes progress?
> A user and I could briefly reproduce a situation where, as far as I could
> tell, no asynctasks were running, yet my AsyncTask would not even start. In
> this case, I couldn't even get one thread. Alas, I cannot reproduce that
> situation, which appeared to fix itself without any code changes.
> But in any case, this isn't really acceptable to have only one asynctask
> task run at once. But there is no central way to control that behavior, is
> there? I would have to replace 83 instances of task.execute with
> task.executeonExecutor. Since the above method is only available in SDK>11,
> this isn't a one line change - it's more like 10-20 lines of code with
> reflection, and some extensive testing.
> In my opinion, this a deplorable punishment for those developers who have
> dutifully followed the AsyncTask pattern, which, to this day, the Android
> platform has encouraged.
> Or perhaps I am reading this wrong. Maybe all DownloadDictionaryTasks
> share one pool, and all CheckDiskSpaceTasks share another pool. In that
> case, the rule is that only one task *of the same concrete type* can run at
> once. This rule, I can probably live with, as I've used my own threading
> pools for tasks that are truly data parallel.
> Can anyone enlighten me more?
> Nathan
> --
> You received this message because you are subscribed to the Google
> Groups "Android Developers" group.
> To post to this group, send email to android-developers@googlegroups.com
> To unsubscribe from this group, send email to
> android-developers+unsubscribe@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/android-developers?hl=en
On Fri, Apr 20, 2012 at 3:16 PM, Nathan <nathan.d.mel...@gmail.com> wrote: > If I understand right, the default behavior of execute is changing to one > single thread pool with only one thread?
I have not been able to confirm that this change is in place. When I try testing a bunch of tasks, they seem to execute in parallel, even on 4.0.3 (haven't tried 4.0.4 yet).
> Does that mean, that absent some code changes, all asynctasks inside a > process will only happen sequentially?
Once this change takes effect (if it has not already), then yes.
> So therefore, if I have a service running DownloadDictionaryTask in the > background, and the user chooses a menu item that starts CheckDiskSpaceTask, > the progress bar will cycle without any progress because the task never > makes progress?
Yes. Either use the supplied pooled executor with executeOnExecutor(), or move one of those things out of AsyncTask (e.g., DownloadDictionaryTask might be better as an IntentService, if it is supposed to keep rolling even if the user leaves the app).
> A user and I could briefly reproduce a situation where, as far as I could > tell, no asynctasks were running, yet my AsyncTask would not even start. In > this case, I couldn't even get one thread. Alas, I cannot reproduce that > situation, which appeared to fix itself without any code changes.
If you come up with a reproducible scenario that demonstrates that the default executor is the single-threaded one, I'd be interested in taking a peek at it.
> But in any case, this isn't really acceptable to have only one asynctask > task run at once. But there is no central way to control that behavior, is > there? I would have to replace 83 instances of task.execute with > task.executeonExecutor. Since the above method is only available in SDK>11, > this isn't a one line change - it's more like 10-20 lines of code with > reflection, and some extensive testing.
You wouldn't necessarily need to use reflection. Set your build target to 11+ and create your own static execute() method somewhere that, based on API level, uses execute() or executeOnExecutor() directly. It's a code change, though, regardless.
Another possibility would be for you to grab an older AsyncTask out of github.com/android, refactor it into your own package, and change your import statements to use it instead of the stock AsyncTask.
> In my opinion, this a deplorable punishment for those developers who have > dutifully followed the AsyncTask pattern, which, to this day, the Android > platform has encouraged.
You certainly won't get any argument from me on this. My gast was most certainly flabbered when Romain Guy mentioned this possibility a year-plus ago.
> Or perhaps I am reading this wrong. Maybe all DownloadDictionaryTasks share > one pool, and all CheckDiskSpaceTasks share another pool.
The pool is static at the AsyncTask level. Hence, all subclasses share a single pool, unless I'm seriously missing something.
20 апреля 2012 г. 23:29 пользователь Mark Murphy
<mmur...@commonsware.com>написал:
> On Fri, Apr 20, 2012 at 3:16 PM, Nathan <nathan.d.mel...@gmail.com> wrote:
> > If I understand right, the default behavior of execute is changing to one
> > single thread pool with only one thread?
> I have not been able to confirm that this change is in place. When I
> try testing a bunch of tasks, they seem to execute in parallel, even
> on 4.0.3 (haven't tried 4.0.4 yet).
The default is definitely serial on my GNex with 4.0.2.
Did they revert it again for the 4.0.3 that you have?
public class ParallelTasksActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
new SillyTask().execute("A"); new SillyTask().execute("B"); new SillyTask().execute("C"); new SillyTask().execute("D"); new SillyTask().execute("E"); }
class SillyTask extends AsyncTask<String, String, Void> { @Override protected Void doInBackground(String... params) { for (int i=0; i < 5; i++) { String msg=params[0] + String.valueOf(i);
Now, if AsyncTask executes serially, I would expect:
A0 A1 A2 A3 A4 B0 B1 B2 B3 B4 ...
Even if the letters were out of order (e.g., C before A), the numerical index would be in order, because the task would be tying up the one-and-only thread, so there should be no interleaving between letter.
04-20 20:20:02.886: D/ParallelTasks(3044): D started 04-20 20:20:02.898: D/ParallelTasks(3044): B started 04-20 20:20:02.898: D/ParallelTasks(3044): A started 04-20 20:20:02.898: D/ParallelTasks(3044): E started 04-20 20:20:02.898: D/ParallelTasks(3044): C started 04-20 20:20:12.898: D/ParallelTasks(3044): A ended 04-20 20:20:12.902: D/ParallelTasks(3044): C ended 04-20 20:20:12.910: D/ParallelTasks(3044): D ended 04-20 20:20:12.914: D/ParallelTasks(3044): B ended 04-20 20:20:12.918: D/ParallelTasks(3044): E ended
All five start, 10 seconds elapses, and all five end, indicating that they are running in parallel.
On Friday, April 20, 2012 12:29:24 PM UTC-7, Mark Murphy (a Commons Guy) wrote:
> On Fri, Apr 20, 2012 at 3:16 PM, Nathan wrote: > > If I understand right, the default behavior of execute is changing to one > > single thread pool with only one thread?
> I have not been able to confirm that this change is in place. When I > try testing a bunch of tasks, they seem to execute in parallel, even > on 4.0.3 (haven't tried 4.0.4 yet).
I don't download the source myself, but if this source listing is accurate, it must be fully in place.
> Yes. Either use the supplied pooled executor with executeOnExecutor(), > or move one of those things out of AsyncTask (e.g., > DownloadDictionaryTask might be better as an IntentService, if it is > supposed to keep rolling even if the user leaves the app).
I sure hope they won't be messing with the threadpool for intentservices too.
On Fri, Apr 20, 2012 at 4:26 PM, Nathan <nathan.d.mel...@gmail.com> wrote: > I don't download the source myself, but if this source listing is accurate, > it must be fully in place.
I've seen that, which is why I can't explain what I'm seeing at runtime.
> I sure hope they won't be messing with the threadpool for intentservices > too.
IntentService does not have a thread pool. IntentService has always had just one thread. Now, if you have several IntentServices in an app, they will all have independent threads.
21 апреля 2012 г. 0:36 пользователь Nathan <nathan.d.mel...@gmail.com>написал:
> It's not quite so easy for a project that wants to run on pre 3.0 > platforms. If you have an elegant solution for that, it will save me some > time.
Idea 1: Write a wrapper method in a utility class somewhere... replace direct calls to execute with the one line call to this method
Idea 2: Use Mark's suggestion grab AsyncTask sources and embed it in your own app so you'll have control over this.
Idea 3: Don't use AsyncTask... but then you'll need a replacement, and it's probably easiest to use idea 2 rather than starting from scratch.
> -- > You received this message because you are subscribed to the Google > Groups "Android Developers" group. > To post to this group, send email to android-developers@googlegroups.com > To unsubscribe from this group, send email to > android-developers+unsubscribe@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/android-developers?hl=en
Running your code on my GNex with official 4.0.2 I get this:
04-21 00:41:08.327 I/ParallelTasks(14355): A started 04-21 00:41:18.335 I/ParallelTasks(14355): A ended 04-21 00:41:18.335 I/ParallelTasks(14355): B started 04-21 00:41:28.335 I/ParallelTasks(14355): B ended 04-21 00:41:28.335 I/ParallelTasks(14355): C started 04-21 00:41:38.343 I/ParallelTasks(14355): C ended 04-21 00:41:38.343 I/ParallelTasks(14355): D started 04-21 00:41:48.335 I/ParallelTasks(14355): D ended 04-21 00:41:48.343 I/ParallelTasks(14355): E started 04-21 00:41:58.343 I/ParallelTasks(14355): E ended
04-21 01:10:32.900 I/ParallelTasks( 1002): A started 04-21 01:10:32.900 I/ParallelTasks( 1002): B started 04-21 01:10:32.910 I/ParallelTasks( 1002): D started 04-21 01:10:32.910 I/ParallelTasks( 1002): E started 04-21 01:10:32.910 I/ParallelTasks( 1002): C started 04-21 01:10:42.910 I/ParallelTasks( 1002): B ended 04-21 01:10:42.910 I/ParallelTasks( 1002): C ended 04-21 01:10:42.910 I/ParallelTasks( 1002): A ended 04-21 01:10:42.910 I/ParallelTasks( 1002): E ended 04-21 01:10:42.910 I/ParallelTasks( 1002): D ended
-- K
21 апреля 2012 г. 0:21 пользователь Mark Murphy <mmur...@commonsware.com>написал:
Yes if your targetSdkVersion is >= 12, then as of that release the default executor is serial.
This change was made because we realized we had a lot of bugs in the platform itself where async tasks where created that had implicit ordering dependences, so with the default parallel execution there were subtle rare bugs that would result.
I can't address how much smarter you are than the rest of us, but I am pretty convinced that for the vast majority of us the best thing to do is have the default here be safe, allowing developers to change it for the specific cases where they don't want that behavior.
This is a lesson I seem to learn every few years: multithreading is hard. Once you think you now understand it and are an expert, you are heading soon to another painful lesson that multithreading is hard.
Having an API to set the default executor back to parallel is not a solution, because it just gives you an easy way to create the exact same problems we are trying to fix. For example, if you have an async task that executes due to some user input to update some data, there is a very very good chance that if you allow these to be parallel you will have a bug.
Even with something as simple as a check box (which is one of the real cases that drove this change) you can have this problem. If you run an executor to save to disk the new state of the check box, there *are* situations where if you tap long enough and the CPU is loaded in the right way, you will end up with the first state being saved after the second.
So, yes, the default is serial, and you must explicitly decide when to use a parellel executor. You should only use a parallel executor when you know this is what you want and it is safe: when it is something that can take a significant amount of time, and you know has no dependencies with any other background tasks you may execute. So in your example here, the solution is to run your download task with AsyncTask.THREAD_POOL_EXECUTOR and leave the others with the default serial executor.
On Fri, Apr 20, 2012 at 12:16 PM, Nathan <nathan.d.mel...@gmail.com> wrote: > Still adjusting to the changes in Android 4.0 regarding AsyncTask.
> If I understand right, the default behavior of execute is changing to one > single thread pool with only one thread? With the reason cited that > programmers are not capable of handling a bigger threadpool (I'm > paraphrasing).
> Does that mean, that absent some code changes, all asynctasks inside a > process will only happen sequentially?
> So therefore, if I have a service running DownloadDictionaryTask in the > background, and the user chooses a menu item that starts > CheckDiskSpaceTask, the progress bar will cycle without any progress > because the task never makes progress?
> A user and I could briefly reproduce a situation where, as far as I could > tell, no asynctasks were running, yet my AsyncTask would not even start. In > this case, I couldn't even get one thread. Alas, I cannot reproduce that > situation, which appeared to fix itself without any code changes.
> But in any case, this isn't really acceptable to have only one asynctask > task run at once. But there is no central way to control that behavior, is > there? I would have to replace 83 instances of task.execute with > task.executeonExecutor. Since the above method is only available in SDK>11, > this isn't a one line change - it's more like 10-20 lines of code with > reflection, and some extensive testing.
> In my opinion, this a deplorable punishment for those developers who have > dutifully followed the AsyncTask pattern, which, to this day, the Android > platform has encouraged.
> Or perhaps I am reading this wrong. Maybe all DownloadDictionaryTasks > share one pool, and all CheckDiskSpaceTasks share another pool. In that > case, the rule is that only one task *of the same concrete type* can run at > once. This rule, I can probably live with, as I've used my own threading > pools for tasks that are truly data parallel.
> Can anyone enlighten me more?
> Nathan
> -- > You received this message because you are subscribed to the Google > Groups "Android Developers" group. > To post to this group, send email to android-developers@googlegroups.com > To unsubscribe from this group, send email to > android-developers+unsubscribe@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/android-developers?hl=en
Note: please don't send private questions to me, as I don't have time to provide private support, and so won't reply to such e-mails. All such questions should be posted on public forums, where I and others can see and answer them.
On Fri, Apr 20, 2012 at 5:24 PM, Dianne Hackborn <hack...@android.com> wrote: > Yes if your targetSdkVersion is >= 12, then as of that release the default > executor is serial.
Bingo! It's the targetSdkVersion that's controlling the behavior. Looking at the AsyncTask source code, I can't quite see how that's happening, but at least I can confirm the results.
Though for me, the serialized behavior does not kick in until a targetSdkVersion of 13 -- 12 still gives me parallel operation.
Sorry yes it is API 13, I turned around the logic of the code when I glanced at it:
// If the app is Honeycomb MR1 or earlier, switch its AsyncTask // implementation to use the pool executor. Normally, we use the // serialized executor as the default. This has to happen in the // main thread so the main looper is set right. if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) { AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }
On Fri, Apr 20, 2012 at 2:31 PM, Mark Murphy <mmur...@commonsware.com>wrote:
> On Fri, Apr 20, 2012 at 5:24 PM, Dianne Hackborn <hack...@android.com> > wrote: > > Yes if your targetSdkVersion is >= 12, then as of that release the > default > > executor is serial.
> Bingo! It's the targetSdkVersion that's controlling the behavior. > Looking at the AsyncTask source code, I can't quite see how that's > happening, but at least I can confirm the results.
> Though for me, the serialized behavior does not kick in until a > targetSdkVersion of 13 -- 12 still gives me parallel operation.
> _The Busy Coder's Guide to Android Development_ Version 3.7 Available!
> -- > You received this message because you are subscribed to the Google > Groups "Android Developers" group. > To post to this group, send email to android-developers@googlegroups.com > To unsubscribe from this group, send email to > android-developers+unsubscribe@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/android-developers?hl=en
Note: please don't send private questions to me, as I don't have time to provide private support, and so won't reply to such e-mails. All such questions should be posted on public forums, where I and others can see and answer them.
> Sorry yes it is API 13, I turned around the logic of the code when I > glanced at it:
> // If the app is Honeycomb MR1 or earlier, switch its AsyncTask > // implementation to use the pool executor. Normally, we use the > // serialized executor as the default. This has to happen in the > // main thread so the main looper is set right. > if (data.appInfo.targetSdkVersion <= > android.os.Build.VERSION_CODES.HONEYCOMB_MR1) { > AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR); > }
> On Fri, Apr 20, 2012 at 2:31 PM, Mark Murphy <mmur...@commonsware.com>wrote:
>> On Fri, Apr 20, 2012 at 5:24 PM, Dianne Hackborn <hack...@android.com> >> wrote: >> > Yes if your targetSdkVersion is >= 12, then as of that release the >> default >> > executor is serial.
>> Bingo! It's the targetSdkVersion that's controlling the behavior. >> Looking at the AsyncTask source code, I can't quite see how that's >> happening, but at least I can confirm the results.
>> Though for me, the serialized behavior does not kick in until a >> targetSdkVersion of 13 -- 12 still gives me parallel operation.
>> _The Busy Coder's Guide to Android Development_ Version 3.7 Available!
>> -- >> You received this message because you are subscribed to the Google >> Groups "Android Developers" group. >> To post to this group, send email to android-developers@googlegroups.com >> To unsubscribe from this group, send email to >> android-developers+unsubscribe@googlegroups.com >> For more options, visit this group at >> http://groups.google.com/group/android-developers?hl=en
> Note: please don't send private questions to me, as I don't have time to > provide private support, and so won't reply to such e-mails. All such > questions should be posted on public forums, where I and others can see and > answer them.
> -- > You received this message because you are subscribed to the Google > Groups "Android Developers" group. > To post to this group, send email to android-developers@googlegroups.com > To unsubscribe from this group, send email to > android-developers+unsubscribe@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/android-developers?hl=en
On Friday, 20 April 2012 23:24:34 UTC+2, Dianne Hackborn wrote:
> Yes if your targetSdkVersion is >= 12, then as of that release the default > executor is serial.
> This change was made because we realized we had a lot of bugs in the > platform itself where async tasks where created that had implicit ordering > dependences, so with the default parallel execution there were subtle rare > bugs that would result.
While I understand why this change why made it introduced some subtle bugs in apps running on ICS with the SerialExecutor vs the the Threaded Executor. It is unfortunate and I'm not sure it was a wise decision to change such an important behaviour that late.
Notably, lots of app uses AsyncTask to do networking I/O for which you can spend quite a lot of time in doInBackground() for example if the connection timeout or is very slow. This is not uncommon on mobile networks. Consider such an AsyncTask blocked for several seconds (maybe 20s or 30s) in doInBackground(). With the serial executor it blocks *all pending* AsyncTask in the queue until it finishes. So it can give to the user the app is frozen or that something that should happening or be updated isn't. That's a new kind of ANR without an actual ANR.
To summarize, all apps who used AsyncTask assuming parallel execution are possibly broken if doInBackground() does not finishes quick. When I explained this to a well know Google engineer, I was told : "You fool! thou shall use AsyncTask only for short lived task! Use your own AsyncTask replacement for long-running parallel tasks". Don't get even me started on the scientific definition of "short lived task"...
In the end since I knew why I need the ThreadDed executor, I just wrapped all my AsyncTask execution with this function:
On Fri, Apr 20, 2012 at 6:26 PM, b0b <pujos.mich...@gmail.com> wrote: > Conclusion: there's probably man apps broken in subtle ways on ICS because > of this change.
Probably not, only because they have to explicitly set the targetSdkVersion to 13+, and I don't know how many people are setting it that high.
That being said, it's a fairly significant change for something as subtle as slightly increasing the targetSdkVersion, which is why we need to make sure everyone knows about this. I agree with Kostya's comment regarding docs -- at this point, I think an Android Developers Blog post is probably needed.
Note: please don't send private questions to me, as I don't have time to provide private support, and so won't reply to such e-mails. All such questions should be posted on public forums, where I and others can see and answer them.
On Fri, Apr 20, 2012 at 3:26 PM, b0b <pujos.mich...@gmail.com> wrote: > While I understand why this change why made it introduced some subtle bugs > in apps running on ICS with the SerialExecutor vs the the Threaded Executor. > It is unfortunate and I'm not sure it was a wise decision to change such > an important behaviour that late.
We were very careful to not change the behavior for any existing apps. It only changes once you update your app and explicitly set your targetSdkVersion to indicate you are compatible with the version of Android where the change occurred. This is standard practice we use frequently when making changes to the platform that impact behavior applications may be relying on.
Note: please don't send private questions to me, as I don't have time to provide private support, and so won't reply to such e-mails. All such questions should be posted on public forums, where I and others can see and answer them.
To complete on this topic, I think it would be very useful to post an article on this issue on the developer's blog, asking developers whose app run on APi 13+ to review all their AsyncTask execute() code to check if it can use the default Executor or if it must use the Threaded Executor, for example in the case of doing networking I/O or other possibly time consuming tasks.
On Friday, April 20, 2012 3:26:26 PM UTC-7, b0b wrote:
> On Friday, 20 April 2012 23:24:34 UTC+2, Dianne Hackborn wrote:
>> Yes if your targetSdkVersion is >= 12, then as of that release the >> default executor is serial.
>> This change was made because we realized we had a lot of bugs in the >> platform itself where async tasks where created that had implicit ordering >> dependences, so with the default parallel execution there were subtle rare >> bugs that would result.
> While I understand why this change why made it introduced some subtle bugs > in apps running on ICS with the SerialExecutor vs the the Threaded Executor. > It is unfortunate and I'm not sure it was a wise decision to change such > an important behaviour that late.
> Notably, lots of app uses AsyncTask to do networking I/O for which you can > spend quite a lot of time in doInBackground() for example if the connection > timeout or is > very slow. This is not uncommon on mobile networks. > Consider such an AsyncTask blocked for several seconds (maybe 20s or 30s) > in doInBackground(). With the serial executor it blocks *all pending* > AsyncTask in the queue until it finishes. > So it can give to the user the app is frozen or that something that should > happening or be updated isn't. That's a new kind of ANR without an actual > ANR.
> To summarize, all apps who used AsyncTask assuming parallel execution are > possibly broken if doInBackground() does not finishes quick. > When I explained this to a well know Google engineer, I was told : "You > fool! thou shall use AsyncTask only for short lived task! Use your own > AsyncTask replacement for long-running parallel tasks". Don't get even me > started on the scientific definition of "short lived task"...
B0b's concerns echo my own.
If you don't use an AsyncTask, you'll get an ANR. But if you do, you have a progress bar that never moves because something else is running, and the users will think it is frozen.
Nowhere have I been told that AsyncTasks were only for short lived tasks (like a few seconds). I have used it for longer tasks. And I've never really assumed that it was safe to use it for task with dependencies between them.
If the platform is using the AsyncTask internally, it better be short lived tasks.
Nonetheless, I can't disagree with Diane's lesson that multithreading is hard. But the other thing I've learned about threads is that I always seem to need more of them.
21 апреля 2012 г. 2:39 пользователь Mark Murphy
<mmur...@commonsware.com>написал:
> On Fri, Apr 20, 2012 at 6:26 PM, b0b <pujos.mich...@gmail.com> wrote:
> > Conclusion: there's probably man apps broken in subtle ways on ICS
> because
> > of this change.
> Probably not, only because they have to explicitly set the
> targetSdkVersion to 13+, and I don't know how many people are setting
> it that high.
I do for one of my apps :)
But then I don't use AsyncTask at all.
The thread pool thing seemed unrealiable to me back in the 2.* days...
Besides, my threading logic is typically either too simple for AsyncTask,
or too complex :)
> That being said, it's a fairly significant change for something as
> subtle as slightly increasing the targetSdkVersion, which is why we
> need to make sure everyone knows about this. I agree with Kostya's
> comment regarding docs -- at this point, I think an Android Developers
> Blog post is probably needed.
>> > Conclusion: there's probably man apps broken in subtle ways on ICS because >> > of this change.
>> Probably not, only because they have to explicitly set the >> targetSdkVersion to 13+, and I don't know how many people are setting >> it that high.
> Bumping targetSdkVersion to the latest version is something very common
and generally harmless.
Not sure I agree.
There are some subtle activity lifecycle callback changes starting with 3.0, some not so subtle home screen widget changes starting with 4.0... just what comes to mind right away...
> -- > You received this message because you are subscribed to the Google > Groups "Android Developers" group. > To post to this group, send email to android-developers@googlegroups.com > To unsubscribe from this group, send email to > android-developers+unsubscribe@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/android-developers?hl=en
This code running unmodified on ICS will download images sequencially (instead of in parallel) and any timeouting download will block all other downloads.
The fix is just a matter of changing the Executor, but it illustrates nicely the side effect of the change.
> There are some subtle activity lifecycle callback changes starting with 3.0, > some not so subtle home screen widget changes starting with 4.0... just what > comes to mind right away...
And don't forget hardware acceleration that gets turned on when targetSdk=14+
-- Romain Guy Android framework engineer romain...@android.com