的上下文: Android应用程序的以下AsyncTask从服务器发送和接收所谓的Request对象。 如果用户在应用程序中更改了他的东西,则会生成新的请求对象并将其添加到同步队列中。然后,如果他按下同步按钮,则会创建AsyncTask并将其请求作为参数执行。
处理程序最终获取所有答案并在数据库中设置必要的后果。然后,他最终通过在UI线程上调用一个方法来更新UI(onPostExecute)。
public class RequestSender extends AsyncTask<Request, Void, Boolean>{
// Server data
private String host;
private int port = 1337;
private Socket socket;
private AnswerHandler handler;
public RequestSender(AnswerHandler handler) {
this.host = "hostNameHere";
this.handler = handler;
}
/**
* This method gets started as asynchronous task when you call .run()
* @return
*/
@Override
protected Boolean doInBackground(Request... requests) {
return sendAndReceive(requests);
}
private boolean sendAndReceive(Request... requests) {
boolean isConnected = this.initSocket();
if(isConnected) {
this.send(requests);
this.waitForAnswer();
} else {
handler.setRequests(requests);
}
return isConnected;
}
/**
* Tries to open a socket on the android device to a specified Host
*/
private boolean initSocket() {
try {
SocketAddress sockaddr = new InetSocketAddress(host, port);
socket = new Socket();
socket.connect(sockaddr, 5000);
return true;
} catch (UnknownHostException e) {
System.err.println("Unknown Host in initSocket()");
} catch (IOException e) {
System.err.println("Connection timed out");
}
return false;
}
/**
* Tries to send a request to the server
* @param request
*/
public void send(Request... request) {
if(socket != null) {
try {
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject(request);
out.flush();
} catch (IOException e) {
System.err.println("Couldn't write to socket in RequestSender");
}
}
}
/**
* Waits for the answer from the server and reports the result in the handler
*/
private void waitForAnswer() {
try {
socket.setSoTimeout(5000);
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
Request[] answers = (Request[]) in.readObject();
socket.close();
handler.setRequests(answers);
} catch (StreamCorruptedException e) {
System.err.println("Failed to open stream from server");
} catch (IOException e) {
System.err.println("Failed to read answers from server");
} catch (ClassNotFoundException e) {
System.err.println("Failed to read class from server");
}
}
@Override
protected void onPostExecute(Boolean a) {
handler.updateUI();
}
}
现在我的问题: 整个事情几次没有任何问题(这取决于我的手机的善意多少次),但是似乎任务卡在某处而没有在System.err上给我任何错误消息。 重新启动应用程序可以解决问题,并且可以毫无问题地再次运行。
我已经读过,自Honeycomb以来,AsyncTasks在一个单独的线程上执行。我在打开套接字上设置了超时并读入,因此在此超时后应该终止卡住的任务。
我的代码是否有任何问题,你能想象出一个解决方案吗?
答案 0 :(得分:0)
最近我遇到了这个问题,经过一段时间的调试和脑力激荡,我终于得到了这个bug。
好吧,让我们做一些功课。
发送/接收数据的流程
connectToServer()
是将设备物理连接到服务器的功能。doInbackground()
,您在其中调用initSocket()
来启动套接字连接。在真实世界场景中,当您请求连接到服务器时需要一些时间,可能是一两秒钟。因此,在启动套接字连接请求之前,您应该等待。如果套接字请求在连接之前发送,则它将进入锁定状态,并在默认超时完成后释放,使其卡住。
编程方案
connectToServer();
// wait for 1 or 2 second.
initSocket();
示例代码
/* Function to check whether we are physically connected to the server or not */
private boolean isConnEstablished(){
WifiInfo connInfo = mManager.getConnectionInfo();
return mManager.isWifiEnabled() && connInfo.getNetworkId() != -1 && connInfo.getIpAddress() != 0;
}
private void initSocket() {
boolean scanning = true;
int tryCount = 5; // we trying for 5 times
try {
while (scanning && tryCount > 0) {
try {
if (isConnEstablished()) {
try{
Thread.sleep(500);
}catch (InterruptedException e){
Log.e("Yo", "sleep-error");
}
tConnection = new Socket(host, port);
scanning = false;
Log.e(getClass().getName(), "Socket connection established");
}else {
throw new ConnectException();
}
} catch (ConnectException e) {
Log.e(getClass().getName(), "connecting again...");
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Log.e(getClass().getName(), "System sleep-error: " + ex.getMessage());
}
}
tryCount--;
}
}