一、效果展示
二、实现步骤
与上个版本相比,修改了一些点:
- 修改了密码存储方式,上次是用的使用sharedPreferences记住密码,这次用的SQLite数据库存储。
- 增加焦点改变监听器的功能,在点击密码栏的时候,会先对手机号检查是否合法,合法的话去数据库查找密码,如果上次是记住密码的话,就会自动填充密码。
实现记住密码功能中,虽然使用共享参数实现了记住密码功能,但是该方案只能记住一个用
户的登录信息,并且手机号码跟密码没有对应关系,如果换个手机号码登录,前一个用户的登录信息就 被覆盖了。真正的记住密码功能应当是这样的:先输入手机号码,然后根据手机号码匹配保存的密码, 一个手机号码对应一个密码,从而实现具体手机号码的密码记忆功能。 现在运用数据库技术分条存储各用户的登录信息,并支持根据手机号查找登录信息,从而同时记住多个 手机号的密码。
XML代码没变,还是原来的。
Java代码:
Mainactivity.java
import android.os.Bundle;
import android.os.CountDownTimer;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RadioGroup;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.example.helloworld.util.HideInputMethod;
import com.example.helloworld.util.LoginInfo;
public class MainActivity extends AppCompatActivity implements View.OnFocusChangeListener {
private EditText et_phone;
private EditText et_password;
private EditText et_verification;
private final MyCountDownTimer myCountDownTimer=new MyCountDownTimer(60000,1000);
private Button bt_CountDown;
private LoginDBHelper mHelp;
private CheckBox cb_remember_the_password;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RadioGroup r=findViewById(R.id.radio);
LinearLayout l_verification=findViewById(R.id.l_verification);
LinearLayout l_password=findViewById(R.id.l_password);
et_phone = findViewById(R.id.et_phone);
et_password = findViewById(R.id.et_password);
et_verification = findViewById(R.id.et_verification);
cb_remember_the_password = findViewById(R.id.cb_remember_the_password);
CheckBox cb_consent_accord=findViewById(R.id.cb_consent_accord);
Button bt_login=findViewById(R.id.bt_login);
Button bt_verify=findViewById(R.id.bt_verify);
//设置密码登录或验证码登陆的单选状态改变监听器
r.setOnCheckedChangeListener((group, checkedId) -> {
if(checkedId==R.id.r_verification) {
l_password.setVisibility(View.GONE);
l_verification.setVisibility(View.VISIBLE);
cb_remember_the_password.setVisibility(View.GONE);
}
else {
l_verification.setVisibility(View.GONE);
l_password.setVisibility(View.VISIBLE);
cb_remember_the_password.setVisibility(View.VISIBLE);
}
});
//文本框设置文本改变监听器,到最大长度后自动收起键盘
et_phone.addTextChangedListener(new HideTextWatcher(et_phone,11));
et_password.addTextChangedListener(new HideTextWatcher(et_password,16));
et_verification.addTextChangedListener(new HideTextWatcher(et_verification,6));
//设置焦点改变监听器
et_password.setOnFocusChangeListener(this);
et_verification.setOnFocusChangeListener(this);
//设置获取验证码按钮的点击事件
bt_verify.setOnClickListener(v->{
if(Check(et_phone)) {
bt_CountDown=bt_verify;
myCountDownTimer.start();
}
});
//设置登陆按钮的点击事件
bt_login.setOnClickListener(v -> {
if(cb_consent_accord.isChecked()) { //判断是否勾选用户协议
if(r.getCheckedRadioButtonId()==R.id.r_password) { //判断登陆类型
String p=et_password.getText().toString();
String ph=et_phone.getText().toString();
if(p.length()>=8) { //不可能输入超过16位,因为编辑框限制了最大长度
LoginInfo info=new LoginInfo();
info.phone=Long.parseLong(ph);
info.password=p;
info.remember= cb_remember_the_password.isChecked();
//密码保存
mHelp.save(info);
Toast.makeText(this, "登陆成功!等待页面跳转...", Toast.LENGTH_SHORT).show();
}
else
Toast.makeText(this, "请输入正确的密码!", Toast.LENGTH_SHORT).show();
}
else {
String verification=et_verification.getText().toString();
if(verification.length()==6)
Toast.makeText(this, "登陆成功!等待页面跳转...", Toast.LENGTH_SHORT).show();
else
Toast.makeText(this, "验证码错误!", Toast.LENGTH_SHORT).show();
}
}
else
Toast.makeText(this, "请同意并勾选用户协议和隐私政策协议", Toast.LENGTH_SHORT).show();
});
}
@Override
protected void onStart() {
super.onStart();
mHelp = LoginDBHelper.getInstance(this,1);
mHelp.openReadLink();
mHelp.openWriteLink();
reload();
}
@Override
protected void onStop() {
super.onStop();
mHelp.closeLink();
}
private void reload() {
LoginInfo info=mHelp.queryTop();
if(info!=null){
et_phone.setText(String.valueOf(info.phone));
if(info.remember)
{
et_password.setText(String.valueOf(info.password));
cb_remember_the_password.setChecked(true);
}
}
}
private Boolean Check(EditText et){
if(et.getId()==R.id.et_phone){
String text=et.getText().toString();
if(text.isEmpty()||text.length()<11){
et.requestFocus();
Toast.makeText(this, "请输入11位手机号", Toast.LENGTH_SHORT).show();
return false;
}
else
return true;
}
else return true;
}
@Override //重写焦点变换监听器
public void onFocusChange(View v, boolean hasFocus) {
Check(et_phone);
if (v.getId() == R.id.et_password && hasFocus) {
LoginInfo info=mHelp.queryByPhone(et_phone.getText().toString());
if(info!=null) //自动填写密码
et_password.setText(info.password);
}
}
private class HideTextWatcher implements TextWatcher {
EditText editText;
int maxLength;
HideTextWatcher(EditText ed,int max){
editText=ed;
maxLength=max;
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
public void onTextChanged(CharSequence s, int start, int before, int count) {}
public void afterTextChanged(Editable s) {
if(s.length()==maxLength) //隐藏输入法
HideInputMethod.hideInput(MainActivity.this,editText);
}
}
private class MyCountDownTimer extends CountDownTimer {
public MyCountDownTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
@Override
public void onTick(long millisUntilFinished) {
Log.e("计时器","正在运行");
bt_CountDown.setClickable(false);
bt_CountDown.setText(millisUntilFinished/1000+"秒");
}
@Override
public void onFinish() {
bt_CountDown.setClickable(true);
bt_CountDown.setText("重新获取");
}
}
}
LoginDBHelper.java
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.example.helloworld.util.LoginInfo;
public class LoginDBHelper extends SQLiteOpenHelper {
private static final String DB_NAME="login.db"; //数据库名称
private static final String TABLE_NAME="login_info"; //表的名称
private static final int DB_VERSION=1; //数据库的版本号
private static LoginDBHelper mHelper=null; //数据库帮助器的实例
private SQLiteDatabase mRDB=null; //数据库读连接实例
private SQLiteDatabase mWDB=null; //数据库写连接实例
private LoginDBHelper(Context context){ //单例默认构造方法为私利
super(context,DB_NAME,null,DB_VERSION);
}
private LoginDBHelper(Context context, int version)
{
super(context,DB_NAME,null,version);
}
//利用单例模式获取数据库帮助器的唯一实例
public static LoginDBHelper getInstance(Context context, int version){
if(version>0&&mHelper==null)
mHelper=new LoginDBHelper(context,version);
else if(mHelper==null)
mHelper=new LoginDBHelper(context);
return mHelper;
}
//打开数据库的读连接
public SQLiteDatabase openReadLink(){
if(mRDB==null || !mRDB.isOpen())
mRDB=mHelper.getReadableDatabase();
return mRDB;
}
//打开数据库的写连接
public SQLiteDatabase openWriteLink(){
if(mWDB==null || !mWDB.isOpen())
mWDB=mHelper.getWritableDatabase();
return mWDB;
}
//关闭数据库连接
public void closeLink(){
if(mRDB!=null||mRDB.isOpen())
{
mRDB.close();
mRDB=null;
}
if(mWDB!=null||mWDB.isOpen())
{
mWDB.close();
mWDB=null;
}
}
@Override
public void onCreate(SQLiteDatabase db) {
//创建表
String Create_sql= String.format("CREATE TABLE IF NOT EXISTS %s ( id Integer PRIMARY KEY AUTOINCREMENT NOT NULL ,phone LONG UNIQUE NOT NULL ,password VARCHAR NOT NULL ,remember INT NOT NULL);", TABLE_NAME);
db.execSQL(Create_sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public int update(LoginInfo info){
ContentValues content=new ContentValues();
content.put("phone",info.phone);
content.put("password",info.password);
content.put("remember",info.remember);
return mWDB.update(TABLE_NAME,content,"phone=?",new String[]{String.valueOf(info.phone)});
}
public int deleteByPhone(String phone){
return mWDB.delete(TABLE_NAME,"phone=?",new String[]{phone});
}
public void save(LoginInfo info){
try {
//事务开始,使用事务是防止删除后没添加上的问题
mWDB.beginTransaction();
deleteByPhone(String.valueOf(info.phone));
insert(info);
mWDB.setTransactionSuccessful();
}catch (Exception e){
e.printStackTrace();
}finally {
mWDB.endTransaction();
}
}
public int deleteAll(){
return mWDB.delete(TABLE_NAME,"1=1",null);}
public long insert(LoginInfo info){
ContentValues content=new ContentValues();
content.put("phone",info.phone);
content.put("password",info.password);
content.put("remember",info.remember);
//如果第三个参数content为null或者元素个数为0 第二个参数则做为缺省参数
return mWDB.insert(TABLE_NAME,null,content);
}
//查找最后一个登陆的账号,也就是id最大的账号
public LoginInfo queryTop() {
LoginInfo info=null;
String sql_query=String.format("Select * FROM %s ORDER BY id DESC LIMIT 1",TABLE_NAME);
Cursor cursor=mRDB.rawQuery(sql_query,null);
if(cursor.moveToNext())
{
info=new LoginInfo();
info.phone=cursor.getLong(1);
info.password=cursor.getString(2);
info.remember=cursor.getInt(3)==1?true:false;
}
return info;
}
//用于查找记住密码的账号密码
public LoginInfo queryByPhone(String phone){
LoginInfo info=null;
String sql_query=String.format("Select * FROM %s WHERE phone = %s ORDER BY id DESC LIMIT 1",TABLE_NAME,phone);
Cursor cursor=mRDB.rawQuery(sql_query,null);
if(cursor.moveToNext())
{
info=new LoginInfo();
info.phone=cursor.getLong(1);
info.password=cursor.getString(2);
info.remember=cursor.getInt(3)==1?true:false;
}
return info;
}
}
LoginInfo.java
public class LoginInfo {
public long phone;
public String password;
public boolean remember;
public LoginInfo(){
}
public LoginInfo(long phone, String password) {
this.phone = phone;
this.password = password;
}
@Override
public String toString() {
return "LoginInfo{" +
"phone=" + phone +
", password='" + password + '\'' +
'}';
}
}