写在前面的话
首先说几句,我只是一个android小白,在本科毕设时做了一款简单的测试题app,界面难看不说,功能还非常容易实现,不过从此我对android产生了浓厚的兴趣。在研究生入学之前,老板要求我们来学校暑期培训,我的培训任务就是继续完善这款app(添加功能和美化UI)。于是从7月下旬忙到现在,总算像一款app了。不过说实话,既要实现功能,又要美化界面;既要做客户端,还要做服务端,真的是挺蛋疼的。
好了,废话不说了,直奔主题吧。先从android存储方式说起,第一版的时候,我要存数据,我看的书上介绍了4种:SharedPreference、Sqlite、文件流、db4o(这个貌似很小众)。什么都不懂的我选择了语法最简单的SP,而且当时需要存储的数据也不多,我就将就用了。培训期间,根据要求我把存储方式改成了Sqlite(本来就应该是这样 = =!),心好累。然而在这个改动过程中,由于自己对Sql数据库一点都不了解,就默默地留下了一个坑,细节就不说了,都是泪。再后来,就前不久,师兄说用户需求是把数据存储到云端,所以你接着改吧,顺便加上登录注册模块。我像没头的苍蝇一样搞了一周,也算是实现了。这中间的道路非常曲折,各种问题,各种蛋疼。于是我才有了写下来的想法,一来总结记录自己的收获,二来分享我遇到的问题给大家,让后来人少走弯路。
正文
不就是连接数据库吗?打开百度(还不习惯Google),搜索“android连接服务器数据库”,果然一堆文章。然而当时的我连什么是服务器都不懂(其实现在我也说不清楚),看了一上午,我大概知道了,连接数据库有直接和间接两种方式:直接的话通过JDBC驱动(微软官方的和民间的),间接的话就是通过服务器和数据库交互,服务器可以是java web、webservice、wcf或者java application。那还想什么,直连多方便(too young = =!),文章也是现成的,于是我就参考某大牛的博客开始尝试。然并卵,整整两天没调出来。也许博主是调试通过了的,但是直连真的好么?其实不好,一个小小的android客户端和一个大型的数据库直接交互,你觉得安全吗?(调不出来,强行找台阶= =!)虽然不符合逻辑不实用,不过你们可以去试试。
果断换成间接连接,参考文章:http://blog.csdn.net/zhyl8157121/article/details/8169172。说实话,大神博主写得非常详细,在此衷心地表达一下感谢。不过,我觉得有些地方还是有点不实用(额 = =!,并不是强行装x)。首先服务端,由于安全性问题,我把webservice换成了wcf;其次客户端,原博中写的HttpConnSoap类连接webservice太繁琐,不如ksoap2-android简单实用。接下来,我就大致说说我的做法,有什么不对的地方或者有什么更好的建议和意见,欢迎批评指正,可骂可赞。有任何问题都可以联系我,邮箱:21515046@zju.edu.cn。
数据库
我连接的数据库是服务器的数据库,它用的sql server 2008 R2。按照一般步骤来:先建库,再建表,然后设计表,注意设置字段的约束,比如是否可以为null、是否为主键、是否自增、是否需要联合主键等等。
服务端
首先vs创建项目:
项目结构如下:
连接数据库:
视图 -> 其它窗口 -> 服务器资源管理器 或者 视图 -> 服务器资源管理器
右键 -> 添加连接。我这里是连接服务器的数据库,所以使用SQL Server身份验证,服务器名填IP地址。如果连接本地数据库的话就使用Windows身份验证。测试一下是否可以连接,可以就点确定。
右键->属性,复制连接字符串,等会要用到。
在DBOperation中写操作契约和数据契约,操作契约就是你要调用的方法名,数据契约就是自定义的复杂数据类型,比如我这里的个人信息和测试数据。
namespace ADWebService_WCF
{
[ServiceContract(Namespace = "http://xxxx.org/")]//自定义命名空间
public interface DBOperation
{
[OperationContract]
bool IsUserNameExist(string UserName);
[OperationContract]
bool IsPasswordMatch(string UserName, string password);
[OperationContract]
List<Info> GetAllInfo(string UserName);
[OperationContract]
List<TestData> GetAllTestData(string UserName);
...
}
[DataContract]
public class Info
{
string UserName;
string password;
string UserId;
string name;
string sex;
string age;
string job;
string edu;
string num;
[DataMember]
public string Username
{
get { return UserName; }
set { UserName = value; }
}
[DataMember]
public string Password
{
get { return password; }
set { password = value; }
}
...
}
在ADWebService.svc.cs中写操作的具体实现。
namespace ADWebService_WCF
{
[ServiceBehavior(Namespace = "http://xxxx.org/")]//自定义命名空间时,这里也要加上
public class ADWebService : DBOperation
{
public static SqlConnection sqlCon;
private String ConServerStr = @"Data Source=115.28.xx.xxx;Initial Catalog=AD;Persist Security Info=True;User ID=sa;Password=******";//刚才复制的连接字符串,记得把******改成真正的密码。
//打开数据库
private void OpenDB()
{
sqlCon = new SqlConnection();
sqlCon.ConnectionString = ConServerStr;
sqlCon.Open();
}
//关闭数据库
private void CloseDB()
{
sqlCon.Close();
}
public bool IsUserNameExist(string UserName)
{
...
}
public bool IsPasswordMatch(string UserName, string password)
{
...
}
//原博文返回的是string数组,如下面两行所示。那样的话返回值的形式不好看,客户端也不好解析
//操作的实现:public List&l