已经好久没有写博客了,实在是上学期期末忙着考试,寒假又偷懒,只做项目,不总结。这是大三下学期了,是时候为了梦想好好努力了!!!坚持不放弃,博客重新开张。
简单说下在寒假中的一个项目的用到Http协议(Android的API,这个API的具体用法可以查看)http://android.toolib.net/reference/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.html这个链接,这里主要讲下几个常用的类:
1.HttpClient类:这个类主要是一个代理类,把本地的请求代理至服务器,并且把服务器的返回的形式(文本内容,可能是一段html代码,也可能是纯的字符串),返回形式以HttpReponse代理,最终得到一个输入流。
2.关于表单编码格式设置的类: UrlEncodedFormEntity postEntity = new UrlEncodedFormEntity(list, “utf-8”);这个类是表单封装的类,可以设置上传参数(键值对)的集合和上传的编码格式。编码格式最关键,设计服务器的参数接受和数据库的数据插入问题,如果不和服务器沟通好,容易导致乱码。
3.HttpPost的类:这个类是表示以POST方式请求服务器对应的脚本,从HTTP的知识来说,请求一般有两种,一种是GET,一种是POST,这里使用POST,因为如果参数过多,在GET中的URL中加入Query符号很复杂,二是可以避免GET请求带来的中文乱码问题。
4.关于返回的输入流转换为字符串的问题,服务器把数据文件都放在了HTTP报文体中,然后交给客户端一个输入流。网上关于字符流转化为字符串的代码很多,这里我不详细说了,我想说一个关键是:通信的编码格式问题。这里讲解一个类InputSteamReader。
InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。因此,这类的有个构造方法: InputStreamReader(InputStream in, Charset cs) ;在这里,传入服务器放在HTTP报文体内部的字符编码,来解码就可避免乱码问题。
以上就是对Android的HTTP的API的关键类进行一个初步讲解,接下来附上代码:
> public class HttpUtils {
private static HttpClient mHttpClient=null;
private static HttpEntity mEntity=null;
/**
* 请求服务器的接口函数
* @param requestPath//服务器路径
* @param requestParams//请求参数(HashMap)
* @param requestEncode//请求的表单的编码格式
* @param responseEncode//请求的返回体的编码格式
* @return //返回体的内容
*/
public static String requestHttpServer
(String requestPath,
Map<String, String> requestParams,
String requestEncode, String responseEncode) {
List<NameValuePair> list = getRequestParams(requestParams);
if (list != null) {
HttpPost post = bulidHttpPost(list, requestPath);
mHttpClient = CustomHttpclient.getSigleTonInstance();
if(mHttpClient!=null) {
InputStream ServerInputStream = getServetReponse(mHttpClient, post);
if (ServerInputStream != null)
//请求服务器没有异常,比如网络异常,超时异常等,就把数据流转化为字符串
{
return (switchStreamToString(ServerInputStream, responseEncode));
}else{
return "InterNetException";
}
}else{
return "singleTonException";
}
}else{
return "paramsException";
}
}
/**
* 将网络中的数据流变成字符串
* @param inputstream
* @param encode
* @return
*/
private static String switchStreamToString(InputStream inputstream, String encode) {
StringBuilder strBuilder = new StringBuilder();
try {
BufferedReader mBufferReader = new BufferedReader(new InputStreamReader(inputstream, encode));
String tmpStr=new String();
while((tmpStr=mBufferReader.readLine())!=null)
{
strBuilder.append(tmpStr);
}
mBufferReader.close();
//Log.i("lzw","转换流至字符串");
return(strBuilder.toString());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return "switchException";
}catch(IOException e){
e.printStackTrace();
return "switchException";
}
}
/**
* 遍历哈希表,用键值对的方式来形成表单的内容
* 返回一个List容器
*
* @param reuqestParams
* @return
*/
private static List<NameValuePair> getRequestParams(Map<String, String> reuqestParams) {
List<NameValuePair> list = null;
if (reuqestParams != null && (!reuqestParams.isEmpty())) {
//Log.i("lzw","post预前准备");
list = new ArrayList<NameValuePair>();
Iterator iterator = reuqestParams.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = (Map.Entry<String, String>) iterator.next();
list.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
//依照键值对填入
}
}
return (list);
}
/**
* 将带有参数的List容器放入Aache表单类中
* 按照服务器的URL形成请求表单
*
* @param list
* @param requestPath
* @return
*/
private static HttpPost bulidHttpPost(List<NameValuePair> list, String requestPath) {
HttpPost post = null;
try {
//Log.i("lzw","形成表单");
UrlEncodedFormEntity postEntity = new UrlEncodedFormEntity(list, "utf-8");
//请求体的编码格式
post = new HttpPost(requestPath);
post.setEntity(postEntity);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return (post);
}
/**
* 执行POST方法,来请求服务器,返回数据连接流
*
* @param mHttpCLient
* @param post
* @return
*/
private static InputStream getServetReponse(HttpClient mHttpCLient, HttpPost post) {
try {
HttpResponse mResponse = mHttpCLient.execute(post);
//向服务器做请求连接
mEntity = mResponse.getEntity();
return (mEntity.getContent());
} catch (SocketTimeoutException e) {
//请求超时异常捕捉
Log.i("lzw","connection_timeout");
e.printStackTrace();
} catch (IOException e) {
//请求服务器异常捕捉
e.printStackTrace();
Log.i("lzw","IOException");
}
return (null);
}
/**
* 断开连接,取消http请求
*/
public static void shutDownConnection(){
synchronized (mHttpClient){
try {
if(mEntity!=null)
{mEntity.consumeContent();}
}
catch (Exception e){
e.printStackTrace();
}
}
Log.i("lzw", "关闭http请求");
}
}
以上就是我们对andorid的HTTP的API的初步使用,这种方法一般就是使用android客户端同服务器交互的基础。接下来我们说几个在项目碰到的问题:
1.从android的前端组件监听请求服务器后,如果网络状态不好(假设一个用户的是个傻子,真的不知道网络),此时,没有网络的情况请求服务器后,我们如何处理这一情况,因此,大家可以看到上述代码中为什么做了分割函数的概念,就是为了让错误的异常信息更加容易区分。
private static InputStream getServetReponse(HttpClient mHttpCLient, HttpPost post) {
try {
HttpResponse mResponse = mHttpCLient.execute(post);
//向服务器做请求连接
mEntity = mResponse.getEntity();
return (mEntity.getContent());
} catch (SocketTimeoutException e) {
//请求超时异常捕捉
Log.i("lzw","connection_timeout");
e.printStackTrace();
} catch (IOException e) {
//请求服务器异常捕捉
e.printStackTrace();
Log.i("lzw","IOException");
}
return (null);
}
这个函数,就是HttpClient请求服务器的关键步骤,如果移动设备上的网络的是断开,直接会抛出IOException这个异常,此刻,如果我们将这个异常捕捉后处理,然后反馈给客户端,明确告诉网络异常,这样的话,就可以保证BUG的减少和及时反馈给用户信息。
还有一种情况,大家应该都知道中国移动的CMCC移动网络吧,这种网络是需要你登录的。我尝试过测试这种未登录的网络来测试。有两种情况可能会出现:一种是:长时间请求超时,结果仍然抛出IOException,这种情况同上面一样,不过要很久才会用反映,最关键是,在项目开发中,要学会根据服务器和客户端的测试的的数据包的基本时间来衡量我们所需要的最大的时间来抛出这个异常,下面附上设置请求返回的最大时间的方法:
设置了最大的请求时间后,我们就可以面对这种问题的出现。还有一种问题,这种未登录的CMCC网络,直接返回一个html文本(登录页面的脚本信息),这里就不会抛出异常供我们捕捉了,怎么办?一般来说,服务器和前端交互都是约定了通信格式的,一般不会返回给客户端html代码,所以,我们可以在解析字符串的时候,捕捉解析的异常,这样,捕捉之后反馈给用户,就可以了。
以上是关于网络情况不好时候的解决方案,如果还有更好的,希望大家可以留言。
接下来说一下在项目中另一个负责人提出的问题:当我们点击了一个登录按钮之后,开启一个线程请求服务器,可是如果用户没有耐心,网络反应很慢,他直接退出了,怎么办?
这种情况其实还是很复杂的,一般来说,如果你退出了,这个进程的就应该终止了,但是,如果你开启有后台线程在运行,这个线程在短时间内是不会停止的,而且,如果用户在退出之后,又重新点击了登录按钮,线程还会重复请求,我们自然不希望有这种问题的出现,那么怎么解决呢?
我们可以设想,当用户按下返回键的时候,我们做一个按键的监听,停止当前的线程请求,这是最合适的方案!这里附上代码:
“`
public static void shutDownConnection(){
synchronized (mHttpClient){
try {
if(mEntity!=null)
{mEntity.consumeContent();}
}
catch (Exception e){
e.printStackTrace();
}
}
Log.i("lzw", "关闭http请求");
}
在用户的按键监听中使用这个方法,就可以停止当前HTTP的请求,也不会导致重复请求。
以上就是关于安卓的HTTP的API使用的基本阐述和问题的解决方案。如果在项目里面还有其他扩展HTTP的功能的方法,我们可以通过查找HTTP的类库来使用,和配置。