2013-12-09 143 views
2

上下文: 以下Android應用程序的AsyncTask從服務器發送和接收所謂的請求對象。 如果用戶在應用程序中更改其內容,則會生成新的請求對象並將其添加到同步隊列中。如果他然後點擊同步按鈕,AsyncTask被創建並且以他的請求作爲參數被執行。Android AsyncTask卡住

處理程序最終獲取所有答案並在數據庫中設置必要的結果。然後他最終通過調用UI線程上的一個方法(onPostExecute)來更新UI。

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

最近我遇到了這個問題,經過一個多星期的調試和頭腦風暴之後,我終於得到了這個bug。

好的,讓我們做一些功課。

進程發送/接收數據

  1. 建立連接。假設connectToServer()是將設備物理連接到服務器的功能。
  2. 套接字/ TCP部分。在你的情況下,你有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--; 
     } 

}