最近一直处于穷忙阶段,每天下班都累的半死(项目上都是上半年松,下半年紧,估计得持续到年底,想想都累),下班感觉没精力学习了。昨天休了一天假,把Android调用WCFRest研究了下,稍作整理,例子以登录和注册为例,登录或注册后跳转新的页面显示用户信息。
涉及到的知识点:1.WCFRest实现基础(WCFRest后面单独讲,没接触过的,就根据我的例子依葫芦画瓢,到实际要用时再研究不迟);2.Http的Get和Post请求;3.页面跳转传值;4.实体类对象与Json字符串的互转;5.子线程中通知主线程更新UI;
对象转换成Json字符串的示例:
注:本机调试时只要将WCFRest的解决方案直接运行即可,然后运行Android的模拟器就可以了。如果要在手机上调试,需要将WCFRest的服务地址改成你本机的ip地址再运行,然后在Android中的HttpHelper将ip地址改成电脑的ip地址,我用手机测试时手机连的是电脑开的Wifi,测试通过。
2.网络权限需在AndroidManifest.xml注册;
3.Post请求时注意Url最后不要加/了;
错误元凶:String url = HttpHelper.BASE_URL + "RegistLogin";
当时在RegistLogin后面又加了一个/导致出错,花了不少时间找这个错误;
4.子线程中也是不能跳转页面的,要通知主线程操作跳转页面;
5.页面的对象在定义后别忘了实例化;
错误元凶:TextView gidRegist = null;
定义后没有实例化,然后取值时报错;这个错误好找,但也要有耐心看那英文错误;
6.最后一个就是本地ip地址啦(这个没出错,友情提醒一下),
计算机本地地址是127.0.0.1而对应的Android本地是10.0.2.2;
涉及到的知识点:1.WCFRest实现基础(WCFRest后面单独讲,没接触过的,就根据我的例子依葫芦画瓢,到实际要用时再研究不迟);2.Http的Get和Post请求;3.页面跳转传值;4.实体类对象与Json字符串的互转;5.子线程中通知主线程更新UI;
1.WCFRest实现基础
简单介绍下接口和控制台宿主配置文件。接口定义了两个方法供调用,Login方法通过Get方式调用,RegistLogin通过Post方式调用,返回值都是用户基础信息。代码如下:
[ServiceContract]
public interface ILoginService
{
[OperationContract(Name = "Login")]
[WebInvoke(Method = "GET",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "Login/{GID}/{PWD}")]
BaseInfo Login(string GID, string PWD);
[OperationContract(Name = "RegistLogin")]
[WebInvoke(Method = "POST",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "RegistLogin")]
BaseInfo RegistLogin(BaseInfo baseInfo);
}
宿主配置文件如下:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding crossDomainScriptAccessEnabled="true" />
</webHttpBinding>
</bindings>
<services>
<service name="LoginService0909.LoginService">
<endpoint
address="Http://127.0.0.1:3721/LoginService"
binding="webHttpBinding"
contract="LoginService0909.ILoginService"/>
</service>
</services>
</system.serviceModel>
</configuration>
至于服务实现,鉴于调试的方便,数据提供模块采用了简单工厂模式加Linq To XML,实际项目一般是数据库,有兴趣的可以去深入研究相关知识。
2.Http的Get和Post请求
主要对象是HttpGet、HttpPost和HttpResponse三个对象,都是org.apache.http之下的;注意Post时需要设置Header的一些属性,Http的帮助类代码如下:public class HttpHelper {
public static final String BASE_URL = "http://10.0.2.2:3721/LoginService/";
private static final String USER_AGENT = "Mozilla/4.5";
private static HttpPost getHttpPost(String url, String json) {
HttpPost request = null;
try {
request = new HttpPost(url);
request.setHeader("Accept", "application/json");
request.setHeader("Content-Type", "application/json");
request.setHeader("User-Agent", USER_AGENT);
} catch (IllegalArgumentException e) {
System.out.println("网络调用出现异常,请检查访问的URL的书写!");
return null;
} catch (Exception ex) {
System.out.println("网络调用出现异常,请检查网络是否开启!");
return null;
}
if (json != null) {
try {
StringEntity entity = new StringEntity(json, "UTF-8");
request.setEntity(entity);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
return request;
}
public static String Post(String url, String json) {
HttpPost request = HttpHelper.getHttpPost(url, json);
String result = null;
if (request == null) {
result = "Post调用网络失败,网络有问题!";
return result;
}
try {
HttpResponse response = new DefaultHttpClient().execute(request);
if (response.getStatusLine().getStatusCode() == 200) {
result = EntityUtils.toString(response.getEntity());
} else {
result = "网络Post异常!请求失败!";
}
} catch (ClientProtocolException e) {
result = "网络Post异常!ClientProtocolException错误!";
} catch (IOException e) {
e.printStackTrace();
result = "网络Post异常!IOException错误!";
}
return result;
}
// 发送Get请求,获得响应查询结果
public static String Get(String url) {
// 获得HttpGet对象
HttpGet request = null;
String result = null;
try {
request = new HttpGet(url);
} catch (IllegalArgumentException e) {
result = "网络Get调用出现异常,请检查访问的URL的书写!";
System.out.println(result);
return result;
} catch (Exception ex) {
result = "网络Get调用出现异常,请检查网络是否开启!";
System.out.println(result);
return result;
}
try {
HttpResponse response = new DefaultHttpClient().execute(request);
if (response.getStatusLine().getStatusCode() == 200) {
result = EntityUtils.toString(response.getEntity());
return result;
}
} catch (ClientProtocolException e) {
result = "网络Get异常!ClientProtocolException错误!";
return result;
} catch (IOException e) {
result = "网络Get异常!IOException错误!";
return result;
}
return null;
}
}
3.页面跳转传值
这个比较简单,在前面的文章也有讲过,不过要注意的,在子线程中不可执行跳转,如需跳转需要通知主线程操作跳转页面。代码如下(如果需要回传的请参考前面的文章Android之Intent):Intent it = new Intent(MainActivity.this,
UserinfoActivity.class);
it.putExtra("JsonResult", txtJsonResult);
MainActivity.this.startActivity(it);
4.实体类对象与Json字符串的互转
在Post请求时传参需要Json字符串(当然也可传入其他格式,不过Json字符串能够更广泛的用于解析对象,并且比XML更简洁),获得返回值需要将Json字符串转换为实体对象;Google提供了Gson的插件,然后将其添加进项目中去。对象转换成Json字符串的示例:
Gson gson = new Gson();
BaseInfo baseInfo = new BaseInfo();
baseInfo.GID = gidRegist.getText().toString();
baseInfo.Name = nameRegist.getText().toString();
baseInfo.PWD = pwdRegist.getText().toString();
baseInfo.City = cityRegist.getSelectedItem().toString();
String json = gson.toJson(baseInfo);
//以下是Json字符串转换成对象的示例:
Gson gson = new Gson();
BaseInfo baseInfo = gson
.fromJson(txtJsonResult, BaseInfo.class);
5.子线程中通知主线程更新UI
在主线程中定义一个Handle对象,代码如下:Handler handlerUserInfo = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
//这边写更新UI的操作
break;
}
}
};
然后在子线程中要更新UI的地方写上:
handlerUserInfo.sendEmptyMessage(0);
这里参数0就是上面的msg.What,主线程用来判断执行相应的代码;
6.运行效果截图
7.其它犯的一些错误:
1.页面需在AndroidManifest.xml注册;2.网络权限需在AndroidManifest.xml注册;
3.Post请求时注意Url最后不要加/了;
错误元凶:String url = HttpHelper.BASE_URL + "RegistLogin";
当时在RegistLogin后面又加了一个/导致出错,花了不少时间找这个错误;
4.子线程中也是不能跳转页面的,要通知主线程操作跳转页面;
5.页面的对象在定义后别忘了实例化;
错误元凶:TextView gidRegist = null;
定义后没有实例化,然后取值时报错;这个错误好找,但也要有耐心看那英文错误;
6.最后一个就是本地ip地址啦(这个没出错,友情提醒一下),
计算机本地地址是127.0.0.1而对应的Android本地是10.0.2.2;
至此全部完成,只是个人的一些实践,对自己是一个记录,同时希望也能对别人有些帮助,如果有什么错误,还望不吝指出,共同进步,转载请保留原文地址。