我最近做项目用到了这个SQLite本地数据库,所以写篇博客总结一下,希望也能对小白有所帮助
SharedPreferences是一种轻型的数据存储方式,在保存数据的时候其实存储的是key-value对,类似于Map。存储位置:/data/data/应用包名/shared_prefs/文件名.xml。通常用来存储一些简单的配置信息。实际开发中,SharedPreferences共享参数经常存储的数据有App的个性化配置信息、用户使用App的行为信息、临时需要保存的片段信息等。
简单且孤立的数据可保存在SharedPreferences。若是复杂且相互间有关的数据,则要保存在数据库中。(有固定规则的,大量的数据保存在数据库中)
文本形式的数据可保存在SharedPreferences。若是二进制数据,则要保存在文件中。(没有固定规则的,大量的数据保存在文件中)
haredPreferences对象与SQLite数据库相比,免去了创建数据库,创建表,写SQL语句等诸多操作,相对而言更加方便,简洁。但是SharedPreferences也有其自身缺陷,比如其只能存储boolean,int,float,long和String五种简单的数据类型,比如其无法进行条件查询等。所以不论SharedPreferences的数据存储操作是如何简单,它也只能是存储方式的一种补充,而无法完全替代如SQLite数据库这样的其他数据存储方式。
SQLite是一个小巧的嵌入式数据库,使用方便、开发简单。它只是一个嵌入式的数据库引擎。在Android里,提供了SQLiteDatabase类,该类的一个对象就表明一个数据库,其实在底层就是一个文件。默认存储位置:/data/data/<PackageName>/databases
SQLiteDatabase是SQLite的数据库管理类,开发者可以在活动页面代码或任何能取到Context的地方获取数据库实例。然后通过SQLiteDatabase提供的一些API来对数据库进行操作:
// 创建名叫test.db的数据库。数据库如果不存在就创建它,如果存在就打开它 SQLiteDatabase db = openOrCreateDatabase(getFilesDir() + "/test.db", Context.MODE_PRIVATE, null); // 删除名叫test.db数据库 // deleteDatabase(getFilesDir() + "/test.db");
调用该类API要用到SQL语句,SQLite的多数SQL语法与Oracle一样,可以到菜鸟网上查阅:https://www.runoob.com/sqlite/sqlite-tutorial.html
SQLiteDatabase中常用的API:
1. 管理类,用于数据库层面的操作。
2. 事务类,用于事务层面的操作。
3. 数据处理类,用于数据表层面的操作。
但是直接通过SQLiteDatabase进行操作数据库非常不方便,必须小心不能重复地打开数据库,处理数据库的升级也很不方便。
因此Android提供了一个辅助工具—— SQLiteOpenHelper,我们可以通过SQLiteOpenHelper这个数据库帮助器来安全方便地打开、升级数据库。
使用方法:
新建一个继承自SQLiteOpenHelper的数据库操作类,提示重写onCreate和onUpgrade两个方法。
其中,onCreate方法只在第一次打开数据库时执行,在此可进行表结构创建的操作;
onUpgrade方法在数据库版本升高时执行,因此可以在onUpgrade函数内部根据新旧版本号进行表结构变更处理。
例如:
//数据库帮助器SQLiteOpenHelper public class MySqliteHelper extends SQLiteOpenHelper { public MySqliteHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); } public MySqliteHelper(Context context){ super(context,Constant.DATABASE_NAME,null,Constant.DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { // TODO 创建数据库后,对数据库的操作
// sql中Constant是用来存放一些关于数据库的常量的类
// 类型有:Integer、text文本、varchar(n)、real浮点型、blob二进制类型
String sql = "create table if not exists "+Constant.TABLE_NAME+"("+ Constant.ID+" Integer primary key ,"+ Constant.USER+" text,"+ Constant.DATE+" text,"+ Constant.TIME+" text,"; db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // TODO 更改数据库版本的操作,根据新旧版本号进行表结构变更处理,当打开数据库时传入版本号与当前不同会调用此方法
//在使用中只需要调用构造函数时把版本号参数version改大即可
db.execSQL("drop table if exists " + Constant.TABLE_NAME);
onCreate(db);
}
@Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db); // TODO 每次成功打开数据库后首先被执行
}
}
在这个类中,封装保证数据库安全的必要方法,包括获取单例对象、打开数据库连接、关闭数据库连接,并且封装对表记录进行增加、删除、修改、查询的操作方法。
获取单例对象:确保App运行时数据库只被打开一次,避免重复打开引起错误。
打开数据库连接:SQLite有锁机制,即读锁和写锁的处理;故而数据库连接也分两种,读连接可调用SQLiteOpenHelper的getReadableDatabase方法获得,写连接可调用getWritableDatabase获得。
关闭数据库连接:数据库操作完毕后,应当调用SQLiteDatabase对象的close方法关闭连接。
例如:
/** * DbManger 操作我们数据库的工具类 我们一般写成单例模式 * 单例模式 : 在整个应用程序中 不管什么地方(类) 获得的都是同一个对象实例*/ public class DbManger { private static final String TAG = "DbManger"; private static MySqliteHelper helper; //建立一个数据库对象 //表名 private String table_name ="p_data";
/**单例模式:不能让每一个类都能new一个,那样就不是同一个对象了,所以首先构造函数要私有化,以上下文Context作为参数 * @param ctx 本类的上下文对象 * @return */ private DbManger(Context ctx){ //由于数据库只需要调用一次,所以在单例中建出来 helper= new MySqliteHelper(ctx); } //public static 为静态类型,要调用就要有一个静态的变量,为私有的 private static DbManger instance; //既然该类是私有的 那么别的类就不能够调用 那么就要提供一个public static(公共的 共享的)的方法 //方法名为getInstance 参数为上下文 返回值类型为这个类的实例 //要加上一个synchronized(同步的)如果同时有好多线程 同时去调用getInstance()方法 就可能会出现一些创建多个DBManger的现象 public static synchronized DbManger getInstance(Context ctx){ //如果为空 就创建一个, 如果不为空就还用原来的 这样整个应用程序中就只能获的一个实例 if(instance == null){ instance = new DbManger(ctx); } return instance; }//常用方法 增删改查 /** * 添加数据 至数据库 * @param USER 用户名 DATE 日期 TIME 时间 */ public void addData(String USER,String DATE,String TIME){ //获得一个可写的数据库的一个引用 SQLiteDatabase db = helper.getWritableDatabase(); ContentValues values= new ContentValues(); values.put(Constant.USER, USER); values.put(Constant.DATE, DATE); values.put(Constant.TIME, TIME);// 参数一:表名,参数三,是插入的内容 // 参数二:只要能保存 values中是有内容的,第二个参数可以忽略 db.insert(table_name, null, values); Log.d(TAG, "addData: 数据保存成功:"+USER+""+DATE+""+TIME); } /** * 删除用户 * @param user */ public void deletebyuser(String user){ SQLiteDatabase db = helper.getWritableDatabase(); //表名 删除的条件 db.delete(table_name, "user = ?", new String[] {user}); } /** * 删除某条记录 * @param id */ public void deletebyid(int id){ SQLiteDatabase db = helper.getWritableDatabase(); //表名 删除的条件 db.delete(table_name, "id = ?", new String[] {Integer.valueOf(id).toString()}); } /** * //查找 每一个黑名单都有 号码和模式 先把号码和模式封装一个bean * 获得所有的黑名单 * @param user 用户名 * @param pageIndex 页数 * @param pageSize 每页显示的行数 * @return */ //分页查询 修改 p_data是一个新定义的,用来存放一系列数据的类 public List<p_data> getAllData(String user,int pageIndex, int pageSize){//创建集合对象 List<p_data> data = new ArrayList<p_data>(); SQLiteDatabase db = helper.getReadableDatabase();
//Cursor cursor = db.query(p_data, null, null, null, null, null, null);//查询全部数据
//order by _id desc 根据_id倒叙排列 使新添加的数据在查询时显示上面。根据用户名查询
//分页查询:pageSize每页显示的数目,pageIndex页数 Cursor cursor = db.rawQuery("select * from p_data where user = ? order by id desc limit "+pageSize +" offset "+((pageIndex-1)*pageSize)+";", new String[]{user});
//返回的 cursor 默认是在第一行的上一行 //遍历 while(cursor.moveToNext()){// cursor.moveToNext() 向下移动一行,如果有内容,返回true String TIME = cursor.getString(cursor.getColumnIndex("time")); // 获得time 这列的值 String DATE = cursor.getString(cursor.getColumnIndex("date")); // 获得date 这列的值//将查找到的数据封装到bean中 p_data bean = new p_data(user,DATE,TIME); //封装的对象添加到集合中 data.add(bean); } //关闭cursor cursor.close(); //SystemClock.sleep(1000);// 休眠2秒,查找出的数据比较多、比较耗时的情况下使用 Log.d(TAG, "getAllData: 查询数据库数据"+data ); return data; } /** * 获得数据的数量 */ public int getNumCount(String user){ SQLiteDatabase db = helper.getReadableDatabase(); Cursor cursor = db.query(table_name, new String[] {"count(*)"}, "user = ?",new String[] {user}, null, null, null, null); cursor.moveToNext(); int count = cursor.getInt(0);// 仅查了一列,count(*) 这一刻列 cursor.close(); return count; } }
可被SQLite直接使用的数据结构是ContentValues类,类似于映射Map,提供put和get方法用来存取键值对。区别之处在于ContentValues的键只能是字符串”。ContentValues主要用于记录增加和更新操作,即SQLiteDatabase的insert和update方法。
对于查询操作来说,使用的是另一个游标类Cursor。调用SQLiteDatabase的query和rawQuery方法时,返回的都是Cursor对象,因此获取查询结果要根据游标的指示一条一条遍历结果集合,Cursor的常用方法:
1. 游标控制类方法,用于指定游标的状态。
2. 游标移动类方法,把游标移动到指定位置。
3. 获取记录类方法,可获取记录的数量、类型以及取值。
创建数据库(onCreateView或onCreate中):
private DbManger dbManger;
dbManger = DbManger.getInstance(view.getContext());//fragment dbManger = DbManger.getInstance(this);//activity
然后通过dbManger调用所需的操作函数即可。
public class p_data { private String USER; private String DATE; private String TIME; public Nbp_data( String USER, String DATE, String TIME) { this.USER = USER; this.DATE = DATE; this.TIME = TIME; } public void setDATE(String DATE) { this.DATE = DATE; } public void setUSER(String USER) { this.USER = USER; } public String getUSER() { return USER; } public String getDATE() { return DATE; } public String getTIME() { return TIME; } }
public class Constant { public static final String DATABASE_NAME = "info.db"; // 数据库名称 public static final int DATABASE_VERSION = 1; //数据库版本 public static final String TABLE_NAME = "p_data"; //数据库表名 /** * id、user、date以下是数据库表中的字段 */ public static final String ID = "id"; //id主键 public static final String USER = "user"; //用户 public static final String DATE = "date"; //日期 public static final String TIME = "time"; //时间 }
参考:
Android Studio开发实战:从零基础到App上线 欧阳燊著 清华大学出版社
CSDN博主:「快乐的金豆」 Android 数据储存的方式之本地数据库储存 https://blog.csdn.net/lijinweii/java/article/details/73930260
联系客服