2012-06-05 2 views
0

Я разрабатываю приложение чата UDP. Вся обработка сети внутри потока в службе. Я до сих пор получаю это сообщение об ошибке для системы опознавания 3.1 и 4.0. Для версий 2.3 и ниже он работает нормально. Вопрос: должен ли я создать два приложения, один для версии 2.3 и ниже, а другой для версии 3.0 и выше? Ошибка возникает, когда метод write (byte [] out) вызывается в соответствии с LogCat.NetworkOnMainThreadException, хотя есть фоновый поток внутри службы

Если я отключу StrictMode для ICS, приложение работает нормально.

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

Если вы получаете это сообщение, кажется, что вы не правильно используете поток. Отправьте свой код. – Squonk

+1

Вы не должны создавать два приложения. Пожалуйста. –

+0

Мое приложение отлично работает для версий ОС 2.3 и ниже. Чтобы заставить его работать в ICS, я должен отключить StrictMode. 2.3 OS не распознает StrictMode, и мне нужно перейти к свойствам проекта и изменить цель сборки проекта на Android 4.0. Таким образом, я создал одно приложение с целью сборки 2.3, а другое с целью сборки 4.0 и StrictMode отключено. Что было бы правильным решением этой проблемы? Благодарю. – SeanZhang2012

ответ

0

Немного поздно, а не супер отличный ответ, но на Android 3+ Runnable не будет интерпретироваться как разрешенный, если он не находится внутри службы (а не подкласс, как у вас есть). Я знаю, что это предельная проверка, учитывая свободу, которую вы должны создать практически во всем, что хотите, но хотите, но повторная многоадресная рассылка UDP - это не то, с чем все разработчики Android. Надеюсь это поможет.

+0

Проблема, пожалуй, намного проще, чем это, как указано в комментарии Squonk, вызов comThread.write() из потока пользовательского интерфейса не приводит к выполнению операции в фоновом потоке, а приводит к сетевой операции происходящих в основном потоке пользовательского интерфейса, который называется методом. Исправление состоит в том, чтобы передать сообщение в поток или запустить его для этой конкретной цели и сделать вызов из его метода запуска - просто вызов произвольных методов объекта Thread не выполняет потоки. –

+0

Ах! SO теперь усекает комментарии к 3 с помощью ссылки show/hide. Я даже не видел последних 3 комментариев, включая Squonk's за его жалобы на недостающий код. – garlicman

 Смежные вопросы

  • Нет связанных вопросов^_^