我在Android上做了一个简单的程序,它使用Socket连接到服务器并接收一些数据。当我以这种方式编码时,它运行良好:
public class MainActivity extends Activity
{
EditText ip_box;
Button login_button;
TextView text;
Handler handler;
final int port = 12121;
Socket socket;
String ip;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();//omitted
handler = new Handler()
{
public void handleMessage(Message msg)
{
String words = (String)msg.obj;
text.setText((String)msg.obj);
}
};
class GetThread implements Runnable
{
public void getMsg()
{
try
{
Scanner in = new Scanner(socket.getInputStream());
String gotmsg = in.nextLine();
Message msg = new Message();
msg.obj = gotmsg;
MainActivity.this.handler.sendMessage(msg);
} catch (UnknownHostException e)
{
Message msg = new Message();
msg.obj = "net error";
MainActivity.this.handler.sendMessage(msg);
} catch (IOException e)
{
Message msg = new Message();
msg.obj = "net error";
MainActivity.this.handler.sendMessage(msg);
}
}
@Override
public void run()
{
try
{
socket = new Socket();
socket.connect(new InetSocketAddress(ip, port) , 5000);
} catch (UnknownHostException e)
{
...
} catch (IOException e) {
...
}
if( socket != null)
getMsg();
else
{
...
}
}
}
login_button.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View arg0)
{
// TODO Auto-generated method stub
ip = ip_box.getText().toString();
GetThread g = new GetThread();
new Thread(g).start();
}
});
}
}
我要做的是使套接字连接成为一个独立的类。我以这种方式制作了这门课:
public class ClientSocketManager
{
String ip;
int port;
Socket socket;
Handler handler; //use this to send messages
/**
* Thread to get message from server
* @author Zero
*
*/
class GetThread implements Runnable
{
@Override
public void run()
{
try
{
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while(true)
{
String input = in.readLine();
if(input!=null)
{
Message msg = new Message();
msg.obj = input;
handler.sendMessage(msg);
}
}
}
catch (IOException e)
{
System.out.println("NetThreadIOException");
Message msg = new Message();
msg.obj = "net error";
handler.sendMessage(msg);
}
catch (NullPointerException e)
{
//System.out.println("NetThreadIOException");
Message msg = new Message();
msg.obj = "net error";
handler.sendMessage(msg);
}
}
}
/**
* Thread to login to server
* @author Zero
*
*/
class LoginThread implements Runnable
{
boolean ok;
@Override
public void run()
{
try
{
socket = new Socket();
socket.connect(new InetSocketAddress(ip, port) , 5000);
} catch (UnknownHostException e)
{
System.out.println("UnknownHostException");
Message msg = new Message();
msg.obj = "did not login";
handler.sendMessage(msg);
ok=false;
} catch (IOException e) {
System.out.println("IOException");
Message msg = new Message();
msg.obj = "did not login";
handler.sendMessage(msg);
ok=false;
}
}
}
public ClientSocketManager(){}
/**
* Create a new ClientSocketManager
* @param _ip
* @param _port
* @param _handler
*/
public ClientSocketManager(String _ip, int _port, Handler _handler)
{
ip = _ip;
port = _port;
handler = _handler;
}
public boolean login()
{
LoginThread login_thread = new LoginThread();
new Thread(login_thread).start();
return login_thread.ok;
}
public void openGetThread()
{
GetThread getThread = new GetThread();
new Thread(getThread).start();
}
}
在主活动中,我像这样使用 ClientSocketManager:
login_button.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View arg0)
{
// TODO Auto-generated method stub
ip = ip_box.getText().toString();
client_socket_manager = new ClientSocketManager(ip, port, handler);
boolean logged = client_socket_manager.login();
//if(!logged)
// return;
client_socket_manager.openGetThread();
}
})
现在它把IOException扔到String input = in.readLine();
上。我很好奇。可能的原因是什么?
谢谢!
原因可能是: client_socket_manager.login()
和client_socket_manager.openGetThread()
启动了两个线程同时运行以执行两个操作login
和get
。因此,当您尚未登录时,已执行操作get
。
问题是您的代码中无法保证 GetThread 将在登录线程之后执行。我看到您已经注释了代码检查登录状态。你需要把它放回去。
boolean loggedIn = false;
class LoginThread implements Runnable
{
boolean ok;
@Override
public void run()
{
try
{
socket = new Socket();
socket.connect(new InetSocketAddress(ip, port) , 5000);
loggedIn = true;
} catch (UnknownHostException e)
{
System.out.println("UnknownHostException");
Message msg = new Message();
msg.obj = "did not login";
handler.sendMessage(msg);
ok=false;
} catch (IOException e) {
System.out.println("IOException");
Message msg = new Message();
msg.obj = "did not login";
handler.sendMessage(msg);
ok=false;
}
}
}
并在运行 GetThread 之前检查此 loggeddIn 标志
client_socket_manager = new ClientSocketManager(ip, port, handler);
client_socket_manager.login();
while (true){
if(loggedIn){
client_socket_manager.openGetThread();
break;
}
Thread.sleep(1000); //wait 1 sec before retrying
}