之前接到了一个设计项目,实现的是基于Android平台的题库设计,就是类似于答题类的APP,包括选择题、判断题、简答题等,随机出题,判断答案是否正确,然后给出成绩单。所以分为多个模块出发,先从登录模块开始。
用户在开启APP之后,会选择去注册账号和密码,根据账号和密码选择和数据库的数据做比对,当数据库中一致时,就会登录进入主界面,那么用户数据的存储就使用SQLite数据库。
在之前的博客中,我详细地介绍过SQLite数据库的创建,通过SQLiteOpenHelper类来实现数据库及表的创建,然后通过getReadableDataBase或者getWriteableDataBase来获取数据库的连接对象,在获取数据库的连接对象时,就会调用onCreate方法,此时数据表也创建成功。
问题1:数据库和数据表什么时候创建合适?
我们第一次在使用到数据库功能的时候,是在注册环节,这个时候会往数据库中插入表数据,我们可以选择在这个时候创建数据库;还有一种方式,就是APP启动时,就将数据库初始化,我个人更倾向于后一种。
在APP启动时,会经历很多环节,其中就包括Application的初始化,这个时候会调用Applicaiton的onCreate()方法,那么我们可以在onCreate()方法中就初始化数据库,首先我们创建一个数据库管理对象DBManager。
public class DBManager {
private DBManager(){}
private static DBManager manager = new DBManager();
public static DBManager getInstance(){
return manager;
}
}
然后在Application的onCreate()方法区获取这个DBManager的单例。
public class MyApplication extends Application {
//定义全局的上下文对象
private static Context mContext;
@Override
public void onCreate() {
super.onCreate();
mContext = this;
//注册初始化数据库
DBManager.getInstance().init();
}
public static Context getGloableContext(){
return mContext;
}
}
我们看到在onCreate()方法中执行了init方法,这个方法就是来初始化数据库和表。
//得到数据库操作帮助类
private static BankDBHelper helper = new BankDBHelper(MyApplication.getGloableContext());
//数据库连接对象
private static SQLiteDatabase db;
//得到数据库的连接对象,初始化建表sql语句
public void init() {
db = helper.getReadableDatabase();
}
public static SQLiteDatabase getDb(){
return db;
}
如此一来,在APP启动的时候,会执行DBManager的init方法,这个方法中就初始化了数据库和表,得到了数据库的连接对象。
(1)注册模块
在注册界面,需要输入用户名和密码,在做一系列的非空判断和非法判断之后,确定输入的用户名和密码都是合法且有效的时候,那么就将用户名和密码插入数据表中
else{
//insert into table(name,password) values(123,123);
String sql = "insert into "+ LoginTable.TABLE_NAME+ "("+LoginTable.COL_NAME+","+LoginTable.COL_PASSWORD+")" +
" values("+username+","+password1+")";
DBManager.getDb().execSQL(sql);
//该字段表示是否注册成功
isRegisterSuccess = true;
}
当注册成功之后,就跳转到登录界面去登录
if(isRegisterSuccess){
//注册成功去登录
startActivity(new Intent(RegisterActivity.this,
LoginActivity.class));
//变量还原
isRegisterSuccess = false;
finish();
}else{
//提示注册失败信息
Toast.makeText(RegisterActivity.this,"注册失败",
Toast.LENGTH_SHORT).show();
}
(2)登录界面
首先查询输入的用户名是否是在数据库中存在,如果没有存在,那么就提示用户未注册,需要去注册;如果是注册过的,那么就判断密码是否匹配,如果都通过,那么就成功登录。
写了两个在登录时肯定会用到的操作类,很方便使用。一个是查询表中所有的注册用户名,另一个是根据用户名查询密码;还是那句话,如果对sql语句掌握不熟练,建议还是使用api操作。
/**
* 登录表的操作类
*/
public class LoginTableDao {
/**
* 得到数据表中全部用户注册的用户名
*/
public static List<String> getUserName(){
List<String> list = new ArrayList<>();
String sql = "select name from "+LoginTable.TABLE_NAME+";";
Cursor cursor = DBManager.getDb().rawQuery(sql, null);
while(cursor.moveToNext()){
String name = cursor.getString(cursor.getColumnIndex(LoginTable.COL_NAME));
list.add(name);
}
return list;
cursor.close();
}
/**
* 根据用户名查询密码
* @param name 用户名
*/
public static String getPassword(String name){
String sql = "select "+LoginTable.COL_PASSWORD+" from "+LoginTable.TABLE_NAME+" where "+LoginTable.COL_NAME+" = ?;";
Cursor cursor = DBManager.getDb().rawQuery(sql, new String[]{name});
if(cursor.moveToNext()){
String password = cursor.getString(cursor.getColumnIndex(LoginTable.COL_PASSWORD));
return password;
cursor.close();
}
return null;
}
通过这两个方法,在登录时就会做判断,如果其中有一个环节有误,那么登录操作就会报出提示。
List<String> userList = LoginTableDao.getUserName();
if(!userList.contains(username)){
Toast.makeText(LoginActivity.this,"该用户名未注册",Toast.LENGTH_SHORT).show();
}else if(!LoginTableDao.getPassword(username).equals(password)){
Toast.makeText(LoginActivity.this,"密码不正确",Toast.LENGTH_SHORT).show();
}else {
startActivity(new Intent(LoginActivity.this,
MainActivity.class));
//保存登录状态
SPUtils.getInstance().saveState("login",true);
finish();
}
以上就是本项目的一个简单的登录模块的制作,当然还有开发的空间,之后有优化的时候,会在此更新。
还有一个问题,之前在更新博客的时候忘记了,就是我们在登录成功之后,退出APP,再次登录后,会判断我们是否之前登录过,如果之前登录过,那么就不需要再登录,直接进入主界面。
对于登录状态的保存,通常使用SP存储,因此写了一个工具类
public class SPUtils {
private SPUtils(){};
private static SPUtils instance = new SPUtils();
//SP存储对象
private static SharedPreferences sp;
public static SPUtils getInstance(){
if(sp == null){
sp = MyApplication.getGloableContext().getSharedPreferences("bank",
Context.MODE_PRIVATE);
}
return instance;
}
//保存数据
public void saveState(String key,Object value){
if(value instanceof String){
sp.edit().putString(key, (String) value).commit();
}else if(value instanceof Boolean){
sp.edit().putBoolean(key, (Boolean) value).commit();
}else if(value instanceof Integer){
sp.edit().putInt(key, (Integer) value).commit();
}
}
//获取数据
public String getState(String key,String defValue){
return sp.getString(key,defValue);
}
public Boolean getState(String key,Boolean defValue){
return sp.getBoolean(key,defValue);
}
public Integer getState(String key,int defValue){
return sp.getInt(key,defValue);
}
}
然后在我们登录成功之后,会将这个状态值保存在本地,然后在欢迎界面,会判断本地bank.xml文件中是否保存了这个登录的信息,如果是,那么直接进入主界面,否则还是得执行登录和注册操作。
//判断如果登录过,那么直接进入主界面
if(SPUtils.getInstance().getState("login",false)){
startActivity(new Intent(SplashActivity.this,MainActivity.class));
}else {
//没有登陆过,那么就显示登录按钮登录
btn_login.setVisibility(View.VISIBLE);
btn_register.setVisibility(View.VISIBLE);
}```