文件存储
将数据存储到文件中
Context
类中提供了一个openFileOutput()
方法,可以用于将数据存储到指定的文件中。
这个方法接收两个参数,第一个参数是文件名,在文件创建的时候使用的就是这个名称,注意这里指定的文件名不可以包含路径,因为所有的文件都是默认存储到/data/data//files/目录下的。第二个参数是文件的操作模式,主要有两种模式可选,MODE_PRIVATE和MODE_APPEND。其中MODE_PRIVATE是默认的操作模式,表示当指定同样文件名的时候,所写入的内容将会覆盖原文件中的内容,而MODE_APPEND则表示如果该文件已存在,就往文件里面追加内容,不存在就创建新文件。
openFileOutput ()
方法返回的是一个 FileOutputStream对象,得到了这个对象之后就可以使用Java流的方式将数据写入到文件中了。
MainActiity.java
package com.example.filepersistencetest;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.os.Bundle;
import android.widget.EditText;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class MainActivity extends AppCompatActivity {
private EditText edit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edit = findViewById(R.id.edit);
}
@Override
protected void onDestroy() {
super.onDestroy();
String inputText = edit.getText().toString();
save(inputText);
}
private 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 {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Type Something here"
/>
</LinearLayout>
从文件中读取信息
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edit = findViewById(R.id.edit);
String inputText = load();
//一次性进行两种空值的判断
if(!TextUtils.isEmpty(inputText)){
edit.setText(inputText);
//将光标移动到文本的末尾以便于继续输入
edit.setSelection(inputText.length());
Toast.makeText(this,"Restoring succeeded",Toast.LENGTH_SHORT).show();
}
}
private 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();
}
SharedPreferences存储
存储数据
- 获取SharedPreferences对象:
-
Context类
中的getSharedPreferences()
方法
此方法接收两个参数,第一个参数用于指定SharedPreferences
文件的名称,如果指定的文件不存在则会创建一个,SharedPreferences文件都是存放在/data/data//shared_prefsl目录下的。第二个参数用于指定操作模式,目前只有MODE_PRIVATE这一种模式可选,它是默认的操作模式,和直接传入0效果是相同的,表示只有当前的应用程序才可以对这个SharedPreferences文件进行读写. -
Activity类
中的getPreferences()
方法
这个方法和Context中的getSharedPreferences()方法很相似,不过它只接收一个操作模式参数,因为使用这个方法时会自动将当前活动的类名作为SharedPreferences的文件名。 -
PreferenceManager类
中的getDefaultSharedPreferences()
方法
这是一个静态方法,它接收一个Context参数,并自动使用当前应用程序的包名作为前缀来命名SharedPreferences文件。
- 向Shared-Preferences文件中存储数据:
- 调用SharedPreferences对象的
edit()
方法来获取一个SharedPreferences.Editor对象。 - 向
SharedPreferences.Editor
对象中添加数据,比如添加一个布尔型数据就使用putBoolean()
方法,添加一个字符串则使用putString()
方法,以此类推。 - 调用
apply()
方法将添加的数据提交,从而完成数据存储操作。
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button saveData = (Button)findViewById(R.id.saveData);
saveData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Content里的方法
SharedPreferences.Editor editor = getSharedPreferences("data",MODE_PRIVATE).edit();
editor.putString("name","金逸飞");
editor.putInt("age",18);
editor.putBoolean("inLove",true);
editor.apply();
}
});
}
}
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/saveData"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Save data" />
</LinearLayout>
读出数据
MainActivity.java
Button restoreData = (Button) findViewById(R.id.restore_data);
restoreData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
SharedPreferences pref = getSharedPreferences("data",MODE_PRIVATE);
String name = pref.getString("name","");//赋初始化值
int age = pref.getInt("age",0);
boolean inLove = pref.getBoolean("inLove",false);
Log.d("MainActivity","name is "+name);
Log.d("MainActivity","age is "+age);
Log.d("MainActivity","IsInLove is "+inLove);
}
});
activity_main.xml
<Button
android:id="@+id/restore_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Restore data"/>
实现记住密码功能
- CheckBox:复选框控件
MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
accountEdit = (EditText) findViewById(R.id.account);
passwordEdit = (EditText) findViewById(R.id.password);
login = (Button) findViewById(R.id.login);
rememberPass = (CheckBox) findViewById(R.id.remembew_password);
pref = PreferenceManager.getDefaultSharedPreferences(this);
boolean isRemember = pref.getBoolean("remember_password",false);
if(isRemember){
//将账号和密码都设置到文本框中
String account = pref.getString("account","");
String password = pref.getString("password","");
accountEdit.setText(account);
passwordEdit.setText(password);
rememberPass.setChecked(true);
}
login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String account = accountEdit.getText().toString(); //获取编辑框的文字
String password = passwordEdit.getText().toString();
if(account.equals("sakura") && password.equals("123456")){
editor = pref.edit();
if(rememberPass.isChecked()){ //检查复选框是否被选中
editor.putBoolean("remember_password",true);
editor.putString("account",account);
editor.putString("password",password);
}else{
editor.clear();
}
editor.apply();
Intent intent = new Intent(LoginActivity.this,MainActivity.class);
startActivity(intent);
finish();
}else{
Toast.makeText(LoginActivity.this,"账号或密码错误",Toast.LENGTH_SHORT).show();
}
}
});
}
activity_main.xml
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<CheckBox
android:id="@+id/remembew_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:text="Recember password"/>
</LinearLayout>
SQLite数据库存储
创建+升级数据库
Book建表语句:
create table Book (
// integer 表示整型,primary key 将id 列设为主键,autoincrement 关键字表示id 列是自增长的
id integer primary key autoincrement,
// text表示文本类型
author text,
// real表示浮点型
price real,
pages integer,
name text)
MyDatabase Helper.java
MyDatabaseHelper
中的onUpgrade()
方法是用于对数据库进行升级的,它在整个数据库的管理工作当中起着非常重要的作用.在onUpgrade()方法中执行了两条DROP语句,如果发现数据库中已经存在Book表或Category表了,就将这两张表删除掉,然后再调用oncreate()方法重新创建。
package com.example.databasetest;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast;
import androidx.annotation.Nullable;
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) ";
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(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL(CREATE_BOOK);
sqLiteDatabase.execSQL(CREATE_CATEGORY);
Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
sqLiteDatabase.execSQL("drop table if exists Book");
sqLiteDatabase.execSQL("drop table if exists Category");
onCreate(sqLiteDatabase);
}
}
MainActivity.java
MyDatabaseHelper
第四个参数: 它表示当前数据库的版本号,之前我们传入的是1,现在只要传入一个比1大的数,就可以让 onUpgrade()方法得到执行了。
package com.example.databasetest;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper databaseHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
databaseHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
Button button = (Button) findViewById(R.id.create_database);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
databaseHelper.getWritableDatabase();
}
});
}
}
添加数据
-
对数据进行的操作有4种,即 CRUD。其中C代表添加
(Create )
,R代表查询(Retrieve )
,U代表更新(Update )
,D代表删除(Delete )
。 -
调用
SQLiteOpenHelpe
r的getReadableDatabase()
或getwritable-Database()
方法是可以用于创建和升级数据库的,不仅如此,这两个方法还都会返回一个sQLiteDatabase对象,借助这个对象就可以对数据进行CRUD操作了。 -
SQLiteDatabase的
insert()
:用于添加数据,接收三个参数:- 第一个参数是表名,我们希望向哪张表里添加数据,这里就传入该表的名字。
- 第二个参数用于在未指定添加数据的情况下给某些可为空的列自动赋值NULL,一般我们用不到这个功能,直接传入null即可。
- 第三个参数是一个ContentValues对象,它提供了一系列的
put()
方法重载,用于向ContentValues中添加数据,只需要将表中的每个列名以及相应的待添加数据传入即可。
activity_main.xml
<Button
android:id="@+id/add_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add data"/>
MainActivity.java
Button addData = (Button) findViewById(R.id.add_data);
addData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
ContentValues values = new ContentValues();
//开始组装第一条数据
values.put("name","The Da Vinci Code");
values.put("author","jinyifei");
values.put("pages",454);
values.put("price",16);
db.insert("Book",null,values);
values.clear();
//开始组装第二条数据
values.put("name","The Lost Symbol");
values.put("author","yinyijing");
values.put("pages",455);
values.put("price",20);
db.insert("Book",null,values);
}
});
删除数据
activity_main.xml
<Button
android:id="@+id/delete_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Delete data"/>
MainActivity.java
Button deleteData = (Button)findViewById(R.id.delete_data);
deleteData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
db.delete("Book","pages > ?",new String[] {"500"});
}
});
查询数据
query()
七个参数:- 第一个参数是表名,表示我们希望从哪张表中查询数据。
- 第二个参数用于指定去查询哪几列,如果不指定则默认查询所有列。
- 第三、第四个参数用于约束查询某一行或某几行的数据,不指定则默认查询所有行的数据。
- 第五个参数用于指定需要去group by的列,不指定则表示不对查询结果进行group by操作。
- 第六个参数用于对group by之后的数据进行进一步的过滤,不指定则表示不进行过滤。
- 第七个参数用于指定查询结果的排序方式,不指定则表示使用默认的排序方式。
MainActivity.java
Button queryButton = (Button) findViewById(R.id.query_data);
queryButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
//查询Book表中所有的数据
Cursor cursor = db.query("Book",null,null,null,null,null,null);
if(cursor.moveToFirst()){
do{
@SuppressLint("Range") String name = cursor.getString(cursor.getColumnIndex("name"));
@SuppressLint("Range") String author = cursor.getString(cursor.getColumnIndex("author"));
@SuppressLint("Range") int pages = cursor.getInt(cursor.getColumnIndex("pages"));
@SuppressLint("Range") double price = cursor.getDouble(cursor.getColumnIndex("price"));
Log.d("MainActivity","book name is "+ name);
Log.d("MainActivity","book author is "+ author);
Log.d("MainActivity","book pages is "+ pages);
Log.d("MainActivity","book price is "+ price);
}while(cursor.moveToNext());
}
cursor.close();
}
});
activity_main.xml
<Button
android:id="@+id/query_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="查询数据"/>
使用SOL操作数据库
- 添加数据的方法如下:
db.execSQL ("insert into Book (name,author,pages,price) values(?,?,?,?)", new String[] { "The Da vinci Code""Dan Brown","454","16.96"});
db.execSQL("insert into Book (name,author,pages,price) values(?,?,?,?)", new String[] { "The Lost Symbol",“Dan Brown","510","19.95” });
- 更新数据的方法如下:
db.execSQL ( "update Book set price = ? where name = ?" ,new String[] { "10.99","The Da Vinci Code"});
- 删除数据的方法如下:
db.execSQL( "delete from Book where pages > ?",new String[] { "500”});
- 查询数据的方法如下:
db.rawQuery ( "select * from Book", null);
使用Lite操作数据库
LitePal简介
LitePal是一款开源的Android数据库框架,它采用了对象关系映射( ORM )的模式,并将我们平时开发最常用到的一些数据库功能进行了封装,使得不用编写一行SQL语句就可以完成各种建表和增删改查的操作。
LitePal的项目主页地址
配置LitePal
将权限加入app/build.gradle中,这里获取最新版本
dependencies {
implementation 'org.litepal.guolindev:core:3.2.3'
}
配置litepal.xml文件,在app/src/main/目录下 new ->Directory,创建一个assets目录,再在assets目录先新建litepal.xml文件,内容如下
<litepal>
/*
dbname指定数据库名 list用于指定所有的映射模型 version用于指定数据库版本号
*/
<dbname value="BookStore" ></dbname>
<version value="1"></version>
<list></list>
</litepal>
修改AndroidManifest.xml
<application
android:name="org.litepal.LitePalApplication"
创建和升级数据库
litepal.xml
这里使用<mapping>
标签来声明我们要配置的映射模型类,注意一定要使用完整的类名。不管有多少模型类需要映射,都使用同样的方式配置在标签下即可。
<list>
<mapping class="com.example.litepaltest.Book"></mapping>
</list>
Book.java
package com.example.listpaltest;
public class Book {
private int id;
private String author;
private double price;
private int pages;
private String name;
private void setId(int id){
this.id = id;
}
public int getId(){
return id;
}
private void setAuthor(String author){
this.author = author;
}
public String getAuthor(){
return author;
}
private void setPrice(double price){
this.price = price;
}
public double getPrice(){
return price;
}
private void setPages(int pages){
this.pages = pages;
}
public int getPages(){
return id;
}
private void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button createDatabase = (Button) findViewById(R.id.create_data);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Connector.getDatabase();
}
});
}
}
Book.java
使用LitePal来升级数据库非常非常简单,你完全不用思考任何的逻辑,只需要改你想改的任何内容,然后将版本号加1就行了。
在Book表中添加一个press(出版社)列:
private String press;
private void setPress(String press){
this.press = press;
}
public String getPress(){
return press;
}
Category.java
想再添加一张Category表,就新建一个Category类就行
package com.example.listpaltest;
public class Category {
private int id;
private String categoryName;
private int categoryCode;
public void setId(int id){
this.id = id;
}
public int getId(){
return id;
}
public void setCategoryName(String categoryName){
this.categoryName = categoryName;
}
public String getCategoryName(){
return categoryName;
}
public void setCategoryCode(int categoryCode){
this.categoryCode = categoryCode;
}
public int getCategoryCode(){
return categoryCode;
}
}
litepal.xml
<mapping class="com.example.litepaltest.Category"></mapping>
</list>
添加数据
public class Book extends LitePalSupport {
MainActivity.java
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("The Da Vinci Code");
book.setAuthor("jinyifei");
book.setPages(454);
book.setPress("MYMYMY");
book.save();
}
});
更新数据
第一种:
Button updateData = (Button) findViewById(R.id.update_data);
updateData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Book book = new Book();
book.setName("The Lost Symbol");
book.setAuthor("yinyijing");
book.setPages(510);
book.setPress("OhNo");
book.setPrice(15.9);
book.save();
book.setPrice(10.9); //直接更新当前数据
book.save();
}
});
第二种:更灵巧
public void onClick(View view) {
Book book = new Book();
book.setPrice(14.95);
book.setPress("Anchor");
book.updateAll("name = ? and author = ?","The Lost Symbol","Dan Brown");
}
把数据都更新为默认值:
Book book = new Book();
//将页数更新为初始化值
book.setToDefault("pages") ;
book.updateAll();
删除数据
Button deleteButton = (Button) findViewById(R.id.delete_data);
deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
LitePal.deleteAll(Book.class,"price < ?","15");
}
});
查询数据
Button queryButton = (Button)findViewById(R.id.query_data);
queryButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
List<Book> books = LitePal.findAll(Book.class);
for(Book book : books){
Log.d("MainActivity","book name is "+book.getName());
Log.d("MainActivity","book Author is "+book.getAuthor());
Log.d("MainActivity","book Pages is "+book.getPages());
Log.d("MainActivity","book price is "+book.getPrice());
Log.d("MainActivity","book press is "+book.getPress());
}
}
});
-
除了
findAll()
方法之外,LitePal还提供了很多其他非常有用的查询API。比如我们想要查询Book表中的第一条数据就可以这样写:
Book firstBook = DataSupport.findFirst(Book.class);
查询Book表中的最后一条数据就可以这样写:
Book lastBook = DataSupport.findLast(Book.class);
-
select()方法用于指定查询哪几列的数据,对应了SQL当中的select关键字。比如只查name和 author这两列的数据,就可以这样写:
List<Book> books = DataSupport.select ( "name","author" ).find(Book.class);
where()方法用于指定查询的约束条件,对应了SQL当中的where关键字。比如只查页数大于400的数据,就可以这样写:
List<Book> books = DataSupport.where( " pages > ?",“400").find(Book.class);
-
order()方法用于指定结果的排序方式,对应了SQL当中的 order by 关键字。比如将查询结果按照书价从高到低排序,就可以这样写:
List<Book> books = DataSupport.order("price desc" ).find(Book.class);
其中desc表示降序排列,asc或者不写表示升序排列。 -
limit()方法用于指定查询结果的数量,比如只查表中的前3条数据,就可以这样写:
List<Book> books = DataSupport.limit (3).find( Book.class) ;
-
offset()方法用于指定查询结果的偏移量,比如查询表中的第2条、第3条、第4条数据,就可以这样写:
List<Book> books = DataSupport.limit(3).offset(1 ).find(Book.class);