Monday, June 18, 2012

Why Ice Cream Sandwich Crashes Your App

The following question has plagued StackOverflow ever since Ice Cream Sandwich's initial release:

My application works fine on devices running Android 2.x, but force closes on devices running HoneyComb (3.x) and Ice Cream Sandwich (4.x). Why does this occur?

This is a great question; after all, newer versions of Android are released with the expectation that old apps will remain compatible with new devices. In my experience, there are a couple reasons why this might occur. Most of the time, however, the reason is simple: you are performing a potentially expensive operation on the UI thread.

What is the UI Thread?

The concept and importance of the application's main UI thread is something every Android developer should understand. Each time an application is launched, the system creates a thread called "main" for the application. The main thread (also known as the "UI thread") is in charge of dispatching events to the appropriate views/widgets and thus is very important. It's also the thread where your application interacts with running components of your application's UI. For instance, if you touch a button on the screen, the UI thread dispatches the touch event to the view, which then sets its pressed state and posts an invalidate request to the event queue. The UI thread dequeues this request and then tells the view to redraw itself.

This single-thread model can yield poor performance unless Android applications are implemented properly. Specifically, if the UI thread was in charge of running everything in your entire application, performing long operations such as network access or database queries on the UI thread would block the entire user interface. No event would be able to be dispatched—including drawing and touchscreen events—while the long operation is underway. From the user's perspective, the application will appear to be frozen.

In these situations, instant feedback is vital. Studies show that 0.1 seconds is about the limit for having the user feel that the system is reacting instantaneously. Anything slower than this limit will probably be considered as lag (Miller 1968; Card et al. 1991). While a fraction of a second might not seem harmful, even a tenth of a second can be the difference between a good review and a bad review on the Android Market. Even worse, if the UI thread is blocked for more than about five seconds, the user is presented with the notorious "application not responding" (ANR) dialog and the app is force closed.

Why Android Crashes Your App

The reason why your application crashes on Android versions 3.0 and above, but works fine on Android 2.x is because HoneyComb and Ice Cream Sandwich are much stricter about abuse against the UI Thread. For example, when an Android device running HoneyComb or above detects a network access on the UI thread, a NetworkOnMainThreadException will be thrown:

E/AndroidRuntime(673): java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.example/com.example.ExampleActivity}: android.os.NetworkOnMainThreadException

The explanation as to why this occurs is well documented on the Android developer's site:

A NetworkOnMainThreadException is thrown when an application attempts to perform a networking operation on its main thread. This is only thrown for applications targeting the Honeycomb SDK or higher. Applications targeting earlier SDK versions are allowed to do networking on their main event loop threads, but it's heavily discouraged.

Some examples of other operations that ICS and HoneyComb won't allow you to perform on the UI thread are:

  • Opening a Socket connection (i.e. new Socket()).
  • HTTP requests (i.e. HTTPClient and HTTPUrlConnection).
  • Attempting to connect to a remote MySQL database.
  • Downloading a file (i.e. Downloader.downloadFile()).

If you are attempting to perform any of these operations on the UI thread, you must wrap them in a worker thread. The easiest way to do this is to use of an AsyncTask, which allows you to perform asynchronous work on your user interface. An AsyncTask will perform the blocking operations in a worker thread and will publish the results on the UI thread, without requiring you to handle threads and/or handlers yourself.

Conclusion

The reason why I decided to write about this topic is because I have seen it come up on StackOverflow and other forums countless times. The majority of the time the error stems from placing expensive operations directly on the UI thread. To ensure you don't disrupt the user experience, it is very important to execute Socket connections, HTTP requests, file downloads, and other long-term operations on a separate Thread. The easiest way to do this is to wrap your operation in an AsyncTask, which launches a new thread and allows you to perform asynchronous work on your user interface.

As always, let me know if this was helpful by +1-ing the post or leaving a comment below! Feel free to ask questions too... I respond to them quickly. :)

Helpful Links

Here are some helpful links that might help you get started with AsyncTasks.


