视频项目笔记(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!

阅读全文
0 0
原创粉丝点击