导语:本文是我在看《Android 第一行代码》的时候的记录,觉得比较有用,也特别重要,其中最后的LitePal操作数据库特别的重要。
一、文件存储
1. 存储函数(openFileOutput)
这里先通过openFileOutPut()
方法能够得到一个FileOutputStream
对象,然后借助它构建一个OutputStreamWriter
对象,接着再使用OutputStreamWriter
构建出一个BufferedWriter
对象,这样就通过BufferedWriter
将文本内容写入到文件中。
public void save(String inputText){
FileOutputStream out = null;
BufferedWriter writer = null;
try{
out = openFileOutput("data", Context.MODE_PRIVATE);
writer = new BufferedWriter(new OutputStreamWriter(out));
writer.write(inputText);
}catch (IOException e){
e.printStackTrace();
}finally {
try{
if(writer != null){
writer.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
2. 读取函数(openFileInput)
public String load(){
FileInputStream in = null;
BufferedReader reader = null;
StringBuilder content = new StringBuilder();
try{
in = openFileInput("data");
reader = new BufferedReader(new InputStreamReader(in));
String line = "";
while ((line = reader.readLine()) != null){
content.append(line);
}
}catch (IOException e){
e.printStackTrace();
}finally {
if (reader != null){
try{
reader.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
return content.toString();
}
项目文件地址:https://github.com/imlhb/StudyAndroid/tree/master/FilePersistenceTest
二、SharedPreferences储存
1.存入数据
SharedPreferences.Editor editor = getSharedPreferences("data",MODE_PRIVATE).edit();
editor.putString("name","Tom");
editor.putInt("age",28);
editor.putBoolean("married",false);
editor.apply();
2.获取数据
SharedPreferences pref = getSharedPreferences("data",MODE_PRIVATE);
String name = pref.getString("name","");
int age = pref.getInt("age",0);
boolean married = pref.getBoolean("married",false);
Log.d(TAG, "onClick: name is " + name);
Log.d(TAG, "onClick: age is " + age);
Log.d(TAG, "onClick: married is " + married);
项目文件地址:https://github.com/imlhb/StudyAndroid/tree/master/SharedPreferencesTest
三、SQLite数据库储存
Android系统内置了SQLite
数据库。
首先需要创建一个类去继承SQLiteOpenHelper
类,SQLiteOpenHelper
中有两个方法,分别是onCreate()
和onUpgrade()
,我们必须重写这两个方法,然后分别在这两个方法中实现创建,升级数据库的逻辑。
1. 创建数据库
public class MyDatabaseHelper extends SQLiteOpenHelper {
//编写Sql语句,创建Book表
public static final String CREATE_BOOK = "create table Book ("
+"id integer primary key autoincrement,"
+"author text,"
+"price real,"
+"pages integer,"
+"name text)";
private Context mContext;
public MyDatabaseHelper(Context context , String name, SQLiteDatabase.CursorFactory factory , int version){
super(context ,name ,factory ,version);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
//创建数据表
db.execSQL(CREATE_BOOK);
Toast.makeText(mContext,"创建数据库成功",Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
2. 升级数据库
这里新增加drop table if exists
,如果发现数据库中已经存在Book表
或Category表
,就先删除表,再调用onCreate()
方法重新创建
public class MyDatabaseHelper extends SQLiteOpenHelper {
public static final String CREATE_BOOK = "create table Book ("
+"id integer primary key autoincrement,"
+"author text,"
+"price real,"
+"pages integer,"
+"name text)";
//新增加Category表
public static final String CREATE_CATEGORY = "create table Category("
+"id integer primary key autoincrement,"
+"category_name text,"
+"category_code integer)";
private Context mContext;
public MyDatabaseHelper(Context context , String name, SQLiteDatabase.CursorFactory factory , int version){
super(context ,name ,factory ,version);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK);
//创建Category表
db.execSQL(CREATE_CATEGORY);
Toast.makeText(mContext,"创建数据库成功",Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//新增加
db.execSQL("drop table if exists Book");
db.execSQL("drop table if exists Category");
onCreate(db);
}
}
3. 添加数据
这边书中是使用了按钮,按下后创建。
首先需要private MyDatabaseHelper dbHelper;
然后new一个MyDatabaseHelper给dbHelper ,像这样:
dbHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
将它实例化后,然后再使用SQLiteDatabase db = dbHelper.getWritableDatabase();
方法会返回一个SQLiteDatabase
对象,这个对象可以对数据进行CRUD
操作。
这边我们先使用insert()
方法,这个方法需要3个参数:
insert(表名,Null,ContentValues对象);
剩下的就put
数据即可values.put("字段名","数据")
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
//开始组装第一条数据
values.put("name","The Da Vinci Code");
values.put("author","Dan Brown");
values.put("pages",454);
values.put("price",16.96);
db.insert("Book",null,values);
values.clear();
//开始组装第二条数据
values.put("name","The Lost Symbol");
values.put("author","Dan Brown");
values.put("pages",510);
values.put("price",19.95);
db.insert("Book",null,values);
这里解释一下CRUD
操作:create
添加数据read
读取数据 update
修改数据delete
删除数据
4. 更新数据
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("price",10.99);
db.update("Book",values,"name = ?",new String[]{"The Da Vinci Code"});
这里update()
方法的第一个参数为表名称,第二个为实例化的ContentValues
,第三个参数对应sql语句中的where
。?是一个占位符,它等于第四个参数的值。
5. 删除数据
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
db.delete("Book","pages > ?",new String[]{"500"} );
删除pages大于500的数据。
6. 查询数据库
这里先调出moveToFirst()
方法将数据指针移动到第一位,然后使用do...while
来循环导出数据,最后使用close()
方法关闭cursor
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor cursor = db.query("Book",null,null,null,null,null,null);
if (cursor.moveToFirst()){
do{
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
double price = cursor.getDouble(cursor.getColumnIndex("price"));
Log.d(TAG, "书的名字为" + name);
Log.d(TAG, "书的作者为" + author);
Log.d(TAG, "书的页数为" + pages);
Log.d(TAG, "书的价格为" + price);
}while (cursor.moveToNext());
}
cursor.close();
7. 使用SQL操作数据库
a. 添加数据
db.execSQL("insert into Book (name,author,pages,price) values (?,?,?,?)",new String[]{"name","author","123","123"});
b. 更新数据
db.execSQL("update Book set price = ? where name = ?", new String[]{"10.99","The Da Vinci Code"});
c. 删除数据
db.execSQL("delete from Book where pages > ?" ,new String[]{"500"});
d. 查询数据
db.rawQuery("select * from Book",null);
项目地址:https://github.com/imlhb/StudyAndroid/tree/master/DatabaseTest
四、使用LitePal操作数据
传统的建表方式就像上面那样复杂,并且再升级数据库的情况下,会先把之前的表drop掉,然后再重新创建。这是特别严重的,导致数据丢失,每升级一次数据库就会清空之前的数据。
然而LitePal就不会。
1. 配置LitePal
第一步
打开app/build.gradle
文件,在dependencies闭包中添加:implementation 'org.litepal.android:core:1.4.1'
,目前最新版本是2.0,我们参考《Android 第一行代码》第二版进行编写。
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0-alpha3'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'org.litepal.android:core:1.4.1'
}
第二步
然后在app/src/main目录下新建个assets目录,并新建个文件litepal.xml,编辑该文件:
<?xml version="1.0" encoding="utf-8" ?>
<litepal>
<dbname value="BookStore"></dbname>
<version value="1"></version>
<list>
</list>
</litepal>
<dbname>标签:数据库名
<version>标签:数据库版本号
<list>标签:指定所有映射模型
第三步
最后配置LitePalApplication
,修改AndroidManifest.xml
中代码,增加android:name="org.litepal.LitePalApplication"
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.litepaltest">
<application
//增加
android:name="org.litepal.LitePalApplication"
//增加
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
这里我们将项目的application
配置为org.litepal.LitePalApplication
,这样才能让LitePal
所有的功能正常使用。
2. 创建和升级数据库
a.创建数据库
先定义一个book类
package com.example.litepaltest;
import org.litepal.crud.DataSupport;
public class Book extends DataSupport{
private int id;
private String author;
private double price;
private int pages;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getPages() {
return pages;
}
public void setPages(int pages) {
this.pages = pages;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
然后修改litepal.xml中<list>里面的代码
<list>
<mapping class="com.example.litepaltest.Book"></mapping>
</list>
这里使用<mapping>标签来申明我们要配置的映射模型类。
最后,在MainActivity中增加代码LitePal.getDatabase();
,这里同样是通过点击生成。
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
LitePal.getDatabase();
}
});
使用sqlite3查看
b.升级数据库
这里升级数据库我们尝试先给Book表新增加一个字段,press,只需要添加:
private String press;
public String getPress() {
return press;
}
public void setPress(String press) {
this.press = press;
}
然后我们和之前一样,创建一个Category类:
package com.example.litepaltest;
public class Category {
private int id;
private String categoryName;
private int categoryCode;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public int getCategoryCode() {
return categoryCode;
}
public void setCategoryCode(int categoryCode) {
this.categoryCode = categoryCode;
}
}
添加category到映射模型中:
<?xml version="1.0" encoding="utf-8" ?>
<litepal>
<dbname value="BookStore"></dbname>
//修改版本号
<version value="2"></version>
<list>
<mapping class="com.example.litepaltest.Book"></mapping>
//新增
<mapping class="com.example.litepaltest.Category"></mapping>
</list>
</litepal>
运行,点击查看。
3. 添加数据
这边第一步先需要Book类继承DataSupport类
public class Book extends DataSupport{...}
然后修改MainActivity中代码
Button addData = (Button) findViewById(R.id.add_data);
addData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Book book = new Book();
book.setName("第一行代码");
book.setAuthor("郭霖");
book.setPages(570);
book.setPrice(79);
book.setPress("人民邮电出版社");
book.save();
}
});
代码比较简单我就不多解释了。
4.更新数据
Button updateData = (Button) findViewById(R.id.update_data);
updateData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Book book = new Book();
book.setPrice(14.95);
book.setPress("Anchor");
book.updateAll("name = ? and author = ?","第一行代码","郭霖");
}
});
5. 删除数据
Button deleteButton = (Button) findViewById(R.id.delete_data);
deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
DataSupport.deleteAll(Book.class,"price<?","15");
}
});
6. 查询数据
Button queryButton = (Button) findViewById(R.id.query_data);
queryButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
List<Book> books = DataSupport.findAll(Book.class);
for (Book book:books){
Log.d(TAG, "onClick: name is " + book.getName());
Log.d(TAG, "onClick: author is " + book.getAuthor());
Log.d(TAG, "onClick: pages is " + book.getPages());
Log.d(TAG, "onClick: price is " + book.getPrice());
Log.d(TAG, "onClick: press is " + book.getPress());
}
}
});
7.查询的其他用法
查询第一条数据
Book firstBook = DataSupport.findFirst(Book.class);
查询最后一条数据
Book firstBook = DataSupport.findLast(Book.class);
查询哪几列的数据
List<Book> books = DataSupport.select("name","author").find(Book.class);
where()约束条件
List<Book> books = DataSupport.where("pages > ?","400").find(Book.class);
order()用法
List<Book> books = DataSupport.order("price desc").find(Book.class);
limit()用法
指定结果数量,比如结果的前3个。
List<Book> books = DataSupport.limit(3).find(Book.class);
offset()用法
查询结果偏移量,比如第2条,第3条。
List<Book> books = DataSupport.limit(3).offset(1).find(Book.class);
对5个方法组合
代表Book表中,第11~20条满足页数大于400的这个条件的name,author,pages这三个列的数据。
List<Book> books = DataSupport.select("name","author").where("pages > ?","400").order("price desc").limit(10).offset(10).find(Book.class);
文章很好值得一看
谢谢!