2010-05-10 22 views
91

Chcę zwrócić wartość false, jeśli adres URL trwa dłużej niż 5 sekund, aby się połączyć - w jaki sposób jest to możliwe przy użyciu języka Java? Oto kod używam, by sprawdzić, czy adres URL jest poprawnyUstawienia limitu czasu HttpURLConnection

HttpURLConnection.setFollowRedirects(false); 
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection(); 
con.setRequestMethod("HEAD"); 
return (con.getResponseCode() == HttpURLConnection.HTTP_OK); 

Odpowiedz

153

HttpURLConnection ma metodę setConnectTimeout.

Wystarczy ustawić limit czasu do 5000 milisekund, a następnie złapać java.net.SocketTimeoutException

Kod powinien wyglądać następująco:

 

try { 
    HttpURLConnection.setFollowRedirects(false); 
    HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection(); 
    con.setRequestMethod("HEAD"); 

    con.setConnectTimeout(5000); //set timeout to 5 seconds 

    return (con.getResponseCode() == HttpURLConnection.HTTP_OK); 
} catch (java.net.SocketTimeoutException e) { 
    return false; 
} catch (java.io.IOException e) { 
    return false; 
} 

 
+1

Ustawiam wartość na 10 minut. Jednak wyrzuca mi 'java.net.ConnectException: Connection time out: connect' zanim minie nawet 2 minuty. Czy wiesz, co jest przyczyną problemu? – Pacerier

+0

@dbyrne wydaje mi się to nieco kłopotliwe - ponieważ ustawiliśmy timeout po utworzeniu obiektu 'HttpURLConnection', zastanawiam się, jakie jest dokładne miejsce w kodzie, które podniesie' SocketTimeoutException'? – Less

+3

SocketTimeoutException jest podklasą wyjątku IOException. Jeśli oba bloki catch robią to samo, możesz po prostu wychwycić wyjątek IOException. – spaaarky21

85

Można ustawić limit czasu tak,

con.setConnectTimeout(connectTimeout); 
con.setReadTimeout(socketTimeout); 
+1

Jaka jest maksymalna wartość limitu czasu, który możemy określić? – Pacerier

+5

@Pacerier Dokumenty nie określają tego wyraźnie. Wywołuje wyjątek IllegalArgumentException, jeśli wartość jest ujemna (wartość 0 oznaczałaby czekanie w nieskończoność). Ponieważ limit czasu to niepodpisana int 32-bitowa, przypuszczam, że maksymalny limit czasu wynosiłby około 49 dni (choć poważnie wątpię, że taka wartość byłaby przydatna dla każdego). –

+1

+1 dla wielu typów przekroczenia limitu czasu ... – jsh

1

Jeśli połączenie HTTP nie ma limitu czasu, możesz zaimplementować sprawdzanie limitu czasu w samym wątku tła (AsyncTask, Service, itp.), kolejna klasa to egzamin ple dla Dostosuj AsyncTask których limit czasu po pewnym okresie

public abstract class AsyncTaskWithTimer<Params, Progress, Result> extends 
    AsyncTask<Params, Progress, Result> { 

private static final int HTTP_REQUEST_TIMEOUT = 30000; 

@Override 
protected Result doInBackground(Params... params) { 
    createTimeoutListener(); 
    return doInBackgroundImpl(params); 
} 

private void createTimeoutListener() { 
    Thread timeout = new Thread() { 
     public void run() { 
      Looper.prepare(); 

      final Handler handler = new Handler(); 
      handler.postDelayed(new Runnable() { 
       @Override 
       public void run() { 

        if (AsyncTaskWithTimer.this != null 
          && AsyncTaskWithTimer.this.getStatus() != Status.FINISHED) 
         AsyncTaskWithTimer.this.cancel(true); 
        handler.removeCallbacks(this); 
        Looper.myLooper().quit(); 
       } 
      }, HTTP_REQUEST_TIMEOUT); 

      Looper.loop(); 
     } 
    }; 
    timeout.start(); 
} 

abstract protected Result doInBackgroundImpl(Params... params); 
} 

próbkę tego

public class AsyncTaskWithTimerSample extends AsyncTaskWithTimer<Void, Void, Void> { 

    @Override 
    protected void onCancelled(Void void) { 
     Log.d(TAG, "Async Task onCancelled With Result"); 
     super.onCancelled(result); 
    } 

    @Override 
    protected void onCancelled() { 
     Log.d(TAG, "Async Task onCancelled"); 
     super.onCancelled(); 
    } 

    @Override 
    protected Void doInBackgroundImpl(Void... params) { 
     // Do background work 
     return null; 
    }; 
} 
+0

Nie jest absolutnie konieczne tworzenie nowego wątku typu "Looper" tylko po to, aby zaplanować połączenie Anuluj(). Możesz to zrobić z głównego wątku w 'onPreExecute()'.Ponadto, jeśli ręcznie anulujesz zadanie, anuluj zaplanowane połączenie, aby uniknąć wycieków. – BladeCoder

+0

Punkt tutaj jest, aby anulować AsyncTask w środku doInBackground(), gdy trwa zbyt dużo czasu na wykonanie, nie na onPreExecute(), również chcę anulować tylko to wystąpienie AsyncTask, który zajmuje zbyt dużo czasu i zachować inne, dużo Doceniam Twoją opinię. –

+1

Myślę, że moja wiadomość nie była wystarczająco jasna. Nie powiedziałem, że powinieneś anulować w onPreExecute(), powiedziałem, że powinieneś utworzyć Handler w onPreExecute() i wysłać opóźnione anulowanie z głównego wątku. W ten sposób użyjesz głównego wątku jako wątku looper'a i możesz oczywiście anulować AsyncTask później, gdy wykonywana jest metoda doInBackground(), ponieważ główny wątek działa równolegle z wątkiem tła. – BladeCoder

0

mogę dostać rozwiązanie dla takiego podobnego problemu z dodatkiem prostych linii

HttpURLConnection hConn = (HttpURLConnection) url.openConnection(); 
hConn.setRequestMethod("HEAD"); 

My wymagało to znajomości kodu odpowiedzi i dla tego właśnie uzyskanie meta-informacji było wystarczające, zamiast uzyskania kompletnego ciała odpowiedzi.

Domyślna metoda żądania to GET, co zajęło dużo czasu, aby powrócić, ostatecznie rzucając mi wyjątek SocketTimeoutException. Odpowiedź była dość szybka, gdy ustawiłem metodę żądania na HEAD.

Powiązane problemy