1. Android SQLite的基本使用
1.1. SQLiteOpenHelper
Android 底层已经通过一个SQLiteOpenHelper的抽象类将数据库的创建,以及修改,更新等都放在了里面。
要使用它必须实现它的OnCreate(SQLiteDatabase db),onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 方法。
onCreate:当数据库第一次被建立的时候被执行,例如创建表,初始化数据等。
onUpgrade:当数据库需要被更新的时候执行,例如删除久表,创建新表。
1.2. 自定义辅助类
我们要在Android中使用SQLite,自然要一个数据库辅助类来创建或打开数据库,这个辅助类继承自SQLiteOpenHelper类。除了必须重写SQLiteOpenHelper的两个抽象方法外,我们还要创建辅助类的构造方法。
/*
* SqliteOpenHelper
* 1.提供了onCreate(), onUpGrade()等创建数据库更新数据库的函数
* 2.提供了获取数据库对象的函数
*/
public class MySqliteHelper extends SQLiteOpenHelper {
/**
* 构造函数
* @param context 上下文对象
* @param name 表示创建数据库的名称
* @param factory 游标工厂
* @param version 表示创建数据库的版本
*/
public MySqliteHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
/**
* 当数据库创建时回调的函数
* @param db 数据库对象
*/
@Override
public void onCreate(SQLiteDatabase db) {
Log.i("TAG", "-------onCreate--------");
}
/**
* 当数据库版本更新时回调的函数
* @param db 数据库对象
* @param oldVersion 数据库旧版本
* @param newVersion 数据库新版本
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i("TAG", "-------onUpGrade-------");
}
/**
* 当数据库打开时回调的函数
* @param db 数据库对象
*/
@Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
Log.i("TAG", "-------onOpen-------");
}
}
onOpen 方法并不是必须重写的方法,是打开数据库会回调的函数,我们用 log 日志来监控数据库的状况。
看到MySqliteHelper类的构造方法可以知道,我们要传入这几个参数比较麻烦,如果每次实例化都需要传入,不利于修改阅读,所以我们通常会创建一个常量类来保存数据库名,版本号这些常量。像如果以后版本号更新了,我们可以很简单的修改。
1.3. 常量类
在这里我们先创建这几个常量。
public class Constant {
public static final String DATABASE_NAME = "info.db"; //数据库名称
public static final int DATABASE_VERSION = 1; //数据库版本
public static final String TABLE_NAME = "person"; //表名
}
既然这几个参数我们都已经确定好了,那就可以修改我们的构造函数啦。
public MySqliteHelper(Context context) {
super(context, Constant.DATABASE_NAME, null, Constant.DATABASE_VERSION);
}
现在只需要传入上下文即可,CursorFactory 为 null,数据库名称和版本号引用常量就可以啦。
1.4. 业务逻辑处理类
我们的 MySqliteHelper 实现了数据库的建立和打开,相当于是一个持久化数据的存储,而 MainActivity 是整个页面数据的展示,我们为了降低耦合度(两者之间的密切关系程度,也可以理解为互相依赖的程度),通常建立一个 DbManager 类,来实现数据库的逻辑处理。
/**
* 主要是对数据库操作的工具类
*/
public class DbManager {
public enum Something {
INSTANCE;
private MySqliteHelper helper;
public MySqliteHelper getInstance(Context context) {
if (helper == null) {
helper = new MySqliteHelper(context);
}
return helper;
}
}
}
因为是对数据库的操作,所以我们这里用单例模式,这里我用了枚举的方法。对单例模式不了解的朋友,可以看看我的另一篇博客Java–单例模式。
1.5. 布局文件
现在我们已经初步搭建好了数据库,可以测试数据库是否可以被创建。这里我是用 Button 的点击事件来操作,下面就是 xml 文件,只是很简单的布局,也是这个博客对数据库操作的主要内容。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="创建数据库"
android:onClick="createDb"
android:background="#ff3" />
<Button
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:id="@+id/btn_insert"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="插入数据"
android:onClick="click"
android:background="#ff3"
android:layout_weight="1" />
<Button
android:layout_weight="1"
android:id="@+id/btn_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="删除数据"
android:onClick="click"
android:background="#ff3" />
</LinearLayout>
<LinearLayout
android:layout_marginTop="60dp"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:layout_weight="1"
android:id="@+id/btn_update"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="修改数据"
android:onClick="click"
android:background="#ff3" />
<Button
android:layout_weight="1"
android:id="@+id/btn_deleteApi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="删除数据api"
android:onClick="onClick"
android:background="#ff3"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"/>
<Button
android:layout_weight="1"
android:id="@+id/btn_query"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="sql语句查询"
android:onClick="click"
android:background="#ff3" />
</LinearLayout>
<LinearLayout
android:layout_marginTop="120dp"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:layout_weight="1"
android:id="@+id/btn_insertApi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="插入数据api"
android:onClick="onClick"
android:background="#ff3" />
<Button
android:layout_weight="1"
android:id="@+id/btn_queryApi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="API查询"
android:onClick="onClick"
android:background="#ff3"
android:layout_marginRight="10dp"
android:layout_marginLeft="10dp"/>
<Button
android:layout_weight="1"
android:id="@+id/btn_updateApi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="修改数据api"
android:onClick="onClick"
android:background="#ff3" />
</LinearLayout>
</RelativeLayout>
1.5. 数据库表
在我们的 SQLite 数据库中,数据的存储是以表的形式,所以在创建数据库的时候我们也应该创建一张数据表,学习过 SQL 语句的都知道要创建一张完整的数据表,需要表名和列名,而这些事我们有可能要去修改的,所以为了效率,我们应该把这些设置为常量去使用,前面我们建立了一个 Constant 类,让我们添加些数据进去:
public class Constant {
public static final String DATABASE_NAME = "info.db"; //数据库名称
public static final int DATABASE_VERSION = 1; //数据库版本
public static final String TABLE_NAME = "person"; //表名
public static final String _ID = "_id";
public static final String NAME = "name";
public static final String AGE = "age";
}
可以看到,我们又添加了表名和三个字段,这样就方便我们日后修改。
让我们回到 MySQLiteHelper 类:
public void onCreate(SQLiteDatabase db) {
Log.i("TAG", "-------onCreate--------");
String sql = "create table " + Constant.TABLE_NAME + " (" +
Constant._ID + " Integer primary key, " +
Constant.NAME + " varchar(10)," +
Constant.AGE + " Integer)";
db.execSQL(sql);
}
execSQL(String sql) 是 SQLiteDatabase 类的执行 SQL 语句的方法,大家将刚才生成的 info.db 删除,再次运行,这样就能在创建数据库文件的时候创建一张 PERSON 的表啦。
我们把生成的 info.db 导出到桌面或者你自己的某个硬盘目录下,用可视化数据库工具打开,你就可以看到数据库的信息,自然也能看到我们新创建的那张表。
1.6. SQL语句增删改查
在 Android 中我们可以自己写 sql 语句去执行,但如果觉得写 sql 语句容易出错,也可以调用 api 中的方法。在 SQLite 中,查询操作是特别的,insert,update,delete都对数据做了修改,但 select 只返回结果,所以我们需要能接收这个结果,这样就不能使用 execSQL 方法啦。
我们还有两个方法可以执行查询,分别是 rawQuery 和 query,query() 是 api 拼接 sql 语句,我们暂且不提。
rawQuery(String sql, String[] selectionArgs),sql 就是执行的 select 语句,selectionArgs 是查询条件的占位符,如果没有占位符,就传入null即可,最后会返回一个 Cursor 对象,帮我们确定数据的位置。
DBManager 类是我们用来管理数据库的工具类,execSQL() 是我们必须用到的方法,为了防止出错,我们应 该在 DBManager 类中写个方法来判断,同样 rawQuery() 也应该判断。
public static void execSQL(SQLiteDatabase db, String sql) {
if (db != null) {
if (sql != null && !"".equals(sql)) {
db.execSQL(sql);
}
}
}
public static Cursor selectDataBySql(SQLiteDatabase db, String sql, String[] selectionArgs) {
Cursor cursor = null;
if (db != null) {
cursor = db.rawQuery(sql, selectionArgs);
}
return cursor;
}
相信大家都能够看懂,这里就不讲啦。
rawQuery 是返回一个 Cursor 游标,那么我们自然需要把它转换为熟悉的 list 集合,首先我们要有存储数据的实体类,这就是 Java Bean 思想。
public class Person {
private int _id;
private String name;
private int age;
public Person(int _id, String name, int age) {
this._id = _id;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"_id=" + _id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
public int get_id() {
return _id;
}
public void set_id(int _id) {
this._id = _id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
有了这个 Person 类,我们就可以在 DBManager 中写从 Cursor 中读数据的方法啦。
public static List<Person> cursorTolist(Cursor cursor) {
List<Person> list = new ArrayList<Person>();
while (cursor.moveToNext()) {
//getColumnIndex(String columnName) 根据参数中指定的字段名称获取字段下标
int columnIndex = cursor.getColumnIndex(Constant._ID);
//getInt(int columnIndex)根据参数中指定的字段下标 获取对应int类型的value
int _id = cursor.getInt(columnIndex);
String name = cursor.getString(cursor.getColumnIndex(Constant.NAME));
int age = cursor.getInt(cursor.getColumnIndex(Constant.AGE));
Person person = new Person(_id, name, age);
list.add(person);
}
return list;
}
根据字段名获取字段下标,再得到字段的 value,懂得一点 Cursor 知识的朋友应该都能明白。
public void click(View view) {
switch (view.getId()) {
case R.id.btn_insert :
SQLiteDatabase db = helper.getWritableDatabase();
for (int i = 1; i <= 30; i++) {
String sql1 = " insert into " + Constant.TABLE_NAME + " values(" + i + ",'张三" + i + "'," + i + ") ";
DbManager.execSQL(db, sql1);
}
db.close();
break;
case R.id.btn_update :
db = helper.getWritableDatabase();
String updatesql=" update "+ Constant.TABLE_NAME + " set " + Constant.NAME +
"='xiao' where " + Constant._ID + "=1";
DbManager.execSQL(db,updatesql);
db.close();
break;
case R.id.btn_delete :
db = helper.getWritableDatabase();
String deletesql = " delete from " + Constant.TABLE_NAME + " where " + Constant._ID + "=2";
DbManager.execSQL(db,deletesql);
db.close();
break;
case R.id.btn_query :
db = helper.getWritableDatabase();
String sql = "select * from " + Constant.TABLE_NAME;
Cursor cursor = DbManager.selectDataBySql(db, sql, null);
List<Person> list = DbManager.cursorTolist(cursor);
for (Person p: list) {
Log.i("TAG", p.toString());
}
db.close();
break;
}
}
因为这个代码只是测试数据,所以就随便添加,只要实现功能即可。
这些代码是很容易理解的,现在打开模拟器点击按钮来看看。
我们可以看到表中已经有了30条数据,并且 id = 2的数据已经被删除了,id = 1的数据名字也已经别改成了 xiao,这说明我们的功能已经实现了。这里要注意的是,如果你按了几次 insert,会报错,因为 id 重复了,这并没什么。
因为我们执行的 select 是查询全部信息,所以查询结果也显然成功啦。
1.7. API 操作
数据库的增删改查需要正确的 SQL 语句,如果对 SQL 语句不熟练的用提供的 api 也是一样的。
1.7.1. insert
insert(String table, String nullColumnHack, ContentValues values);
table:相信大家都能理解是数据表名。
nullColumnStack:因为在 SQLite 中可以允许列中有 NULL,但不能整列都是NULL,这个值代表强行插入null值的数据列的列名,我们都是给 null 就可以了。
values:代表一行记录的数据。insert 方法插入的一行记录使用ContentValues存放,我们看看它的说明。
private HashMap<String, Object> mValues;
可以知道 ContentValues 是一个键为 String 的 HashMap集合,它提供了多种 put(String key, XXX value) (其中key为数据列的列名)方法用于存入数据,多种 getAsXxx(String key) 方法用于取出数据。
insert 方法返回 long,代表新添记录的行号,该行号是一个内部直,与主键id无关,发生错误返回-1。
1.7.2. update
update(String table, ContentValues values, String whereClause, String[] whereArgs)
table 与 values 和 insert 方法是一样的。
whereClause:表示修改条件,满足该whereClause子句的记录将会被更新。
whereArgs:表示修改条件的占位符,用于为whereArgs子句传递参数。
update 方法返回一个 int,表示修改的数据条数。
1.7.3. delete
delete(String table, String whereClause, String[] whereArgs)
table:代表想删除数据的表名。
whereClause:满足该whereClause子句的记录将会被删除。
whereArgs:用于为whereArgs子句传入参数。
与 update 方法中的格式是一样的。
1.7.4. query
query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)
distinct:指定是否去除重复记录。
table:执行查询数据的表名。
columns:要查询出来的列名。
selection:查询条件子句。
selectionArgs:用于为selection子句中占位符传入参数值,值在数组中的位置与占位符在语句中的位置必须一致,否则就会有异常。
groupBy:用于控制分组。
having:用于对分组进行过滤。
orderBy:用于对记录进行排序。
limit:用于进行分页。
最后返回 Cursor 游标。
public void onClick(View view) {
switch(view.getId()) {
case R.id.btn_insertApi :
SQLiteDatabase db = helper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(Constant._ID, 2); //put(表示插入数据库的字段名称,表示插入该字段的具体值)
values.put(Constant.NAME, "Lily");
values.put(Constant.AGE, 15);
long result = db.insert(Constant.TABLE_NAME, null, values);
if (result > 0) {
Toast.makeText(this, "插入数据成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "插入数据失败", Toast.LENGTH_SHORT).show();
}
db.close();
break;
case R.id.btn_updateApi :
db = helper.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put(Constant.NAME, "cc");//put(表示需要修改的字段名称, 修改后的字段值)
// int count = db.update(Constant.TABLE_NAME, cv, Constant._ID + "=3", null);
int count = db.update(Constant.TABLE_NAME, cv, Constant._ID + "=?", new String[]{"3"});
if (count > 0) {
Toast.makeText(this, "修改数据成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "修改数据失败", Toast.LENGTH_SHORT).show();
}
db.close();
break;
case R.id.btn_deleteApi :
db = helper.getWritableDatabase();
int count2 = db.delete(Constant.TABLE_NAME, Constant._ID + "=?", new String[]{"1"});
if (count2 > 0) {
Toast.makeText(this, "删除数据成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "删除数据失败", Toast.LENGTH_SHORT).show();
}
db.close();
break;
case R.id.btn_queryApi :
db = helper.getWritableDatabase();
Cursor cursor = db.query(Constant.TABLE_NAME, null, Constant._ID + ">?",
new String[]{"10"}, null, null, Constant._ID + " asc");
List<Person> list = DbManager.cursorTolist(cursor);
for (Person p : list) {
Log.i("TAG", p.toString());
}
db.close();
break;
}
}
这可以看到,在写查询条件的时候有两种写法:
db.update(Constant.TABLE_NAME, cv, Constant._ID + "=3", null);
db.update(Constant.TABLE_NAME, cv, Constant._ID + "=?", new String[]{"3"});
这两种是完全一样的。
并没有出现强退,我们看看数据表的变化。
可以看到我们已经删除了 id = 1 的数据,并且以前 id = 2 被删除的数据也插入了新的,id = 3 的数据也被修改了,再看看查询。
id > 10 的数据都被输出了,说明我们 api 的功能也都实现啦。
2. Android 生成Excel文件保存到本地
可以下载下来修改直接用,该项目主要是依赖一个叫jxl.jar的包,导到项目中libs文件下加即可。
下载地址:https://download.csdn.net/download/qq_36158551/89808728?spm=1001.2014.3001.5503
逻辑代码
public class ExcelUtil {
//内存地址
public static String root = Environment.getExternalStorageDirectory()
.getPath();
public static void writeExcel(Context context, List<Order> exportOrder,
String fileName) throws Exception {
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)&&getAvailableStorage()>1000000) {
Toast.makeText(context, "SD卡不可用", Toast.LENGTH_LONG).show();
return;
}
String[] title = { "订单", "店名", "电话", "地址" };
File file;
// File dir = new File(context.getExternalFilesDir(null).getPath());
File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath());
file = new File(dir, fileName + ".xls");
if (!dir.exists()) {
dir.mkdirs();
}
// 创建Excel工作表
WritableWorkbook wwb;
OutputStream os = new FileOutputStream(file);
wwb = Workbook.createWorkbook(os);
// 添加第一个工作表并设置第一个Sheet的名字
WritableSheet sheet = wwb.createSheet("订单", 0);
Label label;
for (int i = 0; i < title.length; i++) {
// Label(x,y,z) 代表单元格的第x+1列,第y+1行, 内容z
// 在Label对象的子对象中指明单元格的位置和内容
label = new Label(i, 0, title[i], getHeader());
// 将定义好的单元格添加到工作表中
sheet.addCell(label);
}
for (int i = 0; i < exportOrder.size(); i++) {
Order order = exportOrder.get(i);
Label orderNum = new Label(0, i + 1, order.id);
Label restaurant = new Label(1, i + 1, order.restName);
Label nameLabel = new Label(2,i+1,order.restPhone);
Label address = new Label(3, i + 1, order.receiverAddr);
sheet.addCell(orderNum);
sheet.addCell(restaurant);
sheet.addCell(nameLabel);
sheet.addCell(address);
Toast.makeText(context, "写入成功", Toast.LENGTH_LONG).show();
}
// 写入数据
wwb.write();
// 关闭文件
wwb.close();
}
public static WritableCellFormat getHeader() {
WritableFont font = new WritableFont(WritableFont.TIMES, 10,
WritableFont.BOLD);// 定义字体
try {
font.setColour(Colour.BLUE);// 蓝色字体
} catch (WriteException e1) {
e1.printStackTrace();
}
WritableCellFormat format = new WritableCellFormat(font);
try {
format.setAlignment(jxl.format.Alignment.CENTRE);// 左右居中
format.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);// 上下居中
// format.setBorder(Border.ALL, BorderLineStyle.THIN,
// Colour.BLACK);// 黑色边框
// format.setBackground(Colour.YELLOW);// 黄色背景
} catch (WriteException e) {
e.printStackTrace();
}
return format;
}
/** 获取SD可用容量 */
private static long getAvailableStorage() {
StatFs statFs = new StatFs(root);
long blockSize = statFs.getBlockSize();
long availableBlocks = statFs.getAvailableBlocks();
long availableSize = blockSize * availableBlocks;
// Formatter.formatFileSize(context, availableSize);
return availableSize;
}
}
3. Android SQLite及生成Excel文件保存到本地完整代码
3.1. SqlActivity
package com.inspur.szyj.activity;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import androidx.appcompat.app.AppCompatActivity;
import com.inspur.szyj.R;
import com.inspur.szyj.adapter.SqlAdapter;
import com.inspur.szyj.bean.PersonBean;
import com.inspur.szyj.helper.DateHelper;
import com.inspur.szyj.helper.db.DbService;
import com.inspur.szyj.util.ExcelUtil;
import java.util.ArrayList;
import java.util.List;
public class SqlActivity extends AppCompatActivity
implements View.OnClickListener {
private ListView lv;//控件
private Cursor cursor;//数据源
//自定义的封装类
private DbService dbService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sql);
findViewById(R.id.create).setOnClickListener(this);
findViewById(R.id.update_db).setOnClickListener(this);
findViewById(R.id.insert).setOnClickListener(this);
findViewById(R.id.update).setOnClickListener(this);
findViewById(R.id.select).setOnClickListener(this);
findViewById(R.id.delete).setOnClickListener(this);
findViewById(R.id.delete_all).setOnClickListener(this);
findViewById(R.id.save_excel).setOnClickListener(this);
lv = findViewById(R.id.lv);
dbService = new DbService(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.create) {
dbService.createDB();
} else if (v.getId() == R.id.update_db) {
dbService.updateDatabase();
} else if (v.getId() == R.id.insert) {
PersonBean personBean = new PersonBean();
personBean.setName("张三");
personBean.setIdCard("372929199901010101");
personBean.setSignTime(DateHelper.getCurTime());
personBean.setSignDate(DateHelper.getCurDate());
dbService.insertDb(personBean);
} else if (v.getId() == R.id.update) {
dbService.updateDb();
} else if (v.getId() == R.id.select) {
List<PersonBean> personList = new ArrayList<>();
cursor = dbService.queryDb();
if (cursor != null) {
//1, 游标向下移动一条数据 2, 判断当前移动到的数据是否存在
while (cursor.moveToNext()) {
//获取指定的内容cursor.getString(列的编号, 编号是从0开始)
PersonBean personBean = new PersonBean();
//personBean.setName(cursor.getString(1));
int nameIndex = cursor.getColumnIndex(
"name");
personBean.setName(cursor.getString(nameIndex));
int idCardIndex = cursor.getColumnIndex(
"id_card");
personBean.setIdCard(cursor.getString(idCardIndex));
int signTimeIndex = cursor.getColumnIndex(
"sign_time");
personBean.setSignTime(cursor.getString(signTimeIndex));
int signDateIndex = cursor.getColumnIndex(
"sign_date");
personBean.setSignDate(cursor.getString(signDateIndex));
personList.add(personBean);
}
//关闭游标
cursor.close();
}
SqlAdapter adapter = new SqlAdapter(this, personList);
lv.setAdapter(adapter);
} else if (v.getId() == R.id.delete) {
dbService.deleteDb();
} else if (v.getId() == R.id.delete_all) {
dbService.deleteDbAll();
} else if (v.getId() == R.id.save_excel) {
try {
List<PersonBean> personList2 = new ArrayList<>();
cursor = dbService.queryDb();
if (cursor != null) {
//1, 游标向下移动一条数据 2, 判断当前移动到的数据是否存在
while (cursor.moveToNext()) {
//获取指定的内容cursor.getString(列的编号, 编号是从0开始)
PersonBean personBean = new PersonBean();
//personBean.setName(cursor.getString(1));
int nameIndex = cursor.getColumnIndex(
"name");
personBean.setName(cursor.getString(nameIndex));
int idCardIndex = cursor.getColumnIndex(
"id_card");
personBean.setIdCard(cursor.getString(idCardIndex));
int signTimeIndex = cursor.getColumnIndex(
"sign_time");
personBean.setSignTime(cursor.getString(signTimeIndex));
int signDateIndex = cursor.getColumnIndex(
"sign_date");
personBean.setSignDate(cursor.getString(signDateIndex));
personList2.add(personBean);
}
//关闭游标
cursor.close();
}
ExcelUtil.writeExcel(this, personList2, "excelFile");
} catch (Exception e) {
}
}
}
}
3.2. activity_sql.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activity.JsonActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<Button
android:id="@+id/create"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:padding="3dp"
android:text="创建数据库"
android:textSize="13sp" />
<Button
android:id="@+id/update_db"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:padding="3dp"
android:text="版本更新"
android:textSize="13sp" />
<Button
android:id="@+id/insert"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:padding="3dp"
android:text="插入数据"
android:textSize="13sp" />
<Button
android:id="@+id/update"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="3dp"
android:text="修改数据"
android:textSize="13sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<Button
android:id="@+id/select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="3dp"
android:text="查询数据"
android:textSize="13sp" />
<Button
android:id="@+id/delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="3dp"
android:text="删除数据"
android:textSize="13sp" />
<Button
android:id="@+id/delete_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="3dp"
android:text="删除所有数据"
android:textSize="13sp" />
<Button
android:id="@+id/save_excel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="3dp"
android:text="保存excel"
android:textSize="13sp" />
</LinearLayout>
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null" />
</LinearLayout>
3.3. DbService
package com.inspur.szyj.helper.db;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.inspur.szyj.bean.PersonBean;
/**
* 自定义的封装类
* 用来实现数据库的操作
* @author zzs
*/
public class DbService {
private Context context;
private DbOpenHelper dbOpenHelper;
public DbService(Context context) {
this.context = context;
dbOpenHelper = new DbOpenHelper(context);
}
//创建数据库
public void createDB() {
//打开数据库连接(数据库只有在执行次方法后, 数据库才会被创建)
//底层已经做了实现: 如果数据库不存在, 创建数据库并且打开连接;
// 如果数据库存在,直接打开数据库连接
dbOpenHelper.getWritableDatabase();
}
//数据库版本更新
public void updateDatabase() {
dbOpenHelper.getWritableDatabase();
}
//插入数据
public void insertDb(PersonBean personBean) {
//打开连接()
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
// //方式一
// db.execSQL("insert into person(name,id_card,sign_time,sign_date) values('张三','372929199901010101','2024-03-23 34:23:32','2024-03-23')");
// //方式二
// db.execSQL("insert into person(name,id_card,sign_time,sign_date) values (?,?,?,?)",
// new String[]{"李四", "372929199901010101",
// "2024-03-23 34:23:32", "2024-03-24"});
/*
* 方式三
* 封装好的方法
* table 表名
* nullColumnHack 可以为空
* 如果ContentValues为空: insert into person() values(null)
* values 值 ContentValues
*/
ContentValues values = new ContentValues();
//key:表中的字段 value:字段对应的内容
values.put("name", personBean.getName());
values.put("id_card", personBean.getIdCard());
values.put("sign_time", personBean.getSignTime());
values.put("sign_date", personBean.getSignDate());
db.insert("person", null, values);
}
//查询数据
public Cursor queryDb() {
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
//顺序
//sql = "select * from person order by _id asc";
//倒序
//sql = "select * from person order by _id desc";
//得到查询后的游标
//Cursor cursor=sqLiteDatabases.rawQuery(sql,null);
//Cursor cursor = db.rawQuery("select * from person ", null);
/**
* distinct 是否去除重复
* table 表名
* columns 查询的列名 new String[]{"_id","name","id_card","amount"}
* 可以为null, 代表查询所有数据
* selection where 后面的字句 _id = ?
* selectionArgs 占位符的值 new String[]{"1"}
* groupBy 分组
* having 放置在where 后再次筛选
* orderBy 排序
* limit 区间(分页加载数据)
*/
//Cursor cursor = db.query("person", null, null, null, null, null, null);
// Cursor cursor = db.query("person",
// null, "name = ?", new String[]{"张三"},
// null, null, "name desc");
Cursor cursor = db.query("person",
null, null,null,
null, null, "name asc");
return cursor;
}
//修改数据
public void updateDb() {
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
//方式一
//db.execSQL("update person set amount = ? where _id=?",
// new String[]{"5000","2"});
/**
* 方式二
* table 表名
* values contentValues 值
* whereClause where 字句之后的内容
* whereArgs 占位符的取值
*/
ContentValues values = new ContentValues();
values.put("name", "小灰灰");
db.update("person", values, "name = ?",
new String[]{"张三"});
db.close();
}
/**
* 删除数据
*/
public void deleteDb() {
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
//方式一
//db.execSQL("delete from person where _id = 1");
//方式二
//table:表名 whereClause:where 字句之后的内容 whereArgs:占位符的取值
//db.delete("person", "name=2", null);
//方式三
//String[] args2 = {"111", "222", "333"};
//db.delete("person", "[name]=? and [id_card]=? and [sign_time]=?", args);
String[] args = {"小灰灰"};
db.delete("person", "[name]=?", args);
db.close();
}
/**
* 删除所有数据
*/
public void deleteDbAll() {
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
db.delete("person", null, null);
db.close();
}
}
3.4. DbOpenHelper
package com.inspur.szyj.helper.db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
/**
* 数据库的创建和版本的更新
* @author zzs
*
*/
public class DbOpenHelper extends SQLiteOpenHelper {
/**
* 构造方法 初始数据库创建的必要参数
* @param context 上下文对象
* name 数据库的名称
* factory 游标工厂 null
* version 数据库的版本号
*/
public DbOpenHelper(Context context) {
super(context, "qf25", null, 1);
}
/**
* 创建初始的数据表
* 第一次创建数据库时被调用(只调用一次)
* SQLiteDatabase db 数据库操作类
*/
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table person(_id integer primary key autoincrement," +
"name varchar(50),id_card varchar(500))");
db.execSQL("alter table person add sign_time varchar(500)");
db.execSQL("alter table person add sign_date varchar(500)");
//db.execSQL("alter table person add amount integer");
}
/**
* 更新数据库
* 如果数据库的版本号发生变化后, 执行此方法
* SQLiteDatabase db 数据库操作类
* int oldVersion 旧版本号
* int newVersion 新版本号
*
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i("info", "数据库更新了");
db.execSQL("alter table person add amount integer");
}
}
3.5. ExcelUtil
package com.inspur.szyj.util;
import android.content.Context;
import android.os.Environment;
import android.os.StatFs;
import android.widget.Toast;
import com.inspur.szyj.bean.OrderBean;
import com.inspur.szyj.bean.PersonBean;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.List;
import jxl.Workbook;
import jxl.format.Colour;
import jxl.write.Label;
import jxl.write.WritableCellFormat;
import jxl.write.WritableFont;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import jxl.write.WriteException;
/**
* Created by zzs on 2016/1/15.
*/
public class ExcelUtil {
//内存地址
public static String root = Environment.getExternalStorageDirectory()
.getPath();
public static void writeExcel(Context context, List<PersonBean> exportOrder,
String fileName) throws Exception {
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
&& getAvailableStorage() > 1000000) {
Toast.makeText(context, "SD卡不可用", Toast.LENGTH_LONG).show();
return;
}
String[] title = {"姓名", "身份证号", "签到时间", "签到日期"};
File file;
File dir = new File(context.getExternalFilesDir(null).getPath());
// File dir = new File(Environment.getExternalStorageDirectory()
// .getAbsolutePath()+ "/excelDirectory");
file = new File(dir, fileName + ".xls");
if (!dir.exists()) {
dir.mkdirs();
}
// 创建Excel工作表
WritableWorkbook wwb;
OutputStream os = new FileOutputStream(file);
wwb = Workbook.createWorkbook(os);
// 添加第一个工作表并设置第一个Sheet的名字
WritableSheet sheet = wwb.createSheet("订单", 0);
Label label;
for (int i = 0; i < title.length; i++) {
// Label(x,y,z) 代表单元格的第x+1列,第y+1行, 内容z
// 在Label对象的子对象中指明单元格的位置和内容
label = new Label(i, 0, title[i], getHeader());
// 将定义好的单元格添加到工作表中
sheet.addCell(label);
}
for (int i = 0; i < exportOrder.size(); i++) {
PersonBean order = exportOrder.get(i);
Label orderNum = new Label(0, i + 1, order.getName());
Label restaurant = new Label(1, i + 1, order.getIdCard());
Label nameLabel = new Label(2, i + 1, order.getSignTime());
Label address = new Label(3, i + 1, order.getSignDate());
sheet.addCell(orderNum);
sheet.addCell(restaurant);
sheet.addCell(nameLabel);
sheet.addCell(address);
Toast.makeText(context, "写入成功", Toast.LENGTH_LONG).show();
}
// 写入数据
wwb.write();
// 关闭文件
wwb.close();
}
public static WritableCellFormat getHeader() {
WritableFont font = new WritableFont(WritableFont.TIMES, 10,
WritableFont.BOLD);// 定义字体
try {
font.setColour(Colour.BLUE);// 蓝色字体
} catch (WriteException e1) {
e1.printStackTrace();
}
WritableCellFormat format = new WritableCellFormat(font);
try {
format.setAlignment(jxl.format.Alignment.CENTRE);// 左右居中
format.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);// 上下居中
// format.setBorder(Border.ALL, BorderLineStyle.THIN,
// Colour.BLACK);// 黑色边框
// format.setBackground(Colour.YELLOW);// 黄色背景
} catch (WriteException e) {
e.printStackTrace();
}
return format;
}
/** 获取SD可用容量 */
private static long getAvailableStorage() {
StatFs statFs = new StatFs(root);
long blockSize = statFs.getBlockSize();
long availableBlocks = statFs.getAvailableBlocks();
long availableSize = blockSize * availableBlocks;
// Formatter.formatFileSize(context, availableSize);
return availableSize;
}
}