最近,同学的同学找我做了一款简单的安卓手机软件,第一次,一个人,做一个完整的项目。所以,在这里总结一下完整的开发流程和步骤,方便后来人入门学习。
其实,我是一个新手,没有系统的学过android也没有系统的学过WCF,这些都是自己一点一点尝试出来的。
先说一下我的基础:
- 安卓在三年前接触过,当时乱看一气。主要看的网站就是这个(http://www.fenby.com);
- 今年三月份,深入学习了数据库相关知识,对于数据的增删改查,三范式,E-R有了深刻了解;
- 今天五月份,负责一个软件开发的服务器端的接口编写,也就是用WCF技术实现接口。
如今,自己做了一个项目。下面开始正式的项目介绍。
本系统设计三部分内容:
- 数据库的设计;
- 服务器端接口开发;
- Android客户端功能实现和接口调用。
数据库的结构设计
说实话,数据库的设计完全就是另外一门技术,能够“设计表的结构,灵活使用增删改查等语句”,就够了。
设计的时候,要符合三范式,注意表和属性的命名规范即可。
在这里推荐大家使用一个PowerDesigner软件,这个软件上手快,可视化的方式设计E-R图,自动生成各种数据库系统sql脚本,还能快速生成用户字典等文本文件。在这里就不多说了,读者可以自己了解。这个软件只是提高效率仅此而已。
值得强调一下
前期使用阿里“云服务器ECS”,这一个服务器就够了,这个服务器及可以配置IIS发布站点也可以安装数据库,用这一个就够了。
后期,数据明显数据量剧增,就需要使用“阿里云数据库RDS”,使用MySQL数据库会比SQL Server 每个月的使用费用便宜一点,毕竟MySQL开源嘛,所以,推荐使用MySQL数据库。所以,最开始做项目的时候,就推荐使用MySQL数据库。
关于云服务器ECS
我还想说点:(反正我是第一次用的时候,好多迷惑)
- 上面说了,一开始部署的时候不用租用“阿里云数据库RDS”;
- 购买完以后,会给你服务器IP,自己设置账号密码以后,就可以在自己电脑上进行远程操作啦;
- 在服务器中发布站点和在自己电脑发布站点的步骤一样,没有什么特殊的。
远程操作:
- 开始菜单那输入 mstsc;
- 输入账号密码即可。
服务器端
服务器概述
这一部分主要由两部分组成:
- 接口的编写(VS 2013 的.NET平台WCF技术)
- 接口的部署(IIS)
接口的编写
本人第一次接触WCF技术的时候,是由一位在职场工作多年的技术经理告诉我的,也就是他带领我完成了今年五月份的项目。
要做好WCF部分工作,要注意一下几个方面:
- 什么是WCF技术?
- 怎么创建一个WCF工程?
- 怎么调试和运行一个WCF工程?
- WCF怎么和数据库建立链接?
- 怎么配置数据库服务器的连接地址(也就是IP)?
- 返回值用什么样的规范?如何编写返回值?
什么是WCF技术
这个大家自己百度就好了,我就不抄袭别人的东西了。( 传送门:WCF技术 - 百度百科 )。其实,我没管那么多,能用就行。
怎么创建一个WCF工程
这个,也来一个传送门吧!( 传送门:新建WCF项目 )
如何调试和运行一个WCF工程
在上面的博客连接中已经有说明,这里在强调一下。F5快速调试。(就是这么厉害)
WCF怎么和数据库建立连接
其实,WCF和SQL Server 还是很好连接的,毕竟都是微软自家东西( 传送门:WCF的数据库连接和访问 )
配置数据库服务器的连接地址(也就是IP)
不过,按照上面的方式,就把数据库的连接字符串写在程序内部了,如果服务器IP地址改变,或者更换服务器的时候,就需要重新打开原项目工程进行IP地址的修改(最终的编译结果会生成一个dll文件),这是一件我们不愿意做而且很麻烦的事情,所以,要注意,把连接字符串写在web.config文件中。这样就可以灵活的修改IP地址。(传送门:连接字符串的修改操作)
返回值用什么样的规范?如何编写返回值?
对于WCF而言,返回值都是用JSON串的形式返回的,所以,对于一般的查询结果我们可以自己拼接出来返回一个状态值。
例如:如果验证这个用户是否合法,就可以返回
- {"State" :1}表示合法;
- {“State” :0}表示不合法;
- {“State” :2}表示服务器异常。
当然,你还可以选择自己增加更多的内容。例如:
- {“UserID” :10001 , "Token" : "8fc043eb-0722-4c11-a0f4-8b9194066a35"} //返回用户ID和令牌(GUID)。
只要把你想要返回的东西以JSON格式返回就可以了,剩下的就是Android客户端的调用。如何调用,我们会后续讲解。
对于WCF返回JSON格式,有一个现成的dll文件,直接引用即可。( 传送门:用NuGet安装NewtonSoft.json )
IIS环境配置和接口发布
其实,对于这样的项目工程而言,接口的发布之前还需要Android端和接口在线调试。也就是说,一个人开打VS2013,另一个人打开ADT,面对面直接调试,这样VS端的可以打断点,当Android端的调用接口的时候,VS会自动停在断点处,这样调试和查看参数更加方便。(这个没有找到对应的传送门,后面讲解)
本节三部分组成:
- IIS环境配置
- 在线调试
- 接口发布
IIS环境的配置
在调试和接口发布之前,一定要配置好IIS环境。
关于IIS环境的配置,推荐两个博客结合安装( 传送门:IIS部署和WCF发布 IIS部署 )
这两个博客把WCF发布的内容也讲述了,其实,现在还没有到发布的时候,此时需要的是IIS配置好以后,进行在线调试,等一切都调试通过以后,就可以发布了。
在线调试
这个没有找到合适博客,在这里,本人说明一下。
打开IIS配置文件
按照上面的步骤,打开IIS配置文件。
找到对应的绑定
在VS调试的时候,你就可以知道自己的调试端口号是什么,然后就“ctrl + F”找到对应的端口即可,赋值当前行,把localhost改为本机IP地址,保存,关闭。
打开防火墙
如图,按照序号操作,为了简化文章长度,我把最后的显示结果截成此图,实际上,三个窗体的显示顺序整好与现在的层级显示关系相反。
剩下的就不说了,百度上有打开防火墙端口的教程。( 传送门:打开防火墙端口 )
添加服务
只需要把localhost修改为本机IP即可。
通过以上步骤,Android客户端就可以访问这个连接了。也就是,同一个局域网的用户,都可以访问这个网站了。
剩下的工作就是在线调试。
接口发布
这个接口发布和上面的调试有什么区别呢?
这个问题问的好。
- 上面的调试是在VS打开的情况下才可以访问,而且端口号是VS自己确定的;
- 此时的发布完全由自己控制,就是自己发布一个网站的过程,端口号(如果和上面的端口号不一样,要打开防火墙端口号)可以任意设置,而且不打开VS也可以访问网站。
在上文中已经发过博客链接,在这里,再发一次(传送门:WCF发布 重点看第三部分)
还有一点值得说明,在自己发布接口的根目录下,新建一个文件夹,用于存放签名且加固好的APK,以此来提供用户下载。
但是,在网页中,下载APK需要一些站点的设置,请看传送门( 如何配置IIS使其支持APK文件的下载 )
Android客户端的开发
此部分分为两部分设计:
- 基本的界面设计和控件使用触发事件的响应;
- 服务器接口调用。
界面的设计
不同软件类型的开发,使用的界面控件和布局效果肯定大不一样,所以,在这里,只说明本人在制作软件过程中使用到的相关技术和知识。
数据的存储问题
例如,当用户登陆过apk以后,肯定不希望下一次登录的时候还输入账号密码等信息,所以,此时需要把用户输入的数据进行本地存储,安卓平台有五种数据存储方式,我使用的是“用SharedPreferences存储数据”。这个相对简单,而且只是三两个数据,这个足够了。( 传送门:Android平台进行数据存储的五大方式 )
// 保存登录数据:账号,密码,ID,令牌 到 data 文件中 SharedPreferences sp2 = (LoginActivity.this).getSharedPreferences("data",MODE_PRIVATE); SharedPreferences.Editor editor = sp2.edit();// 获取编辑对象 //editor.clear(); editor.putString("USERID", uid); editor.putString("PASSWORD", psw_md5.getMD5(psw)); editor.putInt("ID", id); editor.putString("TOKEN", token); editor.commit();// 提交保存修改
// 用户退出,清空data中的数据 SharedPreferences sp = ExitActivity().getSharedPreferences("data", MODE_PRIVATE); SharedPreferences.Editor editor = sp.edit();// 获取编辑对象 editor.clear(); editor.commit();// 提交保存修改
自定义ListView控件
这个技术在安卓开发中利用的最多了,纵观网上各种做法,推荐这篇博客( 传送门:Android 自定义ListView)
ListView的滚动事件
如何监听ListView的滚动事件?如果内容滑动到最底部,如何加载新数据?
在网上发现了这篇文章,感觉不错,大家可以看看。( 传送门:ListView加载数据 )
其实,ListView加载数据的事件就是这个,在loadData()的地方写好自己的数据加载代码即可。
listview.setOnScrollListener(new OnScrollListener() { //AbsListView view 这个view对象就是listview @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) { if (view.getLastVisiblePosition() == view.getCount() - 1) { loadData(); } } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { lastItem = firstVisibleItem + visibleItemCount - 1 ; } });
就简单的列举几个吧!做项目的时候,每个人都会遇到各种不一样的问题,自己百度解决就好了。
接口调用
这才是,重点!!!
调用接口,编写客户端函数
对于WCF这样的服务器接口,一般来说,推荐使用KSOP。这个还是跟简单的,在服务器中,包含很多接口,那么在自己的客户端上,你就对应设计每个接口即可。
为了有所了解,请先看文章(传送门:Android平台调用WebService详解 Android调用WCF
Android调用C#的WebService),这三篇文章写的很好,很详细。
不过,我还是贴一段代码,来显示一下我认为的规范开发。
package com.DLMU.freeride.WCFService; import java.io.IOException; import org.ksoap2.SoapEnvelope; import org.ksoap2.serialization.SoapObject; import org.ksoap2.serialization.SoapSerializationEnvelope; import org.ksoap2.transport.HttpTransportSE; import org.xmlpull.v1.XmlPullParserException; import android.util.Log; public class Services { private static String NameSpace = "http://tempuri.org/"; private static String URL = "http://你的IP:端口号/Service1.svc"; private static String MethodName_login = "login"; public String Login(String phonenum, String password) { String methodName = MethodName_login; // 指定WebService的命名空间和调用的方法名 SoapObject soapObject = new SoapObject(NameSpace, methodName); // 设置需调用WebService接口需要传入的参数token soapObject.addProperty("phonenum", phonenum); soapObject.addProperty("password", password); // 生成调用WebService方法的SOAP请求信息,并指定SOAP的版本 SoapSerializationEnvelope envelope = new SoapSerializationEnvelope( SoapEnvelope.VER11); envelope.bodyOut = soapObject; // 设置是否调用的是dotNet开发的WebService envelope.dotNet = true; // 等价于envelope.bodyOut = rpc; envelope.setOutputSoapObject(soapObject); HttpTransportSE trans = new HttpTransportSE(URL); trans.debug = true; // 使用调试功能 try { // 调用WebService String SOAP_ACTION = "http://tempuri.org/IService1/" + methodName; Log.d("WCF", SOAP_ACTION); trans.call(SOAP_ACTION, envelope); } catch (IOException e) { System.out.println("IOException"); e.printStackTrace(); } catch (XmlPullParserException e) { System.out.println("XmlPullParserException"); e.printStackTrace(); } // 获取返回的数据 SoapObject result = (SoapObject) envelope.bodyIn; // 获取返回的结果 String json = null; if (result == null) { json = "接口调用失败"; } else { json = result.getProperty(0).toString(); } Log.d("WCF", json); return json; } }
注意这里,一个参数的大小写要和服务器接口的大小写保持一致,而且先后顺序也不能改变。
// 设置需调用WebService接口需要传入的参数token soapObject.addProperty("phonenum", phonenum); soapObject.addProperty("password", password);
3.2.2 接口的实际调用
如果你认为,编写完对象中的方法就能直接调用,那你就错了。使用接口函数的时候还要注意一点。见代码
try { Thread thread = new Thread(new Runnable() { @Override public void run() { Services s = new Services(); String result = s.Login(uid, psw); if (result.length() >= 12) { //在我的接口中,定义{"State":0},表示账号密码错误,长度为11 //合法用户应该返回:{“UserID” :10001 , "Token" : "8fc043eb-0722-4c11-a0f4-8b9194066a35"},长度大于11 //所以用12来做比较 // 身份合理,正确跳转 Intent intent = new Intent( LoginActivity.this, MainActivity.class); startActivity(intent); finish(); } else { Looper.prepare(); Toast.makeText(LoginActivity.this, "账号或密码错误", Toast.LENGTH_SHORT) .show(); Looper.loop(); } } }); thread.start(); } catch (Exception e) { e.printStackTrace(); }
注意,接口调用要写在线程中,而且要try{}catch{}。
到此,接口的工作就完成了,因为接口返回的数据格式是JSON串,所以,需要在客户端进行JSON串解析。
//{ // [{"ID":1,"TEL":"123456"}], // [{"ID":2,"TEL":"123457"}], // [{"ID":3,"TEL":"123458"}], // [{"ID":4,"TEL":"123454"}] //} JSONTokener jsonTokener = new JSONTokener(data); JSONArray array = (JSONArray) jsonTokener.nextValue(); for (int i = 0; i < array.length(); i++) { // 提取数据 JSONObject item = array.getJSONObject(i); int id = item.getInt("ID"); String tel = item.getString("TEL"); }
根据上面的例子,我对于一个JSON串,如果遇到{[],[],[]},我们需要先使用JSONArray;如果遇到{},我们使用JSONObject来获取数据。
至此,教程结束。
一个上午的时间,都在编写这教程。
其实,做一个安卓手机联网软件不是很难。大家都可以试试。
其实就由两部分组成:客户端 + 服务器。
搞好客户端,写好服务器,做好客户端的接口调用,部署好服务器的站点,足矣。