2016-04-19 5 views
1

AndroidスタジオでAsyncTaskを使用して、バックグラウンドでTCP接続を使用しています。次に、PreExecuteのランナーが5秒のタイムアウトでランナーを実行し、cancel(true)AsyncTaskに呼び出します(DataOutputStreamにはタイムアウトのオーバーライドがないため)。AsyncTaskは、最初の試行でOnCancel()を呼び出さない

問題は、まずアプリケーションを開いてテストし、ログインしようとすると「サーバーに接続しています」だけです。 "TCP Timeout"というメッセージは決して呼び出されません。もう一度ログインしようとすると、正常に動作します。しかし、初めてではありません。だから私はcancel(true)が決して呼び出されないと思います。私はPreExecuteでタイムアウトランナーを実行しようとしましたが、onLoginButtonClickedコードの後ろに(これは愚かなことですが)何も動作しません。

私は間違っていますか?

private class AsynchronisedTask extends AsyncTask<String, Void, String> { 

    @Override 
    protected String doInBackground(String... strings) { 
     String serverAnswer = ""; 
     if (!isCancelled()) 
      serverAnswer = new TCP().SendToServer(strings[0]); 
     return serverAnswer; 
    } 

    @Override 
    protected void onPostExecute(String result) { 
     if (result.contains("Accepted")) { 
      Toast.makeText(LoginActivity.this, "Logged in.", Toast.LENGTH_SHORT).show(); 
      Intent intent = new Intent(LoginActivity.this, ProfilePageActivity.class); 
      Profile profile = new Profile(); 
      profile.setProfileName(usernameText.getText().toString()); 
      intent.putExtra("Username", usernameText.getText().toString()); 
      startActivity(intent); 
     } else { 
      Toast.makeText(LoginActivity.this, "Invalid username or password.", Toast.LENGTH_SHORT).show(); 
     } 
    } 

    @Override 
    protected void onPreExecute() { 
     handler = new Handler(); 
     handler.postDelayed(new Runnable() { 
      @Override 
      public void run() { 
       if (asynchronisedTask.getStatus() == AsyncTask.Status.RUNNING) { 
        asynchronisedTask.cancel(true); 
       } 
      } 
     }, 5000); 
     Toast.makeText(LoginActivity.this, "Contacting server.", Toast.LENGTH_SHORT).show(); 
    } 

    @Override 
    protected void onCancelled(String result) { 
     Toast.makeText(LoginActivity.this, "TCP Timeout.", Toast.LENGTH_SHORT).show(); 
    } 
} 



public class TCP implements ITCP { 
private String IP = "192.168.1.33"; // LOCAL "192.168.1.33" PUBLIC **.***.***.*** 
private int PORT = 9000; 

@Override 
public String SendToServer(String stringToServer) { 
    String answer = ""; 
    Socket socket = null; 
    DataOutputStream dataOutputStream = null; 
    DataInputStream dataInputStream = null; 

    try { 
     socket = new Socket(IP, PORT); 
     dataOutputStream = new DataOutputStream(socket.getOutputStream()); 
     dataInputStream = new DataInputStream(socket.getInputStream()); 
     dataOutputStream.writeUTF(stringToServer); 
     answer = dataInputStream.readUTF(); 

    } catch (UnknownHostException e) { 
     e.printStackTrace(); 

    } catch (IOException e) { 
     e.printStackTrace(); 

    } finally { 
     if (socket != null) { 
      try { 
       socket.close(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
     if (dataOutputStream != null) { 
      try { 
       dataOutputStream.close(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
     if (dataInputStream != null) { 
      try { 
       dataInputStream.close(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
    if (answer instanceof String) 
     return answer; 
    else return answer.toString(); 
} 

答えて

1

OnCancelledは、doInBackgroundが終了するまで呼び出されません。 doInBackgroundはTCPデータ転送を試みているので、決して起こらない。

私は実際にonCanceledが使用されたことはありませんでした。しかし、UIをクリーンアップするしかありません。タスクを終了する方法は、doInBackgroundに定期的にisCanceled()をチェックさせ、そのtrueの場合は終了させることです。どんな言語でも、汎用スレッドを安全に終了させる方法はありません。スレッド自身がそのスレッドの安全性を判断する以外の方法はありません。キャンセルはタスクをキャンセルするだけではなく、他のスレッドがチェックするフラグを設定するだけです。

task.cancel(true)を呼び出すと、ソケットが中断され、InterruptedExceptionが発生します。これをキャッチしてタスクがキャンセルすることができます。

+0

どのようにOnCancelledがdoInBackgroundの後に呼び出されるのは、別のスレッドが5秒のタイムアウトをしてからスレッドでcancel(true)を呼び出すときですか? そして、私はすでにdoInBackgroundのisCanceled()をチェックしていたと思いますか? – Bobfromfinance

+0

これは、doInBackgroundの後までは、ドキュメントのことであるため、呼び出されません:) onCanceledは、キャンセルされたタスクの場合は基本的にonPostExecuteの代わりに呼び出され、同じ目的(UIクリーンアップ)を目的としています。 isCanceledのチェックは値が変わることがあります。 doInBackgroundは並列スレッドで実行されることを忘れないでください。だから、isCanceledは最初は誤っているかもしれませんが、1ミリ秒後に真になります。だからこそ冒頭の虚偽はそれが後でキャンセルされないことを意味するわけではありません。 –

関連する問題