I have set up a socket connection between two droids, and I can send data back and forth with no problem. However, in the server side I have set up a ContentObserver to be notified when there is a change to the contacts.
I get the notification, but when I try to send a message to the client that the contacts have changed, I get a fatal exception. The content observer code is
public class ContactWatcher extends ContentObserver {
public ContactWatcher( Handler h )
{
super( h );
}
public void onChange(boolean selfChange)
{
if(!ConnectionManager.devices[0].matches("Null"))
{
ConnectionManager.sendMessage(MessageNames.CONTACT_UPDATE, 0);
}
}
I get to the sendMessage code, but when it tries to write to the socket the program crashes with the LogCat output
09-04 16:00:50.880: ERROR/AndroidRuntime(958): FATAL EXCEPTION: main
09-04 16:00:50.880: ERROR/AndroidRuntime(958): android.os.NetworkOnMainThreadException
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1077)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at dalvik.system.BlockGuard$WrappedNetworkSystem.write(BlockGuard.java:290)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at org.apache.harmony.luni.net.PlainSocketImpl.write(PlainSocketImpl.java:462)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at org.apache.harmony.luni.net.SocketOutputStream.write(SocketOutputStream.java:55)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:165)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at java.io.BufferedWriter.flush(BufferedWriter.java:129)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at java.io.PrintWriter.flush(PrintWriter.java:270)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at java.io.PrintWriter.println(PrintWriter.java:491)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at java.io.PrintWriter.println(PrintWriter.java:603)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at com.gigaset.homepanel.ConnectionManager.sendMessage(ConnectionManager.java:151)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at com.gigaset.homepanel.ContactWatcher.onChange(ContactWatcher.java:19)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at android.database.ContentObserver$NotificationRunnable.run(ContentObserver.java:43)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at android.os.Handler.handleCallback(Handler.java:587)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at android.os.Handler.dispatchMessage(Handler.java:92)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at android.os.Looper.loop(Looper.java:132)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at android.app.ActivityThread.main(ActivityThread.java:4025)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at java.lang.reflect.Method.invokeNative(Native Method)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at java.lang.reflect.Method.invoke(Method.java:491)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
09-04 16:00:50.880: ERROR/AndroidRuntime(958): at dalvik.system.NativeStart.main(Native Method)
The Android SDK documentation for the
NetworkOnMainThreadExceptionclass is pretty clear and easy to understand. It states that it is thrown on Honeycomb when you try to perform a network operation on the main UI thread.The fix is of course to run the network operation in a background thread. You can associate the
ContentObserverwith a different thread by passing a handler for that thread when you construct theContentObserver.Alternately, you could directly spawn a new thread, or post a runnable to a handler on a different thread.
If you really want to run the network operation on the main thread, you should be able to disable that exception via the
StrictModeapis (not recommended)