这是【Android学习之路】之从零开始做一个小项目的第二篇,欢迎阅读~
① 在第一篇汇报的进度下进行了登录注册页面和功能的大换血!
② 手机短信验证已经莫得问题,适应十分良好
③ 在操纵数据库方面有了很大改善
④ 解决了上一期中读取数据库数据不正确的问题
对于这次的拖更我很抱歉,因为前几天一直在冲刺计算机大赛的最后阶段,所以这篇博客写了前前后后四五天都迟迟没有更新,周一的时候遇到的深坑困住了我,我想了想得先把它解决了再写博客总结叭,然后就与之战斗到了周二(相应的深坑在下面的内容中会讲到)
在第一期的博客中,我的登录和注册都在同一个一面(而且当时有一个数据库读取数据相关的bug,所以我加上了需要点击两次注册的说明,其实是为了先避开这个bug):
这周我已经解决了这个bug,或者说我换了一种方式来进行数据库数据的读取和比较等操作,当然这个一会儿会做讲解,现在先聊一聊我在登陆和注册页面的改进~
① 教师用户:
当你从初始页面中选择了【我是教师】之后跳转至教师页面(这里的登录界面并没有大的改变,主要是修改了【注册】按钮的功能,让其跳转至教师注册页面)
还有就是对账号的注册和输入格式进行了一定的限制
(因为登录按钮点击后的对输入内容的检查功能除了刚刚提到的账号格式限制外,和第一期的并没有什么大变化,所以这里就以注册界面及功能为主进行讲解)
点击【注册】按钮后:销毁当前Activity并跳转至教师注册页面,我采用了手机短信验证的方式对教师用户的注册设置一定的限制(提前录入允许注册的手机号,而且在知道可用于注册的手机号后还需获得它的验证码,如果不是自己的手机一般不会知道其短信验证码是多少,所以一定程度上增强了安全性),同时我对输入的手机号采用正则表达式进行了校验,不允许输入不正确的手机号,如下所示:
public static boolean checkTel(String tel){
Pattern p = Pattern.compile("^[1][3,4,5,7,8,9][0-9]{9}$");
Matcher matcher = p.matcher(tel);
return matcher.matches();
}
手机格式正确的情况下会进一步验证数据库中该手机号是否已经和用户绑定(具体代码一会在数据库改进讲解之后贴出来),这里先进行演示:
可看到上图中,我先是输入了一个我之前注册用过的手机号,点击【获取验证码】按钮后,查询到数据库中已有与该手机号绑定的用户,所以弹出弹窗提示用户,同时将输入框清空。然后我用另一个手机号进行注册,成功获取验证码(这里接受验证码时的短信提示窗口被我顺手给划掉了,,没事一会下面还有截图能看得到)
— — — — — — — — — — — — — — — — —
获取到验证码后填入账号和密码,这里同样也对输入框中的内容进行了检验,账号为英文和数字的组合,不超过10个字符,同时账号和密码输入框均不能为空,为空则注册失败且弹出弹窗提示。
需要注意的是:当注册失败(即不满足格式要求)被弹窗提示后当前验证码失效,需要重新获取,下图对该过程进行演示:
重新获取验证码并填写后,点击【注册】,因为Henry
这个账号之前已经被我注册过了,数据库中已经有其信息,所以当然也是注册失败啦,弹窗提示的同时清空除了手机号以外的其他输入框,如下图所示:
好了,终于把目前各种可能出现的情况都演示完了,下面就好好地注册一个账号叭~
我这里账号就取名为HQ(忘记截图了,,不过一会登录成功可以看到),成功注册后注销当前页面同时跳转至教师登录页面,弹窗提示注册成功,如下图:
我这里就不演示登录过程了哈,一些检验啥的和第一期里的基本一致,直接放上登陆成功的截图:
— — — — — — — — — — — — — — — — — — — — — — — — — — — —
② 学生用户:
如果从初始页面中选择的是【我是学生】之后跳转至学生登录页面:
点击【注册】按钮后:销毁当前Activity并跳转至学生注册页面,我采用了学生学号验证的方式对学生用户的注册设置一定的限制(提前录入允许注册的学号,这里的安全性暂时不如教师注册的安全性强,以后会加上【忘记密码】功能,同样采取手机号绑定的方式增强其安全性),我提前录入的学号有下面的十个(下一步打算将其存储于数据库中,当数据库初始化的时候自动插入在数据库内):
public class IDUtils {
public static String[] studentID= {"202001","202002","202003","202004","202005","202006","202007","202008","202009","202010"};
}
这里对学号的检测演示如下图所示:
同样的,学生端注册也具有对输入的账号和密码的检验,账号为英文和数字的组合,不超过10个字符,同时账号和密码输入框均不能为空,为空则注册失败且弹出弹窗提示,因为和教师端的大同小异,这里就不做演示啦,当注册成功后进行登录,同样的登陆成功后跳转至学生端的个人页面,同时弹窗提示:
上一期,也就是第一阶段中,我采用的是在需要用到数据库的类中实例化DBOpenHelper(我定义的数据库帮助类),读取数据时采用的是cursor读取后存入HashMap中,然后将其存入一个ArrayList中,再利用对这个ArrayList来进行和输入框中数据的比较。
这样的方式下有一个bug就是我总是读取不到第一条数据(当然这是我目前水平的原因,,以后能力提升之后会好好研究一下为啥读不到第一条数据),所以需要注册两次,这样数据库中一条信息就被存储了两遍,没有必要而且在注册时判断用户是否已存在也不方便,终于在我查阅了很多写法之后用了以下的方式很好地解决了这个问题:
① 首先改变了DBOpenHelper的写法:
// public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
// super(context, name, null, version); //重写构造方法并设置factory为null
// }
public DBOpenHelper(Context context){
super(context, "mySchool.db", null, 1);
}
运用了Context,Android程序员把“场景”抽象为Context类,他们认为用户和操作系统的每一次交互都是一个场景,在应用程序中Context的具体实现子类就是:Activity,Service,Application。
② 我新建了一个bean包,目前里面有TeacherBean和StudentBean两个类,把要在操作数据库时会重复多次运用到的东西放在了里面,如下:
package com.henry.myschoolsystem.bean;
public class StudentBean {
public String userName; //账号
public String nickName; //昵称
public String sex; //性别
public String qq; //QQ号
public String wechat; //微信号
public String motto; //个性签名
public String ID; //学生学号
public String password; //密码
}
package com.henry.myschoolsystem.bean;
public class TeacherBean {
public String userName; //账号
public String nickName; //昵称
public String sex; //性别
public String qq; //QQ号
public String wechat; //微信号
public String motto; //个性签名
public String phoneNumber; //教师手机号
public String password; //密码
}
③ 同时新建了DBUtils类来写对数据库的相关操作方法,现在我的utils包中已有四个自定义的工具类:
DBUtils类完整代码如下:
package com.henry.myschoolsystem.utils;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.henry.myschoolsystem.bean.StudentBean;
import com.henry.myschoolsystem.bean.TeacherBean;
import com.henry.myschoolsystem.ui.login.DBOpenHelper;
public class DBUtils {
private static DBUtils instance = null;
private static DBOpenHelper dbHelper;
private static SQLiteDatabase db;
/**
* 构造方法,只有当类被实例化时候调用
* 实例化DBOpenHelper类,从中得到一个可读写的数据库
**/
public DBUtils(Context context) {
dbHelper = new DBOpenHelper(context);
db = dbHelper.getWritableDatabase();
}
/**
* 得到这个类的实例
**/
public static DBUtils getInstance(Context context) {
if (instance == null) {
instance = new DBUtils(context);
}
return instance;
}
/**
* 保存教师资料信息
**/
public void saveTeacherInfo(TeacherBean teacherBean) {
ContentValues cv = new ContentValues();
cv.put("userName", teacherBean.userName);
cv.put("nickName", teacherBean.nickName);
cv.put("sex", teacherBean.sex);
cv.put("qq", teacherBean.qq);
cv.put("wechat",teacherBean.wechat);
cv.put("motto",teacherBean.motto);
cv.put("phoneNumber",teacherBean.phoneNumber);
cv.put("password",teacherBean.password);
db.insert(DBOpenHelper.TEACHER_INFO, null, cv);
}
/**
* 保存学生资料信息
**/
public void saveStudentInfo(StudentBean studentBean) {
ContentValues cv = new ContentValues();
cv.put("userName", studentBean.userName);
cv.put("nickName", studentBean.nickName);
cv.put("sex", studentBean.sex);
cv.put("qq", studentBean.qq);
cv.put("wechat",studentBean.wechat);
cv.put("motto",studentBean.motto);
cv.put("ID",studentBean.ID);
cv.put("password",studentBean.password);
db.insert(DBOpenHelper.STUDENT_INFO, null, cv);
}
// ---------------------------------------------------------------------------------------------
/**
* 通过账号获取教师资料信息
**/
public TeacherBean getTeacherInfo(String teacherName) {
String sql = "SELECT * FROM " + DBOpenHelper.TEACHER_INFO + " WHERE userName=?";
Cursor cursor = db.rawQuery(sql, new String[]{teacherName});
TeacherBean teacherBean = null;
while (cursor.moveToNext()) {
teacherBean = new TeacherBean();
//将对应用户名的所有数据从表中动态赋值给bean
teacherBean.userName = cursor.getString(cursor.getColumnIndex("userName"));
teacherBean.nickName = cursor.getString(cursor.getColumnIndex("nickName"));
teacherBean.sex = cursor.getString(cursor.getColumnIndex("sex"));
teacherBean.qq = cursor.getString(cursor.getColumnIndex("qq"));
teacherBean.wechat = cursor.getString(cursor.getColumnIndex("wechat"));
teacherBean.motto = cursor.getString(cursor.getColumnIndex("motto"));
teacherBean.phoneNumber = cursor.getString(cursor.getColumnIndex("phoneNumber"));
teacherBean.password = cursor.getString(cursor.getColumnIndex("password"));
}
cursor.close();
return teacherBean;
}
/**
* 通过手机号获取教师资料信息
**/
public TeacherBean getTeacherInfoByPhoneNum(String phone) {
String sql = "SELECT * FROM " + DBOpenHelper.TEACHER_INFO + " WHERE phoneNumber=?";
Cursor cursor = db.rawQuery(sql, new String[]{phone});
TeacherBean teacherBean = null;
while (cursor.moveToNext()) {
teacherBean = new TeacherBean();
//将对应用户名的所有数据从表中动态赋值给bean
teacherBean.userName = cursor.getString(cursor.getColumnIndex("userName"));
teacherBean.nickName = cursor.getString(cursor.getColumnIndex("nickName"));
teacherBean.sex = cursor.getString(cursor.getColumnIndex("sex"));
teacherBean.qq = cursor.getString(cursor.getColumnIndex("qq"));
teacherBean.wechat = cursor.getString(cursor.getColumnIndex("wechat"));
teacherBean.motto = cursor.getString(cursor.getColumnIndex("motto"));
teacherBean.phoneNumber = cursor.getString(cursor.getColumnIndex("phoneNumber"));
teacherBean.password = cursor.getString(cursor.getColumnIndex("password"));
}
cursor.close();
return teacherBean;
}
/**
* 通过账号获取学生资料信息
**/
public StudentBean getStudentInfo(String studentName) {
String sql = "SELECT * FROM " + DBOpenHelper.STUDENT_INFO + " WHERE userName=?";
Cursor cursor = db.rawQuery(sql, new String[]{studentName});
StudentBean studentBean = null;
while (cursor.moveToNext()) {
studentBean = new StudentBean();
//将对应用户名的所有数据从表中动态赋值给bean
studentBean.userName = cursor.getString(cursor.getColumnIndex("userName"));
studentBean.nickName = cursor.getString(cursor.getColumnIndex("nickName"));
studentBean.sex = cursor.getString(cursor.getColumnIndex("sex"));
studentBean.qq = cursor.getString(cursor.getColumnIndex("qq"));
studentBean.wechat = cursor.getString(cursor.getColumnIndex("wechat"));
studentBean.motto = cursor.getString(cursor.getColumnIndex("motto"));
studentBean.ID = cursor.getString(cursor.getColumnIndex("ID"));
studentBean.password = cursor.getString(cursor.getColumnIndex("password"));
}
cursor.close();
return studentBean;
}
/**
* 通过学号获取学生资料信息
**/
public StudentBean getStudentInfoByID(String id) {
String sql = "SELECT * FROM " + DBOpenHelper.STUDENT_INFO + " WHERE ID=?";
Cursor cursor = db.rawQuery(sql, new String[]{id});
StudentBean studentBean = null;
while (cursor.moveToNext()) {
studentBean = new StudentBean();
//将对应用户名的所有数据从表中动态赋值给bean
studentBean.userName = cursor.getString(cursor.getColumnIndex("userName"));
studentBean.nickName = cursor.getString(cursor.getColumnIndex("nickName"));
studentBean.sex = cursor.getString(cursor.getColumnIndex("sex"));
studentBean.qq = cursor.getString(cursor.getColumnIndex("qq"));
studentBean.wechat = cursor.getString(cursor.getColumnIndex("wechat"));
studentBean.motto = cursor.getString(cursor.getColumnIndex("motto"));
studentBean.ID = cursor.getString(cursor.getColumnIndex("ID"));
studentBean.password = cursor.getString(cursor.getColumnIndex("password"));
}
cursor.close();
return studentBean;
}
// ---------------------------------------------------------------------------------------------
/**
* 修改教师资料信息,这里的key指代表字段,value表示数值
**/
public void updateTeacherInfo(String key, String value, String userName) {
ContentValues cv = new ContentValues();
cv.put(key, value);
db.update(DBOpenHelper.TEACHER_INFO, cv, "userName=?", new String[]{userName});
}
/**
* 修改学生资料信息,这里的key指代表字段,value表示数值
**/
public void updateStudentInfo(String key, String value, String userName) {
ContentValues cv = new ContentValues();
cv.put(key, value);
db.update(DBOpenHelper.STUDENT_INFO, cv, "userName=?", new String[]{userName});
}
}
我在该类中写好各种需要用到的方法,到时候直接实例化DBUtils然后调用所需方法就行~
— — — — — — — — — — — — — — — —
好,准备工作已经完成,那现在以登录功能来说一说怎么用刚刚的这几个东西:
① 首先我在教师登录的TLoginActivity
类中添加以下的方法用于将DBUtils实例化并调用其通过账号获取教师信息的方法:
private TeacherBean getTeacherData(String key) {
TeacherBean bean = DBUtils.getInstance(this).getTeacherInfo(key);
return bean;
}
DBUtils中的getTeacherInfo()
方法如下:
/**
* 通过账号获取教师资料信息
**/
public TeacherBean getTeacherInfo(String teacherName) {
String sql = "SELECT * FROM " + DBOpenHelper.TEACHER_INFO + " WHERE userName=?";
Cursor cursor = db.rawQuery(sql, new String[]{teacherName});
TeacherBean teacherBean = null;
while (cursor.moveToNext()) {
teacherBean = new TeacherBean();
//将对应用户名的所有数据从表中动态赋值给bean
teacherBean.userName = cursor.getString(cursor.getColumnIndex("userName"));
teacherBean.nickName = cursor.getString(cursor.getColumnIndex("nickName"));
teacherBean.sex = cursor.getString(cursor.getColumnIndex("sex"));
teacherBean.qq = cursor.getString(cursor.getColumnIndex("qq"));
teacherBean.wechat = cursor.getString(cursor.getColumnIndex("wechat"));
teacherBean.motto = cursor.getString(cursor.getColumnIndex("motto"));
teacherBean.phoneNumber = cursor.getString(cursor.getColumnIndex("phoneNumber"));
teacherBean.password = cursor.getString(cursor.getColumnIndex("password"));
}
cursor.close();
return teacherBean;
}
② 在【登录】按钮被点击后,先是获取此时账号输入框中的内容,用trim()去除字符串两边的空格(如果有的话),然后先让TeacherBean实例为空,调用刚刚定义的方法后如果仍然为空,说明数据库中没有该用户,弹窗提示,如果不为空,就接着进行一系列的检验,用teacherBean.password
与输入框中获取到的MD5加密后的密码进行比较
//教师登录
btn_Login.setOnClickListener(new View.OnClickListener() { //单击登录按钮查看是否有该用户以及密码是否正确
@Override
public void onClick(View v) {
String teacher = usernameEditText.getText().toString().trim(); //获取输入的登录名
TeacherBean teacherBean = null;
teacherBean = getTeacherData(teacher);
if (teacherBean == null) {
Toast.makeText(TLoginActivity.this, "该账号不存在,请重新输入或注册!", Toast.LENGTH_SHORT).show();
} else {
String passwordIn = passwordEditText.getText().toString().trim(); //获取输入的密码
if (teacherBean.password.equals(MD5Utils.md5(passwordIn))) { //只是比较内容,不能用==
Toast.makeText(TLoginActivity.this, "登录成功!" + teacher + ",欢迎您~", Toast.LENGTH_LONG).show();
Intent intent = new Intent(TLoginActivity.this, TMainActivity.class); //登录成功跳转教师主界面
startActivity(intent);
finish();
} else {
Toast.makeText(TLoginActivity.this, "密码错误,请重新输入!", Toast.LENGTH_SHORT).show();
passwordEditText.setText("");
}
}
}
});
这样的查询比较方式比上一期的要更有条理,更清晰一些,而且 暂时未发现有bug,这是最开心的哈哈哈
上面的比较过程介绍之后,这里就不再详细介绍啦,因为就是实例化DBUtils类后调用的方法变为了保存信息的方法,这里以学生注册为例讲述一下:
① 首先在SRegisterActivity
类中添加以下三个方法(获取和保存学生信息):
//保存学生信息
private void insertStudent(StudentBean bean) {
DBUtils.getInstance(this).saveStudentInfo(bean);
}
//通过账号获取学生信息
private StudentBean getStudentData(String key) {
StudentBean bean = DBUtils.getInstance(this).getStudentInfo(key);
return bean;
}
//通过学号获取学生信息
private StudentBean getStudentDataByStudentNum(String id) {
StudentBean bean = DBUtils.getInstance(this).getStudentInfoByID(id);
return bean;
}
这里有两个方法来获取学生信息是因为,在注册时需要判断用户填写的学号是否已经绑定了已有用户,如果绑定了则不能再次注册,所以加上了通过学号获取学生信息的方法。
DBUtils中的saveStudentInfo()
方法、getStudentInfo()
方法和getStudentInfoByID()
如下:
/**
* 保存学生资料信息
**/
public void saveStudentInfo(StudentBean studentBean) {
ContentValues cv = new ContentValues();
cv.put("userName", studentBean.userName);
cv.put("nickName", studentBean.nickName);
cv.put("sex", studentBean.sex);
cv.put("qq", studentBean.qq);
cv.put("wechat",studentBean.wechat);
cv.put("motto",studentBean.motto);
cv.put("ID",studentBean.ID);
cv.put("password",studentBean.password);
db.insert(DBOpenHelper.STUDENT_INFO, null, cv);
}
/**
* 通过账号获取学生资料信息
**/
public StudentBean getStudentInfo(String studentName) {
String sql = "SELECT * FROM " + DBOpenHelper.STUDENT_INFO + " WHERE userName=?";
Cursor cursor = db.rawQuery(sql, new String[]{studentName});
StudentBean studentBean = null;
while (cursor.moveToNext()) {
studentBean = new StudentBean();
//将对应用户名的所有数据从表中动态赋值给bean
studentBean.userName = cursor.getString(cursor.getColumnIndex("userName"));
studentBean.nickName = cursor.getString(cursor.getColumnIndex("nickName"));
studentBean.sex = cursor.getString(cursor.getColumnIndex("sex"));
studentBean.qq = cursor.getString(cursor.getColumnIndex("qq"));
studentBean.wechat = cursor.getString(cursor.getColumnIndex("wechat"));
studentBean.motto = cursor.getString(cursor.getColumnIndex("motto"));
studentBean.ID = cursor.getString(cursor.getColumnIndex("ID"));
studentBean.password = cursor.getString(cursor.getColumnIndex("password"));
}
cursor.close();
return studentBean;
}
/**
* 通过学号获取学生资料信息
**/
public StudentBean getStudentInfoByID(String id) {
String sql = "SELECT * FROM " + DBOpenHelper.STUDENT_INFO + " WHERE ID=?";
Cursor cursor = db.rawQuery(sql, new String[]{id});
StudentBean studentBean = null;
while (cursor.moveToNext()) {
studentBean = new StudentBean();
//将对应用户名的所有数据从表中动态赋值给bean
studentBean.userName = cursor.getString(cursor.getColumnIndex("userName"));
studentBean.nickName = cursor.getString(cursor.getColumnIndex("nickName"));
studentBean.sex = cursor.getString(cursor.getColumnIndex("sex"));
studentBean.qq = cursor.getString(cursor.getColumnIndex("qq"));
studentBean.wechat = cursor.getString(cursor.getColumnIndex("wechat"));
studentBean.motto = cursor.getString(cursor.getColumnIndex("motto"));
studentBean.ID = cursor.getString(cursor.getColumnIndex("ID"));
studentBean.password = cursor.getString(cursor.getColumnIndex("password"));
}
cursor.close();
return studentBean;
}
② 当【注册】按钮被点击后,先是判断该学号是否合法,前面的内容有提到需要提前准备好允许注册的一组学号;当学号合法后令StudentBean实例为null,调用通过学号获取学生信息的方法进行判断该学号是否被绑定过,未绑定过则继续进行下一步验证,判断数据库中填入的该账号是否存在,已存在的话拒绝注册,并弹窗提示,同时将账号和密码输入框内容清空:
//学生注册
buttonRegister.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
studentNum = editTextStudentNum.getText().toString().trim();
userName2 = editTextUserName2.getText().toString().trim();
password2 = editTextPassword2.getText().toString().trim();
for (int i = 0; i < IDUtils.studentID.length; i++) {
if (studentNum.equals(IDUtils.studentID[i])) {
have = true;
break;
}
}
if (!have) {
Toast.makeText(SRegisterActivity.this, "该学号不存在,请重新填写", Toast.LENGTH_SHORT).show();
} else {
StudentBean bean = null;
//检查数据库中该学号是否已经被绑定
bean = getStudentDataByStudentNum(studentNum);
if (bean != null) {
Toast.makeText(SRegisterActivity.this, "该学号已绑定过用户!", Toast.LENGTH_SHORT).show();
} else {
if (userName2.equals("") || password2.equals("")) { //如果填写的用户名或密码为空时
Toast.makeText(SRegisterActivity.this, "账号或密码为空,请重新填写", Toast.LENGTH_SHORT).show();
} else {
StudentBean studentBean = null;
//实例化DBUtils2,同时调用其方法获取个人信息资料
studentBean = getStudentData(userName2);
if (studentBean != null) {
Toast.makeText(SRegisterActivity.this, "该用户已存在!", Toast.LENGTH_SHORT).show();
editTextUserName2.setText(""); //将输入框内容清除
editTextPassword2.setText("");
} else {
studentBean = new StudentBean();
studentBean.userName = userName2;
studentBean.nickName = "暂无";
studentBean.sex = "待定";
studentBean.qq = "待定";
studentBean.wechat = "待定";
studentBean.motto = "有点懒吖,啥都没写~";
studentBean.ID = studentNum;
studentBean.password = MD5Utils.md5(password2);
//保存到数据库
insertStudent(studentBean);
Toast.makeText(SRegisterActivity.this, "注册成功!", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(SRegisterActivity.this, SLoginActivity.class);
startActivity(intent);
finish(); //销毁本Activity
}
}
}
}
}
});
— — — — — — — — — — — — — — — —
对了,还有一开始给大家承诺的实现手机验证码功能的TRegisterActivity类完整代码差点忘了,我贴出来啦,一些关键的地方我都已经加上了注释:
package com.henry.myschoolsystem.ui.login;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.henry.myschoolsystem.R;
import com.henry.myschoolsystem.bean.TeacherBean;
import com.henry.myschoolsystem.utils.DBUtils;
import com.henry.myschoolsystem.utils.MD5Utils;
import com.henry.myschoolsystem.utils.SMSUtils;
import org.json.JSONException;
import org.json.JSONObject;
import cn.smssdk.EventHandler;
import cn.smssdk.SMSSDK;
public class TRegisterActivity extends AppCompatActivity {
private Button buttonCode, buttonRegister;
private EditText editTextPhoneNum, editTextCode, editTextUserName, editTextPassword;
private String phoneNum, code, userName, password;
private EventHandler eh;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tregister);
buttonCode = findViewById(R.id.buttonCode);
buttonRegister = findViewById(R.id.buttonRegister);
editTextCode = findViewById(R.id.editTextCode);
editTextPhoneNum = findViewById(R.id.editTextPhoneNum);
editTextUserName = findViewById(R.id.add_username);
editTextPassword = findViewById(R.id.add_password);
eh = new EventHandler() {
@Override
public void afterEvent(int event, int result, Object data) {
if (result == SMSSDK.RESULT_COMPLETE) {
//回调完成
if (event == SMSSDK.EVENT_SUBMIT_VERIFICATION_CODE) {
//提交验证码成功
runOnUiThread(new Runnable() {
@Override
public void run() {
userName = editTextUserName.getText().toString().trim();
password = editTextPassword.getText().toString().trim();
phoneNum = editTextPhoneNum.getText().toString().trim();
//如果填写的用户名或密码为空时
if (userName.equals("") || password.equals("")) {
Toast.makeText(TRegisterActivity.this, "账号或密码为空,请重新填写", Toast.LENGTH_SHORT).show();
} else {
TeacherBean bean = null;
bean = getTeacherData(userName);
if (bean != null) {
Toast.makeText(TRegisterActivity.this, "该用户已存在!", Toast.LENGTH_SHORT).show();
editTextUserName.setText(""); //将输入框内容清除
editTextPassword.setText("");
editTextCode.setText("");
} else {
bean = new TeacherBean();
bean.userName = userName;
bean.nickName = "暂无";
bean.sex = "待定";
bean.qq = "待定";
bean.wechat = "待定";
bean.motto = "有点懒吖,啥都没写~";
bean.phoneNumber = phoneNum;
bean.password = MD5Utils.md5(password);
//保存到数据库
insertTeacher(bean);
Toast.makeText(TRegisterActivity.this, "注册成功!", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(TRegisterActivity.this, TLoginActivity.class);
startActivity(intent);
finish(); //销毁本Activity
}
}
}
});
} else if (event == SMSSDK.EVENT_GET_VOICE_VERIFICATION_CODE) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(TRegisterActivity.this, "语音验证发送", Toast.LENGTH_SHORT).show();
}
});
} else if (event == SMSSDK.EVENT_GET_VERIFICATION_CODE) {
//获取验证码成功
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(TRegisterActivity.this, "验证码已发送", Toast.LENGTH_SHORT).show();
}
});
} else if (event == SMSSDK.EVENT_GET_SUPPORTED_COUNTRIES) {
Log.i("test", "test");
}
} else {
((Throwable) data).printStackTrace();
Throwable throwable = (Throwable) data;
throwable.printStackTrace();
Log.i("1234", throwable.toString());
try {
JSONObject obj = new JSONObject(throwable.getMessage());
final String des = obj.optString("detail");
if (!TextUtils.isEmpty(des)) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(TRegisterActivity.this, des, Toast.LENGTH_SHORT).show();
}
});
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
};
//注册一个事件回调监听,用于处理SMSSDK接口请求的结果
SMSSDK.registerEventHandler(eh);
buttonCode.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
phoneNum = editTextPhoneNum.getText().toString();
if (!phoneNum.isEmpty()) {
if (SMSUtils.checkTel(phoneNum)) { //利用正则表达式获取检验手机号
TeacherBean bean = null;
//检查数据库中该手机号是否已经被绑定
bean = getTeacherDataByPhoneNum(phoneNum);
if (bean != null) {
Toast.makeText(TRegisterActivity.this, "该手机号已绑定过用户!", Toast.LENGTH_SHORT).show();
editTextPhoneNum.setText(""); //将输入框内容清除
} else {
// 获取验证码
SMSSDK.getVerificationCode("86", phoneNum);
}
} else {
Toast.makeText(getApplicationContext(), "请输入有效的手机号", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getApplicationContext(), "请输入手机号", Toast.LENGTH_SHORT).show();
return;
}
phoneNum = editTextPhoneNum.getText().toString();
}
});
buttonRegister.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
code = editTextCode.getText().toString();
if (!code.isEmpty()) {
//提交验证码
SMSSDK.submitVerificationCode("86", phoneNum, code);
} else {
Toast.makeText(getApplicationContext(), "请输入验证码", Toast.LENGTH_SHORT).show();
return;
}
}
});
}
private void insertTeacher(TeacherBean bean) {
DBUtils.getInstance(this).saveTeacherInfo(bean);
}
private TeacherBean getTeacherData(String key) {
TeacherBean bean = DBUtils.getInstance(this).getTeacherInfo(key);
return bean;
}
private TeacherBean getTeacherDataByPhoneNum(String phone) {
TeacherBean bean = DBUtils.getInstance(this).getTeacherInfoByPhoneNum(phone);
return bean;
}
// 使用完EventHandler需注销,否则可能出现内存泄漏
@Override
protected void onDestroy() {
super.onDestroy();
SMSSDK.unregisterEventHandler(eh);
}
}
获取DBUtils实例需要在按钮的监听事件以及方法外部,可以像我这样重新写一个方法用于获取,一开始我直接写在了onClick(View v)方法体里,虽然它会提示让修改类型,不过修改后运行还是崩了,多次尝试后我决定另写一个方法来对DBUtils实例化并调用,然后直接在onClick(View v)方法体中调用这个方法即可,再次实验,nice,解决了问题~
在需要用到TeacherBean或StudentBean的地方,都是需要到数据库中查询后看返回的结果是否为空,这里需要注意的是,要先令其实例=null,像下面的这样,然后再调用以及判断:
TeacherBean teacherBean = null;
teacherBean = getTeacherData(teacher);
if (teacherBean == null) {……}
当它结果不为空之后,对于登录来说,就是进行密码的正确性判断了;不过对于注册功能来说,还需bean = new TeacherBean();
,再进行赋值,规范的完整写法像下面的这样:
TeacherBean bean = null;
bean = getTeacherData(userName);
if (bean != null) {
Toast.makeText(TRegisterActivity.this, "该用户已存在!", Toast.LENGTH_SHORT).show();
editTextUserName.setText(""); //将输入框内容清除
editTextPassword.setText("");
editTextCode.setText("");
} else {
bean = new TeacherBean();
bean.userName = userName;
bean.nickName = "暂无";
bean.sex = "待定";
bean.qq = "待定";
bean.wechat = "待定";
bean.motto = "有点懒吖,啥都没写~";
bean.phoneNumber = phoneNum;
bean.password = MD5Utils.md5(password);
//保存到数据库
insertTeacher(bean);
……
}
这个真的是一不小心就容易犯的错误,因为当组件量多了之后或者是多个页面的组件布局和功能很相似的时候就炒鸡容易出错,比如我这里的教师端和学生端,在登录页面上基本是一致的,所以组件的命名也很相似,两个页面的对应组件基本都是用序号区分或者是加上t和s前缀进行区分。然后当我在通过findViewById(R.id.editTextPhoneNum);
一一获取他们的时候,有的地方就会重复了,比如教师的获取了学生布局页面的,或者是重复获取……很多问题会在不经意间出现,,而且因为他们名字比较相像,当页面运行崩溃之后我主要是去看功能哪里出了问题,不怎么去检查这方面,然而在多次的经历之后我发现崩溃的原因大多数竟是因为id写错!!!
就像下面的这样:
因为是登录页面所以应该获取的id
是login_username
,然而我写的是注册页面的add_username
,像下面这样:
因为这种情况下它是不会报错的,但是一运行就会崩,,,因为上面的setContentView
填的是activity_tlogin
,而填错的add_username
是在activity_tregister
布局文件中的,这种错误真的犯了好多次,,我还反省自己到底哪个功能写的有问题,检查n遍也没找出来,新建一个module去运行相应的功能发现没问题后,我就更困惑了
然而,最后不经意间看到我竟然把id写错了,emmm,顿时既高兴发现了错误,但更多地还是想抽shi自己,在经历了这么多次之后,我现在遇到问题也会主动去认真查看自己的id啥的有没有写错,尽量不犯这种错误耽误了自己的进度
① 在上面注册页面的讲述时我有提到会增加【忘记密码】功能,通过与账号绑定的手机号获取短信验证码后重新设置密码,这个功能还是比较容易实现的,已经写好了修改数据库信息的功能了,目前只需添加相应的组件,调整一下布局,加上一个页面即可完成~
② 目前还有一点想法就是【课程表】页面做成类似下面这样的,每个小方块里的内容能动态地进行获取,当然也有一定的透明度调整,还打算加上用户可以自定义课程表背景图片的功能(因为可能导致内存泄漏,所以这个功能暂时不确定能否很好地实现),不过页面和数据的动态获取并不难,最近努力一下应该很快就能实现~
③ 因为在操纵数据库方面的障碍已经很好地克服了,短信验证也已没有问题,所以接下来尽快设计好各个页面然后添加相应功能即可,感觉路上畅通了许多
第二阶段因为同时遇到了其他的事情,进度不是很多,不过在数据库的操纵方面的突破我个人是很满意的,当解决了之前操纵数据库的问题后那种感觉真的,此时此刻我只能想出一个字来形容:爽!
因为已经完成了计算机大赛,这些天来的一个重担之一放下了,所以这周将会有更多的时间和精力投入到这个项目中,冲冲冲!
第一阶段传送:【Android学习之路】之从零开始做一个小项目(一)
第三阶段传送:【Android学习之路】之从零开始做一个小项目(三)
(ps:在最终项目完成后我会将项目源码上传至GitHub,目前发表出的代码中如有问题和需改进的地方希望大家发现后积极指出~)