NetworkOnMainThreadException on android 4.0.1

Hi guys!

As you may know android sdk greater than 3.2 has strict mode turn on by default. It means that if you do network connection on main (ui) thread android os will close your application.
I'm developing application with photon and start building it from realtime demo prj as an example. It works fine until disconnect method called from service onDestroy. Let see the code.
public void disconnect()	{

		if (null != timer)  {
			timer.cancel();
			timer = null;
		}
		
		if (null != peer)	{
			peer.opLeave();
			peer.disconnect();
		}
		
		peer = null;
		players.clear();
		localPlayer = null;
	}

As i understood TaskTimer runs in separate thread. And all photon operations with networks operates inside this TimerTask ( peer.dispatchIncomingCommands() and peer.sendOutgoingCommands() ). Nevertheless i have an android.os.NetworkOnMainThreadException. Please find stackTrace below:
java.lang.RuntimeException: Unable to stop service com.slobodastudio.discussions.photon.PhotonService@2c2213d8: android.os.NetworkOnMainThreadException
at android.app.ActivityThread.handleStopService(ActivityThread.java:2405)
at android.app.ActivityThread.access$2000(ActivityThread.java:122)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1212)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4340)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method) Caused by: android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1086)
at libcore.io.BlockGuardOs.sendto(BlockGuardOs.java:163)
at libcore.io.IoBridge.sendto(IoBridge.java:463)
at java.net.PlainDatagramSocketImpl.send(PlainDatagramSocketImpl.java:182)
at java.net.DatagramSocket.send(DatagramSocket.java:287)
at de.exitgames.client.photon.UdpConnection.sendData(UdpConnection.java:37)
at de.exitgames.client.photon.EnetPeer.sendData(EnetPeer.java:582)
at de.exitgames.client.photon.EnetPeer.sendOutgoingCommands(EnetPeer.java:488)
at de.exitgames.client.photon.EnetPeer.disconnect(EnetPeer.java:115)
at de.exitgames.client.photon.PhotonPeer.disconnect(PhotonPeer.java:472)
at com.slobodastudio.discussions.photon.PhotonService.disconnect(PhotonService.java:108)
at com.slobodastudio.discussions.photon.PhotonService.onDestroy(PhotonService.java:132)
at android.app.ActivityThread.handleStopService(ActivityThread.java:2388)
... 10 more

My question is: what happens when timer stops? As we can see in disconnect funtion timer stops before peer.Leave and peer.disconnect. So how can we run peer.Leave and peer.disconnect commands if timer is already stopped? Who is sending outgoing command, could it be peer itself?

Thanks in advance,
Sergii

Comments

  • I'm not too deep into Java Android but my question would be: Why does the timer stop?
    If it's working before (even with "strict mode") and suddenly it doesn't, it would be best to fix why it stops.

    PhotonPeer.disconnect will send a "disconnect" command (in a last package) to the server. This seems to be called in the stack trace you supplied.
    If you call disconnect() directly after a opLeave(), leave won't happen. Disconnect throws away what's in the queues and just sends a disconnect.

    You also cancel the timer before you call leave and disconnect. How should either reach the server if there are no more service() calls through the timer?

    Another question: Does the demo work or does it reproduce the issues you describe?
  • Thanks for your reply, Tobias.
    PhotonPeer.disconnect will send a "disconnect" command (in a last package) to the server. This seems to be called in the stack trace you supplied.
    If you call disconnect() directly after a opLeave(), leave won't happen. Disconnect throws away what's in the queues and just sends a disconnect.

    This information helps. As i understood disconnect() uses different approach. If i called opLeave() or opCustom() operation this call sets a request in peer and actual operation (network connection) goes into peer.service() call. It is okay, because peer.service() runs on separate thread by TimerTask. But disconnect() makes connection directly, it doesn't wait for peer.service() call. I think you should make an alert in documentation of method. That disconnect() make a network connection, so developer could move it out from main thread or application will get an NetworkOnMainThreadException in android 4 and greater.

    Thanks,
    Sergii
  • That's a good info. Thanks for pointing it out - we haven't been aware of that yet.
  • plastiv wrote:
    so developer could move it out from main thread or application will get an NetworkOnMainThreadException in android 4 and greater.
    What about Android 3.?
  • SpiralNero: In Android 3, this has not been an issue, so it works.