/*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.