即使服务中有后台线程,NetworkOnMainThreadException也是如此

时间:2012-06-05 19:40:45

标签: android android-4.0-ice-cream-sandwich

我正在开发一个UDP聊天应用程序。所有网络处理都在服务的内部线程中。我仍然收到3.1和4.0 oeprating系统的此错误消息。对于2.3及以下版本,它工作正常。问题:我应该创建两个应用程序,一个用于2.3及更低版本,另一个用于3.0及更高版本?根据LogCat调用 write(byte [] out)方法时会发生错误。

如果我为ICS禁用StrictMode,该应用程序正常运行。

public class ChatService extends Service { 
    private Binder binder;
    private ComThread comThread;

    public IBinder onBind(Intent intent) {
        return binder;
    }

    public void onCreate() {
    }

    public int onStartCommand(Intent intent, int flags, int startId) {
        binder = new ChatServiceBinder();
        start();
        return super.onStartCommand(intent, flags, startId);
    }

    public synchronized void start() {
        comThread = new ComThread();
        comThread.start();
    }

    public void onDestroy() {
        stop();
    }

    public void write(byte[] out) {
        comThread.write(out);
    }

    public synchronized void stop() {
        if (comThread != null) {
            comThread.cancel();
            comThread = null;
        }
    }

    private class ComThread extends Thread {
        private static final int BCAST_PORT = 2562;
    DatagramSocket mSocket;
    InetAddress myBcastIP, myLocalIP;

    public ComThread() {

        try {
            myBcastIP = getBroadcastAddress();
            if (D)
                Log.d(TAG, "my bcast ip : " + myBcastIP);

            myLocalIP = getLocalAddress();
            if (D)
                Log.d(TAG, "my local ip : " + myLocalIP);

            mSocket = new DatagramSocket(BCAST_PORT);
            mSocket.setBroadcast(true);

        } catch (IOException e) {
            Log.e(TAG, "Could not make socket", e);
        }
    }

    public void run() {

        try {

            byte[] buf = new byte[1024];
            if (D)
                Log.d(TAG, "run(), com thread startet");
            // Listen on socket to receive messages
            while (true) {
                DatagramPacket packet = new DatagramPacket(buf, buf.length);
                mSocket.receive(packet);

                InetAddress remoteIP = packet.getAddress();
                if (remoteIP.equals(myLocalIP))
                    continue;

                String s = new String(packet.getData(), 0,
                        packet.getLength());
                if (D)
                    Log.d(TAG, "run(), " + s);

                Message msg = new Message();
                msg.obj = s;
                msg.arg1 = MessageHandler.MSG_IN;
                state.getHandler().sendMessage(msg);

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Write broadcast packet.
     */
    public void write(byte[] buffer) {
        try {
            String data = new String(buffer);
            DatagramPacket packet = new DatagramPacket(data.getBytes(),
                    data.length(), myBcastIP, BCAST_PORT);
            mSocket.send(packet);
        } catch (Exception e) {
            Log.e(TAG, "write(), Exception during write", e);
        }
    }

    /**
     * Calculate the broadcast IP we need to send the packet along.
     */
    private InetAddress getBroadcastAddress() throws IOException {
        WifiManager mWifi = (WifiManager) state
                .getSystemService(Context.WIFI_SERVICE);

        WifiInfo info = mWifi.getConnectionInfo();
        if (D)
            Log.d(TAG, "\nWiFi Status: " + info.toString());

        // DhcpInfo is a simple object for retrieving the results of a DHCP
        // request
        DhcpInfo dhcp = mWifi.getDhcpInfo();
        if (dhcp == null) {
            Log.d(TAG, "Could not get dhcp info");
            return null;
        }

        int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask;
        byte[] quads = new byte[4];
        for (int k = 0; k < 4; k++)
            quads[k] = (byte) ((broadcast >> k * 8) & 0xFF);

        // Returns the InetAddress corresponding to the array of bytes.
        return InetAddress.getByAddress(quads); // The high order byte is
                                                // quads[0].
    }

    private InetAddress getLocalAddress() throws IOException {

        try {
            for (Enumeration<NetworkInterface> en = NetworkInterface
                    .getNetworkInterfaces(); en.hasMoreElements();) {
                NetworkInterface intf = en.nextElement();
                for (Enumeration<InetAddress> enumIpAddr = intf
                        .getInetAddresses(); enumIpAddr.hasMoreElements();) {
                    InetAddress inetAddress = enumIpAddr.nextElement();
                    if (!inetAddress.isLoopbackAddress()) {
                        return inetAddress;
                    }
                }
            }
        } catch (SocketException ex) {
            Log.e(TAG, ex.toString());
        }
        return null;
    }

    public void cancel() {
        try {
            mSocket.close();
        } catch (Exception e) {
            Log.e(TAG, "close() of connect socket failed", e);
        }
    }
}

public class ChatServiceBinder extends Binder {
    private ChatService service = ChatService.this;

    public ChatService getService() {
        return service;
    }
}        

}

}

感谢。

1 个答案:

答案 0 :(得分:0)

有点晚了,而不是一个超级好的答案,但在Android 3+ Runnable上不会被解释为允许,除非它在服务中(不是你拥有的子类)。我知道这是一个限制性的检查,因为您可以自由地创建任何您想要的任何东西,但是再次UDP多播并不是所有Android开发人员都不知所措。希望这会有所帮助。