Android AsyncTask卡住了

时间:2013-12-09 13:05:49

标签: java android android-asynctask

上下文: 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在一个单独的线程上执行。我在打开套接字上设置了超时并读入,因此在此超时后应该终止卡住的任务。

我的代码是否有任何问题,你能想象出一个解决方案吗?

1 个答案:

答案 0 :(得分:0)

最近我遇到了这个问题,经过一段时间的调试和脑力激荡,我终于得到了这个bug。

好吧,让我们做一些功课。

发送/接收数据的流程

  1. 建立连接。假设connectToServer()是将设备物理连接到服务器的功能。
  2. 套接字/ TCP部分。在您的情况下,您有doInbackground(),您在其中调用initSocket()来启动套接字连接。
  3.   

    真实世界场景中,当您请求连接到服务器时需要一些时间,可能是一两秒钟。因此,在启动套接字连接请求之前,您应该等待。如果套接字请求在连接之前发送,则它将进入锁定状态,并在默认超时完成后释放,使其卡住

    编程方案

    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--;
            }
    
    }