视频项目笔记(3)
来源:互联网 发布:淘宝评价管理系统 编辑:程序博客网 时间:2024/06/07 13:31
天天防腐笔记(3)
坚持看视频,忘记的东西只能铭记
- 1、说明注册的流程,这里盗用老师的讲解图片
所以要实现的是如何调用这个验证码接口,还有处理注册后页面跳转后所有问题,包括界面以及数据的存储
- 2、使用html样式去实现界面
// html方式设置文字样式不一mUserAgreementTv.setText(Html.fromHtml("我已阅读并同意<font color='#24cfa2'>《天天防腐》用户协议</font>"));
- 3、验证码功能实现(老师给的代码直接拿来用)
首先我们来分析一下要声明有几种状态:
1)能够点击 - ->设置一个正常的状态
2)不能点击稍后 - ->向后台请求数据呈现的样子 多久之后可以再次获取
3)倒计时状态- ->停止获取验证码
然后写对应状态的代码,开启handler不断去更新状态,计算每一秒过去后按钮上数字的变化,如果秒数>0就减去一,接着往下继续倒数,否则就停止,这就是handler里面要做的事情
package com.gzucm.daydayfanfu.ui;import android.annotation.SuppressLint;import android.content.Context;import android.content.res.ColorStateList;import android.content.res.TypedArray;import android.graphics.drawable.Drawable;import android.os.Handler;import android.os.Message;import android.text.Editable;import android.text.TextWatcher;import android.util.AttributeSet;import android.widget.Button;import android.widget.EditText;import com.gzucm.daydayfanfu.R;import com.gzucm.daydayfanfu.Util.GeneralUtil;@SuppressLint("HandlerLeak")public class VerificationCodeButton extends Button { private int mTime; private String mNormalStr; private ColorStateList mNormalColorList; private Drawable mNormalDrawable; private int mTimerBackground; private int mTimerColor; // Bind input box private EditText mBindPhoneEt; // 是否开始加载 private boolean mStartLoad = false; /** * 利用handler做计时器 */ private Handler mHandler = new Handler() { public void handleMessage(Message msg) { if (mTime > 0) { mTime -= 1; timer(); } else { stopRequest(); } }; }; public VerificationCodeButton(Context context) { this(context, null); } public VerificationCodeButton(Context context, AttributeSet attrs) { this(context, attrs, 0); } public VerificationCodeButton(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // 获取之前的属性(方便将它设置为正常状态) mNormalStr = getText().toString(); mNormalColorList = getTextColors(); mNormalDrawable = getBackground(); TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.VerificationCodeButton); // 计时的时候背景 mTimerBackground = array.getResourceId( R.styleable.VerificationCodeButton_timing_background, 0); mTimerColor = array.getColor( R.styleable.VerificationCodeButton_timing_textColor, 0); array.recycle(); } /** * 设置一个正常状态 */ @SuppressLint("NewApi") public void setNormal() { this.setEnabled(true); this.setText(mNormalStr); this.setTextColor(mNormalColorList); this.setBackground(mNormalDrawable); } /** * 向后台请求数据呈现的样子 */ public void startLoad() { mStartLoad = true; this.setEnabled(false); setAttribute(); this.setText(" 请稍后... "); } private void setAttribute() { if (mTimerBackground != 0) { this.setBackgroundResource(mTimerBackground); } if (mTimerColor != 0) { this.setTextColor(mTimerColor); } } /** * 多久之后可以再次获取 * * @param time */ public void aginAfterTime(int time) { setAttribute(); this.mTime = time; // 一旦开始计时,这个按钮就不能点击了 this.setEnabled(false); timer(); } /** * 停止获取验证码 */ private void stopRequest() { mStartLoad = false; setNormal(); } /** * 计时开始获取 */ private void timer() { this.setText(formatDuring(mTime)); mHandler.sendEmptyMessageDelayed(0, 1000); } private CharSequence formatDuring(int mTime) { if (mTime < 10) { return "0" + mTime + "秒后重获"; } return mTime + "秒后重获"; } /** * Binding a telephone box */ public void bindPhoneEditText(EditText editText) { this.mBindPhoneEt = editText; this.setEnabled(false); setAttribute(); // 监听输入框的状态改变 this.mBindPhoneEt .addTextChangedListener(phoneNumbersAddSpacesTextWatcher); } /** * 自动添加空格的TextWatcher */ private TextWatcher phoneNumbersAddSpacesTextWatcher = new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (s == null || s.length() == 0) return; StringBuilder sb = new StringBuilder(); for (int i = 0; i < s.length(); i++) { if (i != 3 && i != 8 && s.charAt(i) == ' ') { continue; } else { sb.append(s.charAt(i)); if ((sb.length() == 4 || sb.length() == 9) && sb.charAt(sb.length() - 1) != ' ') { sb.insert(sb.length() - 1, ' '); } } } if (!sb.toString().equals(s.toString())) { int index = start + 1; if (sb.charAt(start) == ' ') { if (before == 0) { index++; } else { index--; } } else { if (before == 1) { index--; } } mBindPhoneEt.setText(sb.toString()); mBindPhoneEt.setSelection(index); } // 上面就是加空格的逻辑 // Number is correct first, and then control VerificationCodeButton this is available String trimStr = removeAllSpace(sb.toString()); if(GeneralUtil.judgePhoneQual(trimStr) && !mStartLoad){ // If is phone VerificationCodeButton is able setNormal(); }else{ // Else VerificationCodeButton is enable VerificationCodeButton.this.setEnabled(false); setAttribute(); } } @Override public void afterTextChanged(Editable s) { } }; public static String removeAllSpace(String str) { String tmpstr = str.replace(" ", ""); return tmpstr; }}
在验证码的监听事件中,点击后就开始获取没法点击
case R.id.send_code_bt: // 按钮点击,向后台发送请求 // 1.把按钮置为请稍后状态 mSendCodeBt.startLoad(); // 2.请求 requestUserCode(); // 3.获取后台返回值之后判断后台反馈,如果成功倒计时,否则你要把按钮的状态置又可以点
然后我们使用okHttp先发起对服务器的请求requestUserCode()
- - > 处理验证码接口返回的数据 dealCodeResult() ,此时我们需要开启一个handler去post一个线程,这个Runnable()的run方法是运行在主线程的,所以就可以更新UI , 这里可以参考 我的第一篇笔记,里面也遇到过这个问题
private void requestUserCode() { // 向后台发送请求 // 1.本地验证 String userPhone = mUserPhoneEt.getText().toString().trim(); if(TextUtils.isEmpty(userPhone)){ Toast.makeText(this,"请输入手机号",Toast.LENGTH_LONG).show(); return; } // 2.往后台提交数据 // OKhttp // 1.创建一个OkhttpClient对象 OkHttpClient okHttpClient = new OkHttpClient(); // 2.构建参数的body MultipartBody.FORM 表单形式 MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM); // 2.2封装参数 builder.addFormDataPart("appid", "1"); builder.addFormDataPart("sms_type","3"); builder.addFormDataPart("cell_phone",userPhone); // 添加多个参数 // 3. 构建一个请求 post 提交里面是参数的builder url()请求路径 Request request = new Request.Builder().url("http://v2.ffu365.com/index.php?m=Api&c=Util&a=sendVerifyCode") .post(builder.build()).build(); // 4.发送一个请求 okHttpClient.newCall(request).enqueue(new Callback() {// 请求的回调 @Override public void onFailure(Call call, IOException e) { // 失败 } @Override public void onResponse(Call call, Response response) throws IOException { // 这个不是运行在主线程中 // 成功 数据在response里面 获取后台给我们的JSON 字符串 String result = response.body().string(); Log.e("TAG", result); Gson gson = new Gson(); UserRequestCodeResult codeResult = gson.fromJson(result, UserRequestCodeResult.class); dealCodeResult(codeResult); } }); } /** * 处理请求验证码的返回接口 * @param codeResult */ private void dealCodeResult(final UserRequestCodeResult codeResult) { mHandler.post(new Runnable() { @Override public void run() { // 3.获取后台返回值之后判断后台反馈,如果成功倒计时,否则你要把按钮的状态置又可以点 if(codeResult.errcode == 1){ mSendCodeBt.aginAfterTime(60); }else{ Toast.makeText(UserRegisterActivity.this,codeResult.errmsg,Toast.LENGTH_LONG).show(); mSendCodeBt.setNormal();// 按钮恢复默认 } } }); }
- 4、注册逻辑
case R.id.user_register_bt: dealUserRegister(); break;
这里进行本地验证,证明本地有输入注册信息,然后去访问后台,得到后台返回的JSON字符串(就是UserLoginResult类),这里有个注意的地方,就是此时返回的是登录的状态,不需要我们去再次登录,所以就可以跳转界面了,此时又得开启handler去更新界面,使用SharedPreferences设置登录状态为true , 然后把JSON字符串保存在该文件中。
模拟注册成功,先关闭当前页面,然后关闭登录页面,调用自己的activity管理类关闭其他页面。
private void dealUserRegister() { // 1.本地验证 String userPhone = mUserPhoneEt.getText().toString().trim(); String password = mUserPasswordEt.getText().toString().trim(); String userCode = mUserCodeEt.getText().toString().trim(); if(TextUtils.isEmpty(userPhone)){ Toast.makeText(this,"请输入用户名",Toast.LENGTH_LONG).show(); return; } if(TextUtils.isEmpty(password)){ Toast.makeText(this,"请输入密码",Toast.LENGTH_LONG).show(); return; } if(TextUtils.isEmpty(userCode)){ Toast.makeText(this,"请输入验证码",Toast.LENGTH_LONG).show(); return; } // 2.往后台提交数据 // OKhttp // 1.创建一个OkhttpClient对象 OkHttpClient okHttpClient = new OkHttpClient(); // 2.构建参数的body MultipartBody.FORM 表单形式 MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM); // 2.2封装参数 美团 20 15公共参数 builder.addFormDataPart("appid", "1"); builder.addFormDataPart("verify_code",userCode); builder.addFormDataPart("cell_phone",userPhone); // 添加多个参数 builder.addFormDataPart("password", password);// MD5 AES // 3. 构建一个请求 post 提交里面是参数的builder url()请求路径 Request request = new Request.Builder().url("http://v2.ffu365.com/index.php?m=Api&c=Member&a=register") .post(builder.build()).build(); // 4.发送一个请求 okHttpClient.newCall(request).enqueue(new Callback() {// 请求的回调 @Override public void onFailure(Call call, IOException e) { // 失败 } @Override public void onResponse(Call call, Response response) throws IOException { // 这个不是运行在主线程中 // 成功 数据在response里面 获取后台给我们的JSON 字符串 // 注册完之后不需要用户再次登录 返回的结果就是登录的结果 String result = response.body().string(); Log.e("TAG", result); Gson gson = new Gson(); final UserLoginResult loginResult = gson.fromJson(result, UserLoginResult.class); mHandler.post(new Runnable() { @Override public void run() { dealRegisterResult(loginResult); } }); } }); }
// 3.处理返回的数据 private void dealRegisterResult(UserLoginResult loginResult) { // 首先判断有没有成功 if(loginResult.getErrcode() == 1){ // 成功处理 // 1.需要保存登录状态 当前设置为已登录 SharedPreferences sp = getSharedPreferences("info",MODE_PRIVATE); sp.edit().putBoolean("is_login",true).commit(); // 2.需要保存用户信息 UserLoginResult.DataBean userData = loginResult.getData(); // SharedPreferences 怎么保存对象 把对象转为JSON String --> SharedPreferences Gson gson = new Gson(); String uesrInfoStr = gson.toJson(userData); // 保存的用户信息为Json格式的字符串 sp.edit().putString("user_info",uesrInfoStr).commit(); ActivityManagerUtil.getInstance().finishActivity(this); ActivityManagerUtil.getInstance().finishActivity(UserLoginActivity.class); }else{ // 登录失败 Toast.makeText(this,loginResult.getErrmsg(),Toast.LENGTH_LONG).show(); } }
- 5、活动的管理类,单例模式(开发时经常使用)
定义:只有一个实例在整个应用中,不适用于变化的对象
应用场景:某些操作配置的类(比如你要换应用的皮肤)、管理的一些类(本文管理Activity的类)、任务管理器、网站的计数器、数据库连接池的设计
考虑同步:在 if(mInstance == null) 里面可能两个线程进去后都在那里睡觉,睡完都有可能起来去new一个对象,这就不符合我们的单例模式了
public class ActivityManagerUtil { private Map<String,Activity> mActivitys; private static ActivityManagerUtil mInstance; //整个应用里面只有单个实例 //为什么私有,不让其他类new private ActivityManagerUtil(){ mActivitys = new HashMap<>(); } //其他地方需要用的获取方式 public static ActivityManagerUtil getInstance(){ if(mInstance == null){ //需要考虑线程并发以及同步问题 synchronized (ActivityManagerUtil.class){ if(mInstance == null){ mInstance = new ActivityManagerUtil(); } } } return mInstance; } //添加Activity public void addActivity(Activity activity){ mActivitys.put(activity.getClass().getName(),activity); } //关闭Activity public void finishActivity(Activity activity){ Activity finish = mActivitys.get(activity.getClass().getName()); finish.finish(); mActivitys.remove(activity.getClass().getName()); } //关闭Activity public void finishActivity(Class<? extends Activity> activityClazz){ Activity finish = mActivitys.get(activityClazz.getName()); finish.finish(); mActivitys.remove(activityClazz.getName()); }}
做到这里,我发现都是这样做的:去访问后台拿到数据解析,看要不要保存到本地文件记录,然后开启handler在主线程更新UI , 根据拿来的数据去判断UI界面的状态,我们拿到数据JSON,什么时候保存都可以,但是我们需要处理逻辑,在登录的时候才需要保存用户的信息,所以在这里才保存SharedPreferences。刷新了我对SharedPreferences的看法,好多地方我都看到它的身影,所以在项目中作为小型存储,是很不错的选择,又可以设置登录的状态,还可以保存用户信息,重新进入就可以不用重新登录。可以说,就是登录状态的控制器,用户信息的数据库。
天天防腐的视频教学第四天完成,谢谢老师的一番讲解,记录下来,方便以后遇到的问题可以查找帮助。Thank you!
- 视频项目笔记(3)
- 视频项目笔记(1)
- 视频项目笔记(2)
- 视频项目笔记(4)
- 视频项目笔记(5)
- 基于Z301P摄像头 H.264OK6410的远程视频web监控 项目笔记3(与外网通信)
- openCV学习笔记(3)-- 写入视频
- OC视频笔记-3
- OC视频笔记-3
- 笔记十八(视频)
- 搜车记项目演示(视频)
- Eclipse下为Android项目进行单元测试(传智播客视频笔记)
- 基于Z301P摄像头 H.264OK6410的远程视频web监控 项目笔记5(CGI)
- 基于mjpg-streamer远程视频WEB监控 项目笔记一
- 基于mjpg-streamer远程视频WEB监控 项目笔记二
- 基于mjpg-streamer远程视频WEB监控 项目笔记一
- 基于mjpg-streamer远程视频WEB监控 项目笔记二
- 手机影音项目笔记(二)-----视频播放处理
- Docker学习笔记之容器的四种网络模式
- 请输入星期几的第一个字母来判断一下是星期几
- MacOSX下C++调用Matlab
- 编译程序
- 1
- 视频项目笔记(3)
- 南大Mooc计算机体系基础--x32-86指令系统
- 揭密 Facebook 神秘的硬件团队,从 AR 到意识识别都在研究
- 专访 | 康力优蓝刘雪楠:基于物联网的沃土,机器人场景化需求会更加凸显
- P2 & 阿里巴巴跨界发布“神鲸” 智慧空间
- 北京知产法院:iPhone 6外观并未侵权,撤销停售决定
- Android5.0,6.0,7.0,8.0新特性整理
- 数据结构(C++) 栈-括号匹配与中缀转后缀
- 长续航+旗舰双摄!华硕鹰眼3拍照神器预约开启