任务内容
通过文件操作和数据库操作进行数据读写。
1、完成安卓对文件的读写操作。分成读写不一致和一致两种情况。
2、完成安卓对SQLite数据库的操作。包括数据库建立、创建表格、插入数据、更新数据、删除数据以及查询数据。
附加题:对SQLite的所有操作都是根据用户的输入完成。
评分:完成1和2的功能起评分为80分,附加题15分。其他分数的增减根据报告给出。
概述:Android系统主要提供3种方式实现数据持久化功能:文件存储、SharedPreference存储、数据库存储。
文件存储
文件存储是Android最基本的数据存储方式,不对存储的内容进行任何格式化处理。
context类提供FileOutputStream openFileOutput(filename, mode)方法,将数据存储到指定的文件中。该方法返回文件输出流对象,通过该对象就能用Java流将数据写入文件。
指定的文件名不能包含路径,默认存储到/data/data/<packagename>/files/目录下。
操作模式主要有两种,默认模式mode_private会重写文件,mode_append用于追加文件内容。
写入文件的执行过程:
openFileOutput(filename, mode) ,返回文件输出流对象FileOutputStream -->输出流写入对象OutputStreamWriter() --> 缓冲区写入对象BufferedWriter(),关闭缓冲区写入对象.close()
读取文件的执行过程:
openFileInput(filename) ,返回文件输入流对象FileOutputStream --> 输入流写入对象InputStreamReader() --> 缓冲区读取对象BufferedReader() --> 把数据存放到StringBuilder对象,关闭缓冲区读取对象。
将数据写入文件的自定义方法:
public void save() {
String data = "saved data";
FileOutputStream out = null;
BufferedWriter writer = null;
try{
out = openFileOutput("datafile",MODE_PRIVATE); // 文件输出流
writer = new BufferedWriter(new OutputStreamWriter(out)); // 输出流写入。缓冲区写入。
writer.write(data);
} catch(IOException e){ // 捕获异常
e.printStackTrace();
} finally {
try{ // 关闭文件
if(writer != null){
writer.close();
}
} catch(IOException e){ // 捕获异常
e.printStackTrace();
}
}
}
从文件中读取数据的自定义方法:
public String load() {
FileInputStream in = null;
BufferedReader reader = null;
StringBuilder content = new StringBuilder();
try {
in = openFileInput("datafile");
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();
}
接下来运行一个简单实现读写功能的安卓程序:
在EditText输入数据,将数据保存到文件,退出程序;
重新打开程序,读取文件中的数据,打印到EditText框内。
仓库文件添加布局和EditText输入框:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<EditText
android:id="@+id/edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
android:hint="input your data" />
</LinearLayout>
MainActivity.java文件完整的包和代码:
package com.example.fifth_writeread;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.widget.EditText;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
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 = (EditText) 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();
}
}
protected void onDestroy() {
super.onDestroy();
String inputText = edit.getText().toString(); // 获取EditText的输入数据
save(inputText); // 调用函数保存数据到文件
}
public void save(String inputText) {
FileOutputStream out = null;
BufferedWriter writer = null;
try{
out = openFileOutput("datafile",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();
}
}
}
public String load() {
FileInputStream in = null;
BufferedReader reader = null;
StringBuilder content = new StringBuilder();
try {
in = openFileInput("datafile");
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();
}
}
执行效果:打开程序输入数据。
执行效果:重新打开程序,成功打印刚才输入的临时数据:
SQLite数据库存储
概述
Android系统内置了数据库!SQLite是轻量级的关系型数据库,通常只需要几百KB的内存,因此特别适合在移动设备上使用。
Android专门提供SQLiteOpenHelper帮助类,可以简单地实现数据库的创建和升级。
SQLiteOpenHelper是一个抽象类,使用前提是创建自己的帮助类去继承他。
函数方法 | 说明 |
---|---|
抽象方法onCreate() | 必须在自定义帮助类里重写这两个方法, |
抽象方法onUpgrade() | 然后分别在两个方法中实现创建、升级数据库的逻辑 |
getReadableDatabase() | 这两个方法都可以创建/打开数据库,返回可对数据库进行读写操作的对象 |
getWritableDatabase() | 区别在于,当数据库不可写入(比如磁盘已满),getReadableDatabase()返回的对象会以只读方式打开数据库,而getWritableDatabase()方法会出现异常。 |
建立数据库和表
创建数据库BookStore.db,新建一张Book表,表中有id(主键)、作者、书名等列:
1.建表关键代码:(合并1和2的代码,在布局中添加id为create的按钮,即为运行代码)
public class MyDatabaseHelper extends SQLiteOpenHelper {
public static final String CREATE_BOOK = "create table Book ( "
+"id integer primary key autoincrement," // 自增长autoincrement
+"author text,"
+"name text)" ;
// 静态变量-建表语句
private Context MyContext ; // 私有类Context实例
// 类的构造方法
public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version) ;
MyContext = context ; // 传入Context实例
}
@Override
public void onCreate( SQLiteDatabase db) {
db.execSQL(CREATE_BOOK) ; // 建立数据库、建表,执行之后打印提示
Toast.makeText( MyContext , "Create succeeded", Toast.LENGTH_SHORT).show(); // 建表提示信息
}
@Override
public void onUpgrade( SQLiteDatabase db, int oldVersion , int newVersion) {
}
}
}
2.MainActivity.java文件的其他代码:
package com.example.fifth_sqlite;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper; // 自定义数据库的实例
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 自定义数据库实例:传入四个参数,第二个是数据库名,第四个是版本号。
// 此时会进行建库建表操作
dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);
Button createDatabase = (Button) findViewById(R.id.create);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dbHelper.getWritableDatabase(); // 点击按钮,调用数据库实例的写入函数,创建数据库
}
});
}
执行效果:
升级数据
2.新建第二个表users
在自定义数据库类中添加建表语句,定义为私有静态变量
public static final String CREATE_USERS = "create table users( "
+ "id integer primary key autoincrement,"
+ "username text, "
+ "password text)";
在onUpgrade()中添加
@Override
public void onUpgrade( SQLiteDatabase db, int oldVersion , int newVersion) {
db.execSQL("drop table if exist Book");
db.execSQL("drop table if exist Category");
onCreate(db); // 表存在就删除,避免报错。调用创建函数,新建两张表。
}
创建自定义数据库实例时,需要传入更大的版本号来更新数据库,注意是整数类型
dbHelper = new MyDatabaseHelper(this, "BookStore.db" , null , 2)
添加数据-增删改查CRUD
1.添加数据:创建添加数据的按钮,监听点击操作
public void onClick( View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
// 组装第一条数据
values.put("id" , 0) ;
values.put("author", "dashi");
values.put("name", "how to be a dashi");
db.insert("Book", null, values); // 插入第一条数据
}
2.更新数据:创建更新数据的按钮,监听点击操作
public void onClick( View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name", "how to be a dashi 2");
db.update("Book", values, "name= ?" , new String[] { "how to be a dashi" } );
}
3.删除数据:创建删除数据的按钮,监听点击操作
public void onClick( View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete("Book", "id = ?", new String[] { "0" } );
}
4.查询数据:创建查询数据的按钮,监听点击操作
public void onClick( View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
// 查询Book表中所有的数据
Cursor cursor = db.query("Book", null, null, null, null, null, null);
if( cursor.moveToFirst()) {
do {
// 遍历Cursor对象,取出数据并打印
int id = cursor.getInt(cursor.getColumnIndex("id"));
String author = cursor.getString(cursor.getColumnIndex("author"));
String name = cursor.getString(cursor.getColumnIndex("name"));
Log.d("MainActivity", "book id is " + id);
Log.d("MainActivity", "book author is " + author);
Log.d("MainActivity", "book name is " + name);
} while( cursor.moveToNext());
}
}
全部代码
完整的代码:
1. MainActivity.main代码
package com.example.fifth_sqlite;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);
Button createDatabase = (Button) findViewById(R.id.create);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dbHelper.getWritableDatabase();
}
});
Button add = (Button) findViewById(R.id.add);
add.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
// 组装第一条数据
values.put("id" , 0) ;
values.put("author", "dashi");
values.put("name", "how to be a dashi");
db.insert("Book", null, values); // 插入第一条数据
}
});
Button delete = (Button) findViewById(R.id.delete);
delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete("Book", "id = ?", new String[] { "0" } );
}
});
// 由于更新数据,需要传入更大的数据库版本号,需要设置dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1+n);
// 如果不传入更大的版本号,更新就会产生错误,所以此处不执行代码
Button update = (Button) findViewById(R.id.update);
update.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// SQLiteDatabase db = dbHelper.getWritableDatabase();
// ContentValues values = new ContentValues();
// values.put("name", "how to be a dashi 2");
// db.update("Book", values, "name= ?" , new String[] { "how to be a dashi" } );
}
});
Button retrieve = (Button) findViewById(R.id.retrieve);
retrieve.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
// 查询Book表中所有的数据
Cursor cursor = db.query("Book", null, null, null, null, null, null);
if(cursor.moveToFirst()) {
do {
// 遍历Cursor对象,取出数据并打印
int id = cursor.getInt(cursor.getColumnIndex("id"));
String author = cursor.getString(cursor.getColumnIndex("author"));
String name = cursor.getString(cursor.getColumnIndex("name"));
Log.d("MainActivity", "book id is " + id);
Log.d("MainActivity", "book author is " + author);
Log.d("MainActivity", "book name is " + name);
} while( cursor.moveToNext());
}
}
});
}
public class MyDatabaseHelper extends SQLiteOpenHelper {
public static final String CREATE_BOOK = "create table Book ( "
+"id integer primary key autoincrement," // 自增长autoincrement
+"author text,"
+"name text)" ;
// 静态变量-建表语句
private Context MyContext ; // 私有类Context实例
// 类的构造方法
public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version) ;
MyContext = context ; // 传入Context实例
}
@Override
public void onCreate( SQLiteDatabase db) {
db.execSQL(CREATE_BOOK) ; // 建表
Toast.makeText( MyContext , "Create succeeded", Toast.LENGTH_SHORT).show(); // 建表提示信息
}
@Override
public void onUpgrade( SQLiteDatabase db, int oldVersion , int newVersion) {
}
}
}
2. activity_main.xml的按钮代码:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/create"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="创建数据库" />
<Button
android:id="@+id/add"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="添加数据" />
<Button
android:id="@+id/delete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="删除数据" />
<Button
android:id="@+id/update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="更新数据" />
<Button
android:id="@+id/retrieve"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="查询数据" />
</LinearLayout>
执行效果
主页面:
1.添加数据:点击添加数据按钮,然后点击查询数据按钮。
2.删除数据:点击删除数据按钮,然后点击查询数据按钮,返回数据为空。
3.更新数据:修改自定义数据库实例的版本号为2,重新打开安卓程序。点击更新数据按钮,然后点击查询数据按钮,成功把书名“how to be a dashi”修改为“how to be a dashi 2”
参考
《第一行代码 Android 第2版》——郭霖著