2018-09-09 关于用户登录的过程(用Fragment去实

2018-09-30  本文已影响0人  仲夏之雪梦旅人

之前已经说过如何进行登录界面的编写,一个好的app是需要从用户的角度去出发的,我们登录界面不仅能提供用户密码登录,还应该能支持用户短信登录甚至是短信修改密码,这样就需要我们用更多的精力去优化我们的代码.首先说一下本篇文章的重点
1.关于如何进行Fragment的跳转
2.如何进行Fragment之前的传参
3.如何使从当前Fragment回退到我们需要的界面
4.如何使用mobSdk进行短信验证.
5.对于用户输入信息的判断.
这样,我们一点一点来分析,首先,我们需要进行Fragment的跳转。这个问题很重要,因为我们的界面肯定是有按键需求的,当用户按下一个键后,会要跳转到我们需要的界面上,上一篇文章在最后提到可以用接口回调的方式去实现,其实这样太麻烦了,我们可以用事务处理的方式去实现对Fragment管理.

public class FragmentTranscationUtil {
    //获取FragmentManager,开启事务,添加碎片
    public static void replaceFragment(FragmentActivity activity, Fragment fragment) {
        FragmentManager manager = activity.getSupportFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        transaction.setCustomAnimations(R.anim.activity_right_in, 0, 0, R.anim.activity_right_out);
        transaction.replace(R.id.userloginFrame_layout, fragment);
        transaction.addToBackStack(null);
        transaction.commit();
    }

    //获取FragmentManager,开启事务,添加碎片
    public static void replaceFragment(FragmentActivity activity, Fragment fragment, Bundle bundle) {
        FragmentManager manager = activity.getSupportFragmentManager();
        fragment.setArguments(bundle);
        FragmentTransaction transaction = manager.beginTransaction();
        transaction.setCustomAnimations(R.anim.activity_right_in, 0, 0, R.anim.activity_right_out);
        transaction.replace(R.id.userloginFrame_layout, fragment);
        transaction.addToBackStack(null);
        transaction.commit();
    }

这是一个帮助类,参数很简单,首先,我们要获取当前所在Activity,这个不用多说吗,因为Fragment多是嵌套在Activity里面的,第二个参数就是我们需要跳转的目标Fragment
下面第二个构造函数的第三个参数Bundle则是用来进行传参的.这个我下面会详细讲解
首先,我们要获取到FragmentManger的实例manger,然后manager.beginTransaction();
去开启事务,将我们需要执行的逻辑放入到事务中,在调用transaction.commit();去执行
就行了,这里顺便向大家展示一下Fragment生命周期
Fragment的生命周期和activity生命周期很像,其生命周期方法如下所示。

  1. onAttach:绑定到activity
  2. onCreate:创建fragment
  3. onCreateView: 创建fragment的布局
  4. onActivityCreated: activity创建完成后
  5. onStart: 可见, 不可交互
  6. onResume: 可见, 可交互
  7. onPause: 部分可见, 不可交互
  8. onStop:不可见
  9. onDestroyView: 销毁fragment的view对象
  10. onDestroy: fragment销毁了
  11. onDetach: 从activity解绑了
    下面给出FragmentTransaction的全部方法(API 24)转载自https://www.jianshu.com/p/5761ee2d3ea1

这样我们就解决了Fragment跳转问题,同时Fragment回退问题也给出了答案,那就是利用addToBackStack(String name)
我们知道Activity有任务栈,用户通过startActivity将Activity加入栈,点击返回按钮将Activity出栈。Fragment也有类似的栈,称为回退栈(Back Stack),回退栈是由FragmentManager管理的。

image

默认情况下,Fragment事务是不会加入回退栈的,如果想将Fragment加入回退栈并实现事物回滚,首先需要在commit()方法之前调用事务的以下方法将其添加到回退栈中:

我个人使用的是Mob开发者平台(http://sms.mob.com)注册,获取到Appkey和appSecret,这个非常重要

配置Gradle
1、打开项目根目录的build.gradle,在buildscrip–>dependencies 模块下面添加 classpath ‘com.mob.sdk:MobSDK:+’,如下所示;

buildscript {
    repositories {
        jcenter()
    }
 
    dependencies {
        ...
        classpath 'com.mob.sdk:MobSDK:+'
 
    }
}

2、在使用SMSSDK模块的build.gradle中,添加MobSDK插件和扩展,如:

// 添加插件
apply plugin: 'com.mob.sdk'

// 在MobSDK的扩展中注册SMSSDK的相关信息
MobSDK {
    appKey "d580ad5*****"//填写自己获取的appKey
    appSecret "7fcae59a******7e2759e9e397c82bdd"//填写自己获取的appSecret

    SMSSDK {}
}

这里面的appkey和appSecret是自己注册而获取到的.替换一下就行了,
3、初始化MobSDK
如果您没有在AndroidManifest中设置appliaction的类名,MobSDK会将这个设置为com.mob.MobApplication,但如果您设置了,请在您自己的Application类中调用:

MobSDK.init(this);

以初始化MobSDK。
具体代码
这里有两种方式去实现,一个是可视化界面,一个是非UI实现,
因为我个人是是使用无UI的方式,所以会讲述无Ui实现的方法,这里给出可视化界面的文档(http://wiki.mob.com/sdk-sms-android-3-0-0/
首先介绍一下EventHandler这是一个异步操作,和Handler类似所有的业务逻辑将会在这里处理,它是和registerEventHandler一起使用的,registerEventHandler是一个事件接收器,他是专门负责接收所有被触发的事件,而registerEventHandler本身可以注册多个,所有接收器也会在事件被触发时候接收消息.一般是配套使用,否则容易产生内存泄露
下面给出具体代码

 //请求短信验证码
    private void SendCode(String country, String number) {
        EventHandler eh = new EventHandler() {
            @Override
            public void afterEvent(int i, int i1, Object o) {
                if (i == SMSSDK.EVENT_GET_VERIFICATION_CODE) {//获取短信验证码事件
                    //获取验证码成功
                    if (i1 == SMSSDK.RESULT_COMPLETE) {
                        listener.getCodeSuccess();
                    } else if (i1 == SMSSDK.RESULT_ERROR) {
                        listener.getCodeFailure();
                    }
                }
            }
        };
        SMSSDK.registerEventHandler(eh);
        SMSSDK.getVerificationCode(country, number);
    }

可以看到这是我自定义的一个方法,首先获取国家,中国是86开头,没啥好说的,然后是你将要发送短信验证的用户手机号码,这也没啥好说的,至于listener是我自定义的接口,会统一处理事务逻辑.

 //提交验证码
    private void SubmitCode(String country, final String number, String code) {
        EventHandler eh = new EventHandler() {
            @Override
            public void afterEvent(int i, int i1, Object o) {
                if (i == SMSSDK.EVENT_SUBMIT_VERIFICATION_CODE) {//验证码提交事件
                    if (i1 == SMSSDK.RESULT_COMPLETE) {
                        //回调成功
                        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                        listener.submitCodeSuccesss(number, dateFormat.format(new Date()));
                    } else if (i1 == SMSSDK.RESULT_ERROR) {//提交验证码失败
                        listener.submitCodeFailure();
                    }
                }
            }
        };
        SMSSDK.registerEventHandler(eh);
        SMSSDK.submitVerificationCode(country, number, code);
    }

提交验证码多出一个你接收短信验证的信息code,其他都差不多的。
这里给出mob业务逻辑,可以最大限度自定义出符合你自己要求的业务逻辑。

Handler mhandle = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            int event = msg.arg1;
            int result = msg.arg2;
            Object data = msg.obj;

            if (event == SMSSDK.EVENT_SUBMIT_VERIFICATION_CODE) {//验证码提交事件
                if (result == SMSSDK.RESULT_COMPLETE) {
                    //回调成功
                    Toast.makeText(context, "提交验证码成功"+result, Toast.LENGTH_LONG).show();
                } else if (result == SMSSDK.RESULT_ERROR) {
                    Toast.makeText(context, "提交验证码失败"+data, Toast.LENGTH_LONG).show();
                }

            } else if (event == SMSSDK.EVENT_GET_VERIFICATION_CODE) {//获取短信验证码事件

                //获取验证码成功
                if (result == SMSSDK.RESULT_COMPLETE) {
                    Toast.makeText(context, "获取短信验证码成功", Toast.LENGTH_LONG).show();
                    boolean mobcheck = (Boolean) data;
                    if (mobcheck) {
                        //通过智能验证
                        Toast.makeText(context, "mob云验证", Toast.LENGTH_LONG).show();
                    } else {
                        //依然走短信验证
                        Toast.makeText(context, "短信验证", Toast.LENGTH_LONG).show();
                    }
                } else if (result == SMSSDK.RESULT_ERROR) {
                    Toast.makeText(context, "获取短信验证码失败"+data, Toast.LENGTH_LONG).show();
                }
            } else if (event == SMSSDK.EVENT_GET_SUPPORTED_COUNTRIES) {
                SMSSDK.getSupportedCountries();
            } else {

                try {
                    ((Throwable) data).printStackTrace();
                    Throwable throwable = (Throwable) data;
                    JSONObject jsonObject = new JSONObject(throwable.getMessage());
                    String des = jsonObject.optString("detail");
                    int status = 0;
                    status = jsonObject.optInt("status");
                    if (TextUtils.isEmpty(des)) {

                    }
                } catch (Exception e) {
                    SMSLog.getInstance().w(e);
                }
            }
        }
    };

Ps:SMSSDK已经做了混淆处理,再次混淆会导致不可预期的错误,请在您的混淆脚本中添加如下的配置,跳过对SMSSDK的混淆操作:

-keep class com.mob.**{*;}
-keep class cn.smssdk.**{*;}
-dontwarn com.mob.**

这个时候,大家可能就有疑问了,没有UI界面我如何去输入收到的短信验证码去验证,很简单,自己写个UI就行了啊,一般现在流行的界面可能就是如下图所示了,引用一下图片https://www.jianshu.com/p/91b0b8038dd5

1879314-56d1f0d5b902bfee.png

这位大牛的效果还是不错的,我说下自己的思路,简单的就是TextView+Edittext去组合实现的,下面,附上xml资源,大家可以详细了解一下

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/colorWhite">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/tv_code1"
            style="@style/codeTextView" />

        <View
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <TextView
            android:id="@+id/tv_code2"
            style="@style/codeTextView" />

        <View
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <TextView
            android:id="@+id/tv_code3"
            style="@style/codeTextView" />

        <View
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <TextView
            android:id="@+id/tv_code4"
            style="@style/codeTextView" />

        <View
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <TextView
            android:id="@+id/tv_code5"
            style="@style/codeTextView" />

        <View
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <TextView
            android:id="@+id/tv_code6"
            style="@style/codeTextView" />

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center"
        android:orientation="horizontal">

        <View
            android:id="@+id/view1"
            android:layout_width="40dp"
            android:layout_height="2dp"
            android:layout_gravity="bottom"
            android:background="@color/colorGray707061" />

        <View
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <View
            android:id="@+id/view2"
            android:layout_width="40dp"
            android:layout_height="2dp"
            android:layout_gravity="bottom"
            android:background="@color/colorGray707061" />

        <View
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <View
            android:id="@+id/view3"
            android:layout_width="40dp"
            android:layout_height="2dp"
            android:layout_gravity="bottom"
            android:background="@color/colorGray707061" />

        <View
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <View
            android:id="@+id/view4"
            android:layout_width="40dp"
            android:layout_height="2dp"
            android:layout_gravity="bottom"
            android:background="@color/colorGray707061" />

        <View
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <View
            android:id="@+id/view5"
            android:layout_width="40dp"
            android:layout_height="2dp"
            android:layout_gravity="bottom"
            android:background="@color/colorGray707061" />

        <View
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <View
            android:id="@+id/view6"
            android:layout_width="40dp"
            android:layout_height="2dp"
            android:layout_gravity="bottom"
            android:background="@color/colorGray707061" />

    </LinearLayout>

    <lf.com.android.blackfishdemo.view.CodeEditTextView
        android:id="@+id/et_code_text"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#00000000"
        android:inputType="number"
        android:longClickable="false"
        android:maxLength="6"
        android:textColor="#00000000" />

</RelativeLayout>

乍一看貌似很复杂,其实就是绘制了可以输入6位数的Textview和对应的下标Item,然后上面再被我自定义的EditText所覆盖


/**
 * 验证码控件,去掉传统EditText双击选中EditText的内容
 * 和去掉光标位置会随点击改变
 */
public class CodeEditTextView extends AppCompatEditText {
    private long lastTime = 0;

    public CodeEditTextView(Context context) {
        super(context);
    }

    public CodeEditTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CodeEditTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onSelectionChanged(int selStart, int selEnd) {
        super.onSelectionChanged(selStart, selEnd);
        this.setSelection(this.getText().length());
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN://判断点击事件,防止用户多次点击
                long currenTime = System.currentTimeMillis();
                if (currenTime - lastTime < 500) {
                    lastTime = currenTime;
                    return true;
                } else {
                    lastTime = currenTime;
                }
                break;


        }
        return super.onTouchEvent(event);
    }
}

自定义的Edittext首先会通过long currenTime = System.currentTimeMillis();获取到当前时间点,判断两个点击时间间隔,从而屏蔽双击事件,长按会走 onSelectionChanged这个方法,所以,设置光标始终在文本后面,也就屏蔽了长按事件
然后通过对Edittext事件进行TextWatcher监听(后面会详细讲解),依次将输入内容分写到Textview上,就完成了上面的效果.至此,如何使用短信验证就告一段落.
好了,同通过短信验证就意味着,用户登录过程已经接近尾声甚至已经结束了,但是,在这里,我还是想一起说了吧,因为短信验证不仅仅用于登录,也用于修改密码,而且,用户输入的内容我们要去判断,不可能用户随便输入一个文本我们就要对其进行一次短信验证吧,毕竟,喜欢找Bug的用户也不少,所以,我们要对用户输入的内容进行判断。这就是我么要说的5.对于用户输入信息的判断.在说这个之前,我先向大家介绍一下,什么是正则表达式
正则表达式是一种查找以及字符串替换操作。正则表达式在文本编辑器中广泛使用,比如正则表达式被用于:

 private void setEditTextLitener() {
        mEditText.addTextChangedListener(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) {

            }

            @Override
            public void afterTextChanged(Editable s) {
 
            }
        });
    }

我们可以通过监听afterTextChanged获取到输入内容,从而进行判断,然后去编写我们所需要的逻辑,至此,用户登录过程就完美结束了,欢迎大家留言,提出问题.谢谢大家的阅读。

上一篇下一篇

猜你喜欢

热点阅读