我继承了一个 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;
}
}
}