0

我继承了一个 Android 应用程序并正在更新它以获取最新的 API。NetworkOnMainThreadException当我创建套接字时,我得到了。我已经阅读了许多说要使用的解决方案AsyncTask。但是AsyncTask应该只用于短期运行的任务。这是一个标准的 TCP 连接,将在运行的应用程序的整个生命周期内持续存在。它是双向的。

我如何使用 Threads 更新类,以便我不会收到异常并能够通过套接字发送数据?

public class TcpConnection
{
    enum State
{
    Closed,
    Closing,
    Open
};

State _state;    
Socket _socket;
//data stream from the head-unit
DataInputStream _inputStream;
//data stream to the head-unit
DataOutputStream _outputStream;

Receiver _receiver;
Thread _thread;

OnTcpDataReceivedListener _onTcpDataReceived;

public TcpConnection()
{                 
     _state = State.Closed;
}

// Listen to this to be informed of what data has been received from a TCP / IP socket.
public void setOnTcpDataReceivedListener(OnTcpDataReceivedListener listener)   
{
    _onTcpDataReceived = listener;
}

// Used to inform the listener that data has been received from a TCP / IP socket.
public interface OnTcpDataReceivedListener
{
    public void onTcpDataReceived(byte[] buffer, int length);
}

// Try connecting to a given TCP / IP connection.
// Notes:
// Blocks until a connection is created.
// if connected
public synchronized void connect(String ipAddress, int port) 
throws IOException
{
    if (_state != State.Closed)
        return;

    try
    {
        _state = State.Open;

        _socket = new Socket(ipAddress, port);
        _inputStream = new DataInputStream(_socket.getInputStream());
        _outputStream = new DataOutputStream(_socket.getOutputStream());            
    }
    catch(IOException ex)
    {            
        //TODO: do better error handling
        ex.printStackTrace();

        if (_socket != null) {
            _socket.close();
            _socket = null;             
        }

        if (_inputStream != null) {
            _inputStream.close();
            _inputStream = null;
        }

        if (_outputStream != null) {
            _outputStream.close();
            _outputStream = null;
        }

        throw ex;
    }

    _receiver = new Receiver();

    _thread = new Thread(_receiver);
    _thread.setName("TcpConnection.Receiver");
    _thread.start();
}

public void write(byte[] buffer)
{
    if (_state != State.Open)
        return;

    try
    {
        _outputStream.write(buffer);
    }
    catch(IOException ex)
    {            
        //TODO: do better error handling
        ex.printStackTrace();            
    } 
}

public synchronized void close()
{
    _state = State.Closing;

    if (_socket != null && !_socket.isClosed())
    {
        try
        {
            _socket.close();
        }
        catch(IOException ex)
        {
            //TODO: do better error handling
            ex.printStackTrace();
        }
    }         
}

private class Receiver implements Runnable
{                                  
    @Override
    public void run() 
    {                        
        try 
        {
            byte[] buffer = new byte[512];
            int read = 0;

            while(_state == State.Open)
            {                    
                read = _inputStream.read(buffer);

                if (read > 0)
                {
                    if (_onTcpDataReceived != null)
                    {
                        _onTcpDataReceived.onTcpDataReceived(buffer, read);
                    }
                }
            }
        }
        catch (SocketException ex)
        {
            if (    !(_state != State.Open 
                    && ex.getMessage() != null 
                    && ex.getMessage().equalsIgnoreCase("socket closed")))
            {
                ex.printStackTrace();
            }
        }
        catch (IOException ex) 
        {
            //TODO: need error handling
            ex.printStackTrace();
        }            
        finally 
        {
            if (_socket != null && !_socket.isClosed())
            {
                try
                {
                    _socket.close();
                }
                catch (IOException ex) 
                {
                    //TODO: need error handling
                    ex.printStackTrace();
                }                    
            }
        }

        _state = State.Closed;
     }
}   

}

4

1 回答 1

0

你有几个选择:

  1. TcpConnection更新用于将所有调用包装TcpConnection在单独线程中的实际 Android 类:您可以创建一个Executor并使用它。
  2. 添加一个处理所有传输和接收的Executor实例。TcpConnection我希望您的问题与connect函数有关:也许尝试将该代码包装在单独的 Runnable 中并在线程上启动它?
于 2013-05-13T20:35:36.343 回答