我们在开发的时候,基本都需要写一些网络请求的模块。
下面是一个模板代码,可以直接复制过去使用。
流程介绍:
我们申请一个线程池,便于控制网络请求。
把网络的请求的具体内容写到Runnable中去,然后传递给我们的ThreadPoolUtils去执行。
先看下我们的Activity吧。
public class HttpDemoActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//在线程中执行这个获取XXX的task
ThreadPoolUtils.execute(new MyGetXXXRunnableTask());
}
}
好了,我们的demo基本就长这样子咯。
那么我们的MyGetXXXRunnableTask就是这样啦。
MyGetXXXRunnableTask
public class MyGetXXXRunnableTask implements Runnable{
private String paraX;
public MyGetXXXRunnableTask( String paraX){
this.paraX = paraX;
}
@Override
public void run() {
HttpGet httpGet = new HttpGet("某个地址");
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, 60000);
httpGet.setParams(params);
try {
HttpResponse httpResponse = HttpClientHelper.getHttpClient().execute(httpGet);
byte[] bytes = EntityUtils.toByteArray(httpResponse.getEntity());
String result = new String(bytes);
Log.i(TAG,"hi,i get "+result);
} catch (Exception ex){
ex.printStackTrace();
}
}
}
需要注意的一句是HttpResponse httpResponse = HttpClientHelper.getHttpClient().execute(httpGet);
是的啦,就是这样,我们用一个单例的helper去执行我们的网络请求.
具体如下
HttpClientHelper
public class HttpClientHelper {
private static HttpClient httpClient;
private HttpClientHelper(){}
public static synchronized HttpClient getHttpClient(){
if(null == httpClient){
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
HttpProtocolParams.setUseExpectContinue(params, true);
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(), 80));
ClientConnectionManager conManager = new ThreadSafeClientConnManager(params, schReg);
httpClient = new DefaultHttpClient(conManager, params);
}
return httpClient;
}
}
最后就是我们的ThreadPoolUtil类
线程池辅助类,可以设置核心线程数、最大线程数、额外线程空状态生存时间,阻塞队列长度来优化线程池。
ThreadPoolUtils
public class ThreadPoolUtils {
private ThreadPoolUtils(){}
//线程池核心线程数
private static int CORE_POOL_SIZE = 5;
//线程池最大线程数
private static int MAX_POOL_SIZE = 100;
//额外线程空状态生存时间
private static int KEEP_ALIVE_TIME = 10000;
//阻塞队列。当核心线程都被占用,且阻塞队列已满的情况下,才会开启额外线程。
private static BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(10);
//线程工厂
private static ThreadFactory threadFactory = new ThreadFactory() {
private final AtomicInteger integer = new AtomicInteger();
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "myThreadPool thread:" + integer.getAndIncrement());
}
};
//线程池
private static ThreadPoolExecutor threadPool;
static {
threadPool = new ThreadPoolExecutor(CORE_POOL_SIZE,
MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, workQueue,
threadFactory);
}
//最重要的一句咯。
public static void execute(Runnable runnable){
threadPool.execute(runnable);
}
}
好啦,模板的一个网络请求写到这里,需要小结一下咯。
问题
1.返回结果
有什么问题?你没发觉好像没有返回结果给我们的调用吗??没有返回结果啊,真的没有啊?
怎么办?
- 可以使用EventBus来做这事!
- 加回调接口
2.线程池
不是任何程序都适合用线程池的,需要根据实际的业务来做。
什么时候不适合呢?
- 如果需要使一个任务具有特定优先级,对此建议使用具有优先级配置的任务队列来做。
- 如果具有可能会长时间运行(并因此阻塞其他任务)的任务。
- 如果需要将线程放置到单线程单元中(线程池中的线程均处于多线程单元中)。
- 如果需要永久标识来标识和控制线程,比如想使用专用线程来终止该线程,将其挂起或按名称发现它
那些情况下合适?
- 需要大量的线程来完成任务,且完成任务的时间比较短。 WEB服务器完成网页请求这样的任务,使用线程池技术是非常合适的。因为单个任务小,而任务数量巨大,你可以想象一个热门网站的点击次数。 但对于长时间的任务,比如一个Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了。
对于这个案例情景,推荐使用谷歌的Volley,因为它的设计就是针对高频数据量小的业务而做的。
可以看下这篇文章了解下:Android网络访问解决方案小结·1
- 对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。
- 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。突发性大量客户请求,在没有线程池情况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量线程可能使内存到达极限,并出现”OutOfMemory”的错误。