39 comments :

  1. Thank you. It helped me a lot!!!

    ReplyDelete
  2. Agreed..
    I also had the same issue, "NetworkOnMainThreadException"

    I could resolve it by removing targetSDKVersion=15 attribute from manifest.

    It may be due to some compatibility modes.
    It was ok as a quick solution, but you MUST use a different thread when it comes to time consuming tasks like network operations.

    ReplyDelete
  3. Removing targetSdkVersion most likely won't have any effect if your minSdkVersion is greater than or equal to "11"... I wouldn't think of it as a "quick solution". :)

    ReplyDelete
    Replies
    1. Agree..Solution is use Non UI thread to avoid this NetworkThreadMainException

      Delete
  4. Very useful for a Developer

    ReplyDelete
  5. Myself got the same issue and solved it...The article is very helpful those who find NetworkOnMainThreadException for first time.

    Thanks

    ReplyDelete
  6. Super useful, great explanation - Thanks!

    ReplyDelete
  7. thanks , it is useful for me............sachin

    ReplyDelete
  8. Thanks thanks and thanks. I have this problem with sockets. Very helpfull

    ReplyDelete
  9. What dose it mean yar ?? ? I just want simple way to stop crashing applications on android ics 4.0.3 is their any way or software to do the same ???

    ReplyDelete
    Replies
    1. it means you need to buy an Iphone or not mess around with anything complex.

      Delete
    2. uhh... iOS is no different? in fact, most modern GUIs follow the same single-threaded model as outlined in this post.

      Delete
  10. Thank you, was useful to me too.
    Understood why new Socket() crashed on me, I now use an AsyncTask and everything is fine.

    ReplyDelete
  11. Same same. Very useful. Asynctask wasn't as painful as I thought.

    ReplyDelete
  12. Even I have seen this issue being discussed in many forums but I think the solution given by you is simple and easy to understand which eases our work.

    ReplyDelete
  13. Even for those who are unfamiliar with development; this post helpful.
    Thanks.

    ReplyDelete
  14. Nice job!!! well written! Very good post!

    ReplyDelete
  15. Extremely helpful article!

    ReplyDelete
  16. Thanks. Perfectly explained

    ReplyDelete
  17. I have used AsyncTask but my data is not posted to server for Google Nexus device which works on Android 4.1. It doesn't crash but it doesn't post the data also. Anyway to get this done.

    ReplyDelete
    Replies
    1. Sounds like a problem with how you are performing the network request... not a problem with how you are using the AsyncTask. Post a question on StackOverflow with the code you are using and you'll probably get a response pretty quick... if not, you can post a link to the post here and I can take a look. :)

      Delete
    2. I posted it on Stack Overflow and I am posting the link here too. Please take a look at it. Let me know if I am going wrong somewhere. http://stackoverflow.com/questions/13796306/multiple-image-upload-using-asynctask-in-android-using-phonegap

      Delete
  18. very helpful, thank you.

    ReplyDelete
  19. thanks you very useful, great explanation!!!

    ReplyDelete
  20. I got the same issue and solved it...The article is very helpful those who find NetworkOnMainThreadException for first time. and I have seen this issue being discussed in many forums but I think the solution given by you is simple and easy to understand.

    ReplyDelete
  21. Very useful article. Thank you.

    ReplyDelete
  22. for android apps, we need to make sure that the UI is non-blocking

    ReplyDelete
  23. thanks.... very useful explanation in a very simple language. I also had the same issue "NetworkOnMainThreadException". Now I solved it.
    Your article is very useful specially for new Android developers.

    ReplyDelete
  24. thanks a ton man!!! removing target sdk from my manifest solved it all for me!!!

    ReplyDelete
    Replies
    1. No, don't do that, you're just masking the problem! Make sure all long-running requests are performed on a background thread instead!

      Delete
  25. Excellent tutorial in very simple language! Thanks.

    ReplyDelete
  26. Thanks .It was a big problem in my application.

    ReplyDelete
  27. I had the same problem, thanks for this article!

    ReplyDelete
  28. At the end, someone explained my trouble. Thank you so much !!

    ReplyDelete