文章目录
数据存储
1.文件存储
适用于存储简单的文本数据或者二进制数据,若想存复杂的文本数据需自行定义格式规范以便要用到数据时可将数据从文件中重新解析出来。
举例(与书中有所不同但大同小异):
①编写界面
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".FirstActivity">
<Button
android:id="@+id/read_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="60dp"
android:layout_marginBottom="56dp"
android:text="读取"
app:layout_constraintBottom_toTopOf="@+id/read"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.95" />
<TextView
android:id="@+id/read"
android:layout_width="180dp"
android:layout_height="221dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="188dp"
android:hint="读点啥"
android:textSize="50sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.578"
app:layout_constraintStart_toEndOf="@+id/write" />
<EditText
android:id="@+id/write"
android:layout_width="180dp"
android:layout_height="221dp"
android:layout_marginStart="16dp"
android:layout_marginBottom="188dp"
android:hint="写点啥"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/write_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="60dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="60dp"
android:text="写入"
app:layout_constraintBottom_toTopOf="@+id/write"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0" />
</android.support.constraint.ConstraintLayout>
②编写读写文件逻辑:
public class FirstActivity extends AppCompatActivity {
private String write_data;
private String read_data;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
final Button Write_button = (Button) findViewById(R.id.write_button);
Button Read_button = (Button) findViewById(R.id.read_button);
final EditText Write_text = (EditText) findViewById(R.id.write);
final TextView Read_text = (TextView) findViewById(R.id.read);
Write_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(!Write_text.getText().toString().equals("")){
FileOutputStream out = null;
BufferedWriter writer = null;
try{
write_data = Write_text.getText().toString();
/*
* "data"是保存的文件名,后面是模式
* MODE_PRIVATE(默认)--写入同名文件会覆盖原有数据
* MODE_APPEND--有文件则在末尾加数据,没有则创建文件再加数据
*/
out = openFileOutput("data", Context.MODE_PRIVATE);
writer = new BufferedWriter(new OutputStreamWriter(out));
writer.write(write_data);
Toast.makeText(FirstActivity.this,"写入成功",Toast.LENGTH_SHORT).show();
}
catch (IOException e){
e.printStackTrace();
}
finally {
try{
if (writer != null) {
writer.close();
}
}
catch (IOException ex){
ex.printStackTrace();
}
}
}
else {
AlertDialog.Builder builder = new AlertDialog.Builder(FirstActivity.this);
builder.setTitle("警告");
builder.setMessage("写入数据为空");
builder.setCancelable(true);
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
builder.show();
}
}
});
Read_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FileInputStream in = null;
BufferedReader reader = null;
StringBuilder content = new StringBuilder();
try {
//读取文件名为"data"中的内容
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 ex){
ex.printStackTrace();
}
}
}
read_data = content.toString();
Read_text.setText(read_data);
Toast.makeText(FirstActivity.this,"读取成功",Toast.LENGTH_SHORT).show();
}
});
}
}
③效果:
为证明确实写入了虚拟机内存,我查看了虚拟机的内容(书中的查看方法在AS3.0+已经不行了)
(一)
View–>Tool Windows–>Device File Explorer
(二)
找到data文件夹,保存到电脑中
(三)
查看
2.SharedPreference存储
使用键值对的方式来存储数据。
有三种方法:
类名 | 方法名 | 参数 | 备注 |
---|---|---|---|
Context | .getSharedPreferences (String name,int mode) | 指定文件名,指定操作模式(只有MODE_PRIVATE,与直接传入0效果相同) | 背后是用xml文件存放数据,文件存放在/data/data//shared_prefs目录下 |
Activity | .getPreferences(int mode) | 指定操作模式 | 文件名默认使用当前活动的类名,模式默认为0或MODE_PRIVATE,还可以使用MODE_APPEND、MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE |
PreferenceManager | .getDefaultSharedPreferences (Context) | 自动使用当前应用程序的包名作为前缀来命名SharedPreference文件 |
使用步骤:
①获得SharedPreferences对象
②获得SharedPreferences.Editor对象。
③通过SharedPreferences.Editor接口的putXxx()方法存放键-值对(其中Xxx表示不同的数据类型。如:字符串类型的value需要用putString()方法)。
④通过SharedPreferences.Editor接口的commit()方法保存键-值对(commit方法相当于数据库事务中的提交(commit)操作)。
举例(getSharedPreference()):
①编写按钮响应事件
Write_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
write_data = Write_text.getText().toString();
SharedPreferences.Editor editor = getSharedPreferences
("data",MODE_PRIVATE).edit();
editor.putString("input",write_data);
editor.apply();
Toast.makeText(FirstActivity.this,"写入成功",Toast.LENGTH_SHORT).show();
}
});
Read_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences pref = getSharedPreferences("data",MODE_PRIVATE);
read_data = pref.getString("input","");
Read_text.setText(read_data);
Toast.makeText(FirstActivity.this,"读取成功",Toast.LENGTH_SHORT).show();
}
});
效果:
举例(getDefaultSharedPreferences()):
尝试编写简单的记住用户和记住密码功能
①添加两个CheckBox
<CheckBox
android:id="@+id/rmUser"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_marginStart="72dp"
android:layout_marginTop="8dp"
android:text="记住用户"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/Sign_in" />
<CheckBox
android:id="@+id/rmPass"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_marginStart="44dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:text="记住密码"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.309"
app:layout_constraintStart_toEndOf="@+id/rmUser"
app:layout_constraintTop_toBottomOf="@+id/Sign_in" />
②编写逻辑
要记住了用户才可以记住密码:
public class LoginActivity extends BaseActivity {
private SharedPreferences pref;
private SharedPreferences.Editor editor;
private CheckBox rmUser;
private CheckBox rmPass;
private EditText User;
private EditText Password;
private Button Sign_in;
@Override
protected void onCreate(Bundle saveInstanceState){
super.onCreate(saveInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_login);
pref = PreferenceManager.getDefaultSharedPreferences(this);
rmUser = (CheckBox) findViewById(R.id.rmUser);
rmPass = (CheckBox) findViewById(R.id.rmPass);
User = (EditText) findViewById(R.id.User);
Password = (EditText) findViewById(R.id.Password);
boolean isRmUser = pref.getBoolean("remember_user",false);
boolean isRmPass = pref.getBoolean("remember_password",false);
rmUser.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (rmUser.isChecked()){
rmPass.setClickable(true);
rmPass.setChecked(false);
}
else {
rmPass.setClickable(false);
rmPass.setChecked(false);
}
}
});
if(isRmUser){
String Users = pref.getString("User","");
User.setText(Users);
rmUser.setChecked(true);
if (isRmPass){
String Passwords = pref.getString("Password","");
Password.setText(Passwords);
rmPass.setChecked(true);
}
}
Sign_in = (Button) findViewById(R.id.Sign_in);
Sign_in.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String account = User.getText().toString();
String password = Password.getText().toString();
if(account.equals("test")&&password.equals("12345678")){
editor = pref.edit();
if (rmUser.isChecked()){
editor.putBoolean("remember_user",true);
editor.putString("User",account);
if (rmPass.isChecked()){
editor.putBoolean("remember_password",true);
editor.putString("Password",password);
}
else{
editor.putBoolean("remember_password",false);
editor.remove("Password");
}
}
else {
editor.clear();
editor.putBoolean("remember_user",false);
editor.remove("User");
}
editor.apply();
editor.clear();
Intent intent = new Intent(LoginActivity.this,MainActivity.class);
intent.putExtra("data",account);
startActivity(intent);
User.setText("");
Password.setText("");
finish();
}
else {
Toast.makeText(LoginActivity.this,"用户名密码有误",
Toast.LENGTH_SHORT).show();
}
}
});
}
}
我是修改了书中例子,可能有些地方逻辑会不顺畅甚至是冗余了请见谅
③效果:
保存的数据(完全没加密):
3.数据库存储
SQLite数据库存储
(1)创建数据库
主要是借助SQLiteOpenHelper这个帮助类
①编写MyDatabaseHelper.java
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast;
public class MyDatebaseHelper extends SQLiteOpenHelper {
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 MyDatebaseHelper(Context context, String name,
SQLiteDatabase.CursorFactory factory, int verson){
super(context,name,factory,verson);
mContext = context;
}
@Override
//创建
public void onCreate(SQLiteDatabase db){
db.execSQL(CREATE_BOOK);
Toast.makeText(mContext,"生成数据库成功",Toast.LENGTH_SHORT).show();
}
@Override
//更新
public void onUpgrade(SQLiteDatabase database, int oldverson,int newverson){
database.execSQL("drop table if exists Book");
onCreate(database);
}
}
②添加一个按钮用于测试创建数据库
<Button
android:id="@+id/create_DB"
android:layout_width="match_parent"
android:layout_height="81dp"
android:layout_alignBottom="@+id/textView"
android:layout_marginBottom="-364dp"
android:text="创建数据库"
/>
③编写按钮响应事件
public class MainActivity extends BaseActivity {
private MyDatebaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
......
dbHelper = new MyDatebaseHelper(MainActivity.this,"BookStore.db",null,1);
Button create_DB = (Button) findViewById(R.id.create_DB);
create_DB.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dbHelper.getWritableDatabase();
Toast.makeText(MainActivity.this,dbHelper.getDatabaseName(),
Toast.LENGTH_SHORT).show();
}
});
......
}
④效果(查看创建的数据库):
书上的方法感觉比较麻烦,搜索了一下发现Android Studio本身就有查看数据库的插件,下载
(在File --> Settings --> Plugins --> 搜索Database Navigator下载)即可
- 1.先把数据库导出(通过Device File Explorer)
- 2.点击打开下载好的Database Navigator(在左侧有DB Browser)
- 3.把导出的数据库添加到Database Navigator中
(其中android_metadata是每个数据库都有的,Book是刚刚通过代码创建的)
(2)升级数据库
①修改MyDatabaseHelper
public class MyDatebaseHelper extends SQLiteOpenHelper {
......
public static final String CREATE_CATEGORY = "create table Category ("
+ "id integer primary key autoincrement,"
+ "category_name text,"
+ "category_code integer)";
private Context mContext;
......
@Override
public void onCreate(SQLiteDatabase db){
db.execSQL(CREATE_BOOK);
db.execSQL(CREATE_CATEGORY);
Toast.makeText(mContext,"生成数据库成功",Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase database, int oldverson,int newverson){
database.execSQL("drop table if exists Book");
database.execSQL("drop table if exists Category");
onCreate(database);
}
}
②在主活动中修改版本,升级
如果verson相同的话不会执行onUpgrade(),数据库已经存在的话也不会再次执行onCreate()
public class MainActivity extends BaseActivity {
private MyDatebaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
......
//这里的"2"即为版本号,比之前的版本号大即可,因为这里设置的时候是int,所以只能为整数
dbHelper = new MyDatebaseHelper(MainActivity.this,"BookStore.db",null,2);
......
}
③查看导出的数据库
(3)添加数据
对表中数据有四种操作——CRUD
操作 | 方法 | 参数 |
---|---|---|
Create(创建/添加) | .insert(String table, String nullColumnHack, ContentValues values) | ①表名 ②在未指定数据时自动赋值null ③要添加的值 |
Retrieve(查询) | query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) | ①表名 ②想要显示的字段 ③条件 ④selection的值 ⑤分组 ⑥分组条件 ⑦排序 ⑧分页 |
Update(更新) | .update(String table, ContentValues values, String whereClause, String[] whereArgs) | ①表名 ②ContentValues对象:该对象存储方式为Key-value,Key表示表中的字段名称,value表示该字段对应的值 ③查询条件,例如:_ID = ? ④第三个参数的值(用来替换的值) |
Delete(删除) | delete(String table, String whereClause, String[] whereArgs) | ①表名er ②删除条件例如:_ID = ? ③whereClause的值! |
做着做着发现如果用上面说的插件来查看数据库,那么每次操作都要导出一次数据库很麻烦,于是又找了另一种较为方便的查看方式
- 1.在app中的build.gradle中添加依赖
implementation 'com.facebook.stetho:stetho:1.5.0'
- 2.在活动启动后调用函数
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Stetho.initializeWithDefaults(this);
setContentView(R.layout.activity_second);
......
}
- 3.在浏览器地址栏中输入chrome://inspect/#devices(Chrome和猎豹浏览器都行)
- 4.找到数据库查看即可
点inspect
即能查看
举例:
①Create
逻辑:插入两本书的书名、页数、价格,id自动递增
Button Insert = (Button) findViewById(R.id.Insert);
Insert.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase database = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name","The Da Vinic Code");
values.put("author","Dan Brown");
values.put("pages",454);
values.put("price",16.96);
database.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);
database.insert("Book",null,values);
Toast.makeText(SecondActivity.this,"插入成功",Toast.LENGTH_SHORT).show();
}
});
效果(按两下插入):
②更新
逻辑:把书名为"The Da Vinic Code"的价格更新为11.88
Button Updata = (Button) findViewById(R.id.Update);
Updata.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase database = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("price",11.88);
database.update("Book",values,"name = ?",new String[]{"The Da Vinic Code"});
}
});
效果:
③删除
逻辑:删除页数pages超过500的书的信息
Button Delete = (Button) findViewById(R.id.Delete);
Delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase database = dbHelper.getWritableDatabase();
database.delete("Book","pages > ?", new String[]{"500"});
}
});
效果:
④查询
逻辑:查看Book库中的所有数据,在下面的TableLayout中显示
TableLayout:
<TableLayout
android:layout_width="395dp"
android:layout_height="253dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<TableRow
android:layout_weight="4"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/book_name"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="书名" />
<TextView
android:id="@+id/book_author"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="作者" />
<TextView
android:id="@+id/book_pages"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="页数" />
<TextView
android:id="@+id/book_price"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="价格" />
</TableRow>
</TableLayout>
活动:
public class SecondActivity extends AppCompatActivity {
private MyDatebaseHelper dbHelper;
String name = "书名";
String author = "作者";
String pages = "页数";
String price = "价格";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Stetho.initializeWithDefaults(this);
setContentView(R.layout.activity_second);
......
final TextView Bname = (TextView) findViewById(R.id.book_name);
final TextView Bauthor = (TextView) findViewById(R.id.book_author);
final TextView Bpages = (TextView) findViewById(R.id.book_pages);
final TextView Bprice = (TextView) findViewById(R.id.book_price);
Button Retrieve = (Button) findViewById(R.id.Retrieve);
Retrieve.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase database = dbHelper.getWritableDatabase();
Cursor cursor = database.query("Book",null,null,null,null,null,null);
for(cursor.moveToFirst();!cursor.isAfterLast();cursor.moveToNext()){
name = name + "\r\n" + cursor.getString(cursor.getColumnIndex("name"));
author = author + "\r\n" + cursor.getString(cursor.getColumnIndex("author"));
pages = pages + "\r\n" + cursor.getString(cursor.getColumnIndex("pages"));
price = price + "\r\n" + cursor.getString(cursor.getColumnIndex("price"));
}
Bname.setText(name);
name = "书名";
Bauthor.setText(author);
author = "作者";
Bpages.setText(pages);
pages = "页数";
Bprice.setText(price);
price = "价格";
cursor.close();
}
});
......
}
效果: