Android Socket Error when switching between 3G and wifi
<p>My app connects to a server at various times. If I switch between 3g and wifi or vice versa I get a socket timeout error.  How do I circumvent this?  I read some posts on stackoverflow where people had similar issues and they fixed it by using a new socket.  How do make my http request with a new socket?</p>

<p>CODE:</p>

<pre><code>class HttpRunnable implements Runnable
{
    private HttpRequestNotification request = null;

    public HttpRunnable(HttpRequestNotification req)
    {
        request = req;
    }

    public void run()
    {
        HttpURLConnection conn = null;
        try {
            System.out.println(request.url);
            conn = (HttpURLConnection)(new URL(request.url)).openConnection();
            conn.setInstanceFollowRedirects(false);
            conn.setRequestMethod(request.verb);
            conn.setReadTimeout(20000);
            conn.setConnectTimeout(20000);

            // If the request contains an explicit auth token, replace our cached copy
            if (request.authToken != null &amp;&amp; request.authToken.length() &gt; 0)
                authorizationToken = request.authToken;

            // Add the authorization token, if we have it
            if (authorizationToken != null &amp;&amp; authorizationToken.length() &gt; 0)
            {
                conn.setRequestProperty("Authorization", authorizationToken);
            }

            if (request.postData != null &amp;&amp; request.postData.length &gt; 0)
            {   // Let the connection know we'll be posting data
                conn.addRequestProperty("Content-Type", "application/xml");
                conn.setDoOutput(true);
            }
            conn.connect();

            if (request.postData != null &amp;&amp; request.postData.length &gt; 0)
            {   // Write POST data, if necessary
                OutputStream os = conn.getOutputStream();
                os.write(request.postData);
                os.close();
            }

            // Grab input stream. If it hasn't occurred already, this will send the Http request over the wire.
            InputStream inputStream = conn.getInputStream();

            // Save off statusCode, statusMessage, headers
            request.statusCode = conn.getResponseCode();
            request.statusMessage = conn.getResponseMessage();
            Map hdrs = conn.getHeaderFields();
            Iterator iter = hdrs.keySet().iterator();
            while (iter.hasNext())
            {
                String key = (String) iter.next();
                String val = conn.getHeaderField(key); 
                if (key != null &amp;&amp; val != null)
                {
                    if (key.equalsIgnoreCase("location"))
                        request.url = val;
                    request.headers.put(key, val);
                }
            }

            // Extract the message body. We used to extract the content-length header &amp; only
            // read that amount of bytes, but we found that sometimes the header is missing.
            // Specifically, we found that requests lacked a content-length header in these cases:
            // 1) for HTTP 1.1 requests that provide a "transfer-encoding: chunked" header instead
            // 2) When running on certain carriers, we found the content-length header to be unreliable
            //    (DroidX running over Verizon -- full response body was there, but the content-length
            //    field was waaaay too small.
            // To handle all of these cases, we simply read until the end of the stream is reached, then
            // convert the result to a byte array.  See defect 14288 (over WiFi, some android devices
            // return Content-Length; over 3G, they may use transfer-encoding).
            ByteArrayOutputStream baos = new ByteArrayOutputStream(10*1024);    // This size is an initial size, not max size
            while (true)
            {
                int data = inputStream.read();
                if (data &lt; 0)
                    break;
                baos.write(data);
            }
            request.responseData = baos.toByteArray();

            // Extract the auth token, if it's present
            if (authorizationToken == null &amp;&amp; request.url.endsWith("authenticate") &amp;&amp; 
                    request.statusCode &gt;= 200 &amp;&amp; request.statusCode &lt; 300)
            {
                String authToken = conn.getHeaderField("X-Authorization-Token");
                if (authToken != null &amp;&amp; authToken.length() &gt; 0)
                    request.authToken = authorizationToken = authToken;
            }

            if (request.statusCode &gt;= 200 &amp;&amp; request.statusCode &lt; 400)
            {
                request.onSuccess();
            }
            else
            {
                // Note -- this check is included here as well as below for future-proofing. Note that currently
                // the J2SE implementation of HttpConnection will throw an IOException if the resopnse code
                // is not in the 200-299 range.
                if (request.statusCode == HttpURLConnection.HTTP_UNAUTHORIZED &amp;&amp;
                        !UserAuthService.HttpRequestNotification_Login.class.isInstance(request))
                {   // Got a 401 Unauthorized. Since this is not a login request, we want to transition
                    // the user back to the login screen.
                    LoginOrchestrator.getInstance().logout();
                }
                else
                    request.onError(request.statusCode, "");
            }

        }
        catch (IOException e)
        {
            try
            {
                if (conn != null)
                {
                    request.statusCode = conn.getResponseCode();
                    request.statusMessage = conn.getResponseMessage();
                }
            }
            catch (IOException ex) {}

            // Have to check for this HTTP_UNAUTHRORIZED case here as well -- the J2SE HttpConnection
            // throws an IOException when the status code is not in the 200-299 range.
            if (request.statusCode == HttpURLConnection.HTTP_UNAUTHORIZED &amp;&amp;
                    !UserAuthService.HttpRequestNotification_Login.class.isInstance(request))
            {   // Got a 401 Unauthorized. Since this is not a login request, we want to transition
                // the user back to the login screen.
                LoginOrchestrator.getInstance().logout();
            }
            else
                request.onError(request.statusCode, e.toString() + ": " + e.getMessage());
        }
        System.out.flush();
    }
}
</code></pre>
