Android客户端实现注册、登录详解(2)
上文中介绍了安卓客户端与服务器交互,实现注册功能,android客户端实现注册/登录详解(一)
本文将继续介绍app与服务器的交互实现登录和自动登录的功能,上文说到请求服务器进行注册主要是通过post请求携带参数实现,起作用的主要代码:
stringrequest request=new stringrequest(method.post, url, new listener<string>() { //请求成功 @override public void onresponse(string s) { //执行请求成功的回调 callback.onsuccess() } }, new errorlistener() { //请求错误 @override public void onerrorresponse(volleyerror volleyerror) { //执行请求失败的回调 callback.onfailure() } }){ //携带参数(map集合) @override protected map<string, string> getparams() throws authfailureerror { return parames; } }; //将请求添加到请求队列中 volley.newrequestqueue(context).add(request);
其实登录实现的原理也是一样的,同样是通过post请求,而在本demo中则是把请求服务器的方法封装在一起了,所以登录的实现也是调用了requestmanager网络请求处理类中的post方法
/** * post 请求数据 * * @param app_url 公共的接口前缀 http://www.itlanbao.com/api/app/ * @param tag_url 接口名称,eg:users/user_register_handler.ashx(注册接口) * @param parameter 请求参数封装对象 * @param clazz 返回数据封装对象,如果传null,则直接返回string * @param callback 接口回调监听 */ public static <t> void post(final string app_url, final string tag_url, final hashmap<string, string> parameter, class<t> clazz, final httpresponecallback callback) { //发送post请求服务器 post(app_url, tag_url, parameter, clazz, callback, priority.normal); }
demo演示
实现代码
1.服务器的数据格式
1.url: http://www.itlanbao.com/api/app/users/user_login_handler.ashx
2.参数说明:
email 必须有 邮箱
password 必须有 密码
accesstoken 必须有 md5(email+password+"双方平台约定公钥")
3.请求方式:post
4.返回值格式
成功
{ "ret":0, "errcode":0, "msg":"登录用户接口调用成功", "data":{ "userid":"16489", "email":"nnn@aaa.com", "nickname":"duss", "userhead":"http://img.itlanbao.com/avatar.png" } }
失败
{ "ret":1, "errcode":1, "msg":"账号或密码错误" }
2.登录界面(loginactivity),点击登录按钮
//点击登录按钮 loginbtn.setonclicklistener(new button.onclicklistener() { @override public void onclick(view v) { // todo auto-generated method stub string account = loginaccount.gettext().tostring();//账号 string password = loginpassword.gettext().tostring();//密码 if (!textutils.isempty(account) && !textutils.isempty(password) && utils.isemail(account)) { requestapidata.getinstance().getlogindata(account, password, userbaseinfo.class, loginactivity.this); } else { toast.maketext(loginactivity.this, "账号或者密码有误", toast.length_short).show(); } } });
核心代码为:
//传入账号名,密码,解析数据的bean对象和回调(这里传入的是自身,所以loginactivity也同样实现了回调接口httpresponecallback) requestapidata.getinstance().getlogindata(account, password, userbaseinfo.class, loginactivity.this);
3.网络接口类(requestapidata)
//创建接口对象 public static requestapidata getinstance() { if (instance == null) { instance = new requestapidata(); } return instance; } /** * 4.8登录用户接口 * @param email 邮箱 * @param password 密码 * @param clazz 数据返回的解析对象 * @param callback 回调 * 特别要注意参数位置不能变要根据文档来 * 请求方式:post */ public void getlogindata(string email ,string password, class<userbaseinfo> clazz, httpresponecallback callback) { mcallback = callback; //这是每一个接口的唯一标示 string tagurl = urlconstance.key_login_info;//登录接口 hashmap<string, string> parameter = new hashmap<string, string>(); parameter.put("email", email); parameter.put("password", password); //拼接参数信息,邮箱,密码,公钥,并用md5进行加密 stringbuilder builder = new stringbuilder(); builder.append(email); builder.append(password); builder.append(urlconstance.public_key); parameter.put(urlconstance.accesstoken_key,md5util.getmd5str(builder.tostring())); //请求数据接口 requestmanager.post(urlconstance.app_url,tagurl, parameter, clazz, callback); }
4.网络请求处理类(requestmanager)中请求数据,和注册执行了同样的方法,只是这里的传入的tag_url为登录的接口
/** * post 请求数据 * * @param app_url 公共的接口前缀 http://www.itlanbao.com/api/app/ * @param tag_url 接口名称,eg:users/user_login_handler.ashx(登录接口) * @param parameter 请求参数封装对象 * @param clazz 返回数据封装对象,如果传null,则直接返回string * @param callback 接口回调监听 */ public static <t> void post(final string app_url, final string tag_url, final hashmap<string, string> parameter, class<t> clazz, final httpresponecallback callback) { //发送post请求服务器 post(app_url, tag_url, parameter, clazz, callback, priority.normal); } /** * post 请求数据 * * @param app_url 路径 * @param url 接口名称 * @param parameter 请求参数封装对象 * @param clazz 返回数据封装对象,如果传null,则直接返回string * @param callback 接口回调监听 * @param priority 指定接口请求线程优先级 */ public static <t> void post(final string app_url, final string url, final hashmap<string, string> parameter, final class<t> clazz, final httpresponecallback callback, priority priority) { if (callback != null) { callback.onresponestart(url);//回调请求开始 } initrequestqueue(); //将公共的接口前缀和接口名称拼接 //eg:拼接成登录的接口 http://www.itlanbao.com/api/app/users/user_login_handler.ashx stringbuilder builder = new stringbuilder(app_url); builder.append(url); {// 检查当前网络是否可用 final networkutils networkutils = new networkutils(itlanbaolibapplication.getinstance()); if (!networkutils.isnetworkconnected() && android.os.build.version.sdk_int > 10) { if (callback != null) { callback.onfailure(url, null, 0, "网络出错");//回调请求失败 return; } } } /** * 使用volley框架真正去请求服务器 * method.post:请求方式为post * builder.tostring():请求的链接 * listener<string>:监听 */ stringrequest request = new stringrequest(method.post, builder.tostring(), new listener<string>() { @override public void onresponse(string response) { // todo auto-generated method stub // 这个位置先公共解析处理共同异常 try { if (response != null && callback != null) { gson gson = new gson(); //回调请求成功,同时url和解析的对象 callback.onsuccess(url, gson.fromjson(response, clazz)); } } catch (exception e) { // todo: handle exception if (callback != null) { //回调请求失败--解析异常 callback.onfailure(url, e, 0, "解析异常"); return; } } } }, new errorlistener() { //请求出错的监听 @override public void onerrorresponse(volleyerror error) { if (callback != null) { if (error != null) { callback.onfailure(url, error.getcause(), 0, error.getmessage()); } else { callback.onfailure(url, null, 0, ""); } } } }) { //post请求的参数信息 protected map<string, string> getparams() { return getpostapiparmes(parameter); } }; //添加请求到请求队列中 addrequest(request, url); } /* * post参数 * * ts:时间戳 sign: 接口签名 parms = 按文档参数拼接 parm[0]+ … + parm[n-1] sign = * md5(parms+"双方平台约定公钥") */ private static apiparams getpostapiparmes(final hashmap<string, string> parameter) { apiparams api = new apiparams(); for (entry<string, string> entry : parameter.entryset()) { api.with(entry.getkey(), entry.getvalue()); } return api; }
5.同样回到loginactivity中执行回调,失败则提示,成功则将登录信息保存到sp中和application中
@override public void onresponestart(string apiname) { // todo auto-generated method stub if (urlconstance.key_login_info.equals(apiname)) { toast.maketext(loginactivity.this, "正在加载数据中", toast.length_short).show(); } } @override public void onloading(string apiname, long count, long current) { // todo auto-generated method stub } @override public void onsuccess(string apiname, object object) { // todo auto-generated method stub if (urlconstance.key_login_info.equals(apiname)) { //邮箱登录返回数据 if (object != null && object instanceof userbaseinfo) { userbaseinfo info = (userbaseinfo) object; if (info.getret().equals(constant.key_success)) { //登录成功,保存登录信息 itlanbaoapplication.getinstance().setbaseuser(info);//保存到application中 //保存到sp中 userpreference.save(keyconstance.is_user_id, string.valueof(info.getuserid())); userpreference.save(keyconstance.is_user_account, info.getemail()); userpreference.save(keyconstance.is_user_password, loginpassword.gettext().tostring()); intent intent = new intent(); intent.setclass(loginactivity.this, mainactivity.class); startactivity(intent); overridependingtransition(android.r.anim.slide_in_left, android.r.anim.slide_out_right); finish(); } else { log.e("tag", "info="+info.tostring()); if (info.geterrcode().equals(constant.key_no_regist)) { toast.maketext(loginactivity.this, "登录失败", toast.length_short).show(); } else { toast.maketext(loginactivity.this, info.getmsg(), toast.length_short).show(); log.e("tag", "info.getmsg()="+info.getmsg()); } } } } } @override public void onfailure(string apiname, throwable t, int errorno, string strmsg) { // todo auto-generated method stub toast.maketext(loginactivity.this, "failure", toast.length_short).show(); }
6.自动登陆的实现,其实就是我们在欢迎页面进行一个判断:读取sp中的信息,如有登录的信息,则取出,携带此信息请求服务器(同登录的请求),若成功,则直接跳转到主页面;如果登录不成功或者sp中没有保存的登录信息,则跳转到登录界面,代码如下(welcomeactivity中)
string useraccount = userpreference.read(keyconstance.is_user_account, null);//软件还没有保持账号 string userpassword = userpreference.read(keyconstance.is_user_password, null); string userid = userpreference.read(keyconstance.is_user_id, null); if (textutils.isempty(useraccount)) {//没有保存的登录信息跳转到登录界面 //空的,表示没有注册,或者清除数据 intent intent = new intent(); intent.setclass(welcomeactiviy.this, loginactivity.class); startactivity(intent); overridependingtransition(android.r.anim.slide_in_left, android.r.anim.slide_out_right); finish(); } else { //用保存的信息直接登录 requestapidata.getinstance().getlogindata(useraccount, userpassword, userbaseinfo.class, welcomeactiviy.this); } welcomeactivity也同样实现了httpresponecallback接口,所以传入的callback对象也是自身,我们在回调方法中判断是否登录成功 @override public void onresponestart(string apiname) { } @override public void onloading(string apiname, long count, long current) { } @override public void onsuccess(string apiname, object object) { //当前接口是否是获取用户的基本信息的接口 if (urlconstance.key_user_base_info.equals(apiname)) { if (object != null && object instanceof userbaseinfo) { userbaseinfo info = (userbaseinfo) object; itlanbaoapplication.getinstance().setbaseuser(info);//把数据放入到application里面,全局 userpreference.save(keyconstance.is_user_id, string.valueof(info.getuserid())); intent intent = new intent(); intent.setclass(welcomeactiviy.this, mainactivity.class); startactivity(intent); overridependingtransition(android.r.anim.slide_in_left, android.r.anim.slide_out_right); finish(); } else { toast.maketext(welcomeactiviy.this, "加载失败", toast.length_short).show(); } } else if (urlconstance.key_login_info.equals(apiname)) {//当前接口是登录的接口 //登录返回数据 if (object != null && object instanceof userbaseinfo) { userbaseinfo info = (userbaseinfo) object; if (constant.key_success.equals(info.getret())) { itlanbaoapplication.getinstance().setbaseuser(info);//将用户信息保存在application中 userpreference.save(keyconstance.is_user_id, string.valueof(info.getuserid())); intent intent = new intent(); intent.setclass(welcomeactiviy.this, mainactivity.class); startactivity(intent); overridependingtransition(android.r.anim.slide_in_left, android.r.anim.slide_out_right); finish(); } else { toast.maketext(welcomeactiviy.this, info.getmsg(), toast.length_short).show(); } } } } @override public void onfailure(string apiname, throwable t, int errorno, string strmsg) { toast.maketext(welcomeactiviy.this, "failure", toast.length_short).show(); }
demo下载地址:http://xiazai.jb51.net/201611/yuanma/androidlogindemo(jb51.net).rar
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。