/*Addressing Multithreading Issues The examples we’ve shown so far created a new HttpClient for each request. In practice, however, you should probably create one HttpClient for the entire application and use that for all of your HTTP communication. With one HttpClient servicing all of your HTTP requests, you should also pay attention to multithreading issues that could surface if you make simultaneous requests through the same HttpClient. Fortunately, the HttpClient provides facilities that make this easy—all you have to do is create the DefaultHttpClient using a ThreadSafeClientConnManager, as shown in Listing 11–6.*/ Listing 11–6. Creating an HttpClient for Multithreading: CustomHttpClient.java import org.apache.http.HttpVersion; import org.apache.http.client.HttpClient; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.params.ConnManagerParams; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; import org.apache.http.protocol.HTTP; public class CustomHttpClient { private static HttpClient customHttpClient; /** A private Constructor prevents instantiation */ private CustomHttpClient() { } public static synchronized HttpClient getHttpClient() { if (customHttpClient == null) { HttpParams params = new BasicHttpParams(); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET); HttpProtocolParams.setUseExpectContinue(params, true); HttpProtocolParams.setUserAgent(params, "Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; Nexus One Build/FRG83) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1" ); ConnManagerParams.setTimeout(params, 1000); HttpConnectionParams.setConnectionTimeout(params, 5000); HttpConnectionParams.setSoTimeout(params, 10000); SchemeRegistry schReg = new SchemeRegistry(); schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443)); ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params,schReg); customHttpClient = new DefaultHttpClient(conMgr, params); } return customHttpClient; } public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } }
/** If your application needs to make more than a few HTTP calls, you should create an HttpClient that services all your HTTP requests. The simplest way to do this is to create a singleton class that can be accessed from anywhere in the application, as we’ve shown here. This is a fairly standard Java pattern in which we synchronize access to a CHAPTER 11: Building and Consuming Services 317 getter method, and that getter method returns the one and only HttpClient object for the singleton, creating it the first time as necessary. Now, take a look at the getHttpClient() method of CustomHttpClient. This method is responsible for creating our singleton HttpClient. We set some basic parameters, some timeout values, and the schemes that our HttpClient will support (i.e., HTTP and HTTPS). Notice that when we instantiate the DefaultHttpClient(), we pass in a ClientConnectionManager. The ClientConnectionManager is responsible for managing HTTP connections for the HttpClient. Because we want to use a single HttpClient for all the HTTP requests (requests which could overlap if we're using threads), we create a ThreadSafeClientConnManager. We also show you a simpler way of collecting the response from the HTTP request, using a BasicResponseHandler. The code for our activity that uses our CustomHttpClient is in Listing 11–7.**/ Listing 11–7. Using Our CustomHttpClient: HttpActivity.java import java.io.IOException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import android.app.Activity; import android.os.Bundle; import android.util.Log; public class HttpActivity extends Activity { private HttpClient httpClient; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); httpClient = CustomHttpClient.getHttpClient(); getHttpContent(); } public void getHttpContent() { try { HttpGet request = new HttpGet("http://www.google.com/"); String page = httpClient.execute(request, new BasicResponseHandler()); System.out.println(page); } catch (IOException e) { // covers: // ClientProtocolException // ConnectTimeoutException // ConnectionPoolTimeoutException // SocketTimeoutException e.printStackTrace(); } 318 CHAPTER 11: Building and Consuming Services } }
For this sample application, we do a simple HTTP get of the Google home page. We also use a BasicResponseHandler object to take care of rendering the page as a big String, which we then write out to LogCat. As you can see, adding a BasicResponseHandler to the execute() method is very easy to do.