Android SQLite的基本使用、生成Excel文件保存到本地

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 数据库对象*/@Overridepublic void onCreate(SQLiteDatabase db) {Log.i("TAG", "-------onCreate--------");}/*** 当数据库版本更新时回调的函数* @param db 数据库对象* @param oldVersion 数据库旧版本* @param newVersion 数据库新版本*/@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {Log.i("TAG", "-------onUpGrade-------");}/*** 当数据库打开时回调的函数* @param db 数据库对象*/@Overridepublic 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"><LinearLayoutandroid:orientation="horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"><Buttonandroid:layout_weight="1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="创建数据库"android:onClick="createDb"android:background="#ff3" /><Buttonandroid: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" /><Buttonandroid: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><LinearLayoutandroid:layout_marginTop="60dp"android:orientation="horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"><Buttonandroid: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" /><Buttonandroid: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"/><Buttonandroid: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><LinearLayoutandroid:layout_marginTop="120dp"android:orientation="horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"><Buttonandroid: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" /><Buttonandroid: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"/><Buttonandroid: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;}@Overridepublic 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类型的valueint _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 AppCompatActivityimplements View.OnClickListener {private ListView lv;//控件private Cursor cursor;//数据源//自定义的封装类private DbService dbService;@Overrideprotected 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);}@Overridepublic 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"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:layout_marginBottom="5dp"android:gravity="center_vertical"android:orientation="horizontal"><Buttonandroid: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" /><Buttonandroid: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" /><Buttonandroid: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" /><Buttonandroid:id="@+id/update"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="3dp"android:text="修改数据"android:textSize="13sp" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:layout_marginBottom="5dp"android:gravity="center_vertical"android:orientation="horizontal"><Buttonandroid:id="@+id/select"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="3dp"android:text="查询数据"android:textSize="13sp" /><Buttonandroid:id="@+id/delete"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="3dp"android:text="删除数据"android:textSize="13sp" /><Buttonandroid:id="@+id/delete_all"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="3dp"android:text="删除所有数据"android:textSize="13sp" /><Buttonandroid:id="@+id/save_excel"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="3dp"android:text="保存excel"android:textSize="13sp" /></LinearLayout><ListViewandroid: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   数据库操作类*/@Overridepublic 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       新版本号**/@Overridepublic 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;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/54231.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv11改进 | 独家创新- 注意力篇 | YOLOv11结合全新多尺度线性注意力机制MLAttention(全网独家创新)

1. MLAttention介绍 (1). 多尺度卷积操作&#xff1a;MLAttention通过多尺度卷积操作来增强不同尺度的特征表达能力。采用了多种卷积核尺寸&#xff08;例如5x5、1x7、7x1、1x11、11x1、1x21、21x1&#xff09;的深度可分离卷积来捕捉不同感受野的特征。较小的卷积核擅长捕捉细…

TypeScript 算法手册【快速排序】

文章目录 1. 快速排序简介1.1 快速排序定义1.2 快速排序特点 2. 快速排序步骤过程拆解2.1 选择基准元素2.2 划分数组2.3 递归排序 3. 快速排序的优化3.1 三数取中法选择基准3.2 插入排序与快速排序结合案例代码和动态图 4. 快速排序的优点5. 快速排序的缺点总结 【 已更新完 Ty…

C语言基础(7)之操作符(1)(详细介绍)

目录 1. 各种操作符介绍 1.1 操作符汇总表 2. 移位操作符 2.1 移位操作符知识拓展 —— 原码、反码、补码 2.2 移位操作符讲解 2.2.1 右移操作符 ( >> ) 2.2.2 左移操作符 ( << ) 3. 位操作符 3.1 & (按位与) 3.2 | (按位或) 3.3 ^ (按位异或) 3.4…

排序算法之——归并排序,计数排序

文章目录 前言一、归并排序1. 归并排序的思想2. 归并排序时间复杂度及空间复杂度3. 归并排序代码实现1&#xff09;递归版本2&#xff09;非递归版本 二、计数排序1. 计数排序的思想2. 计数排序的时间复杂度及空间复杂度3. 计数排序代码实现 总结&#xff08;排序算法稳定性&am…

【JavaEE】——线程池大总结

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯&#xff0c; 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01;希望本文内容能够帮助到你&#xff01; 目录 引入&#xff1a;问题引入 一&#xff1a;解决方案 1&#xff1a;方案一——协程/纤程 &#xff08;1…

【完-网络安全】Windows注册表

文章目录 注册表启动项及常见作用五个根节点常见入侵方式 注册表 注册表在windows系统的配置和控制方面扮演了一个非常关键的角色&#xff0c;它既是系统全局设置的存储仓库&#xff0c;也是每个用户的设置信息的存储仓库。 启动项及常见作用 快捷键 WinR打开运行窗口&#x…

【C++】C++基础

目录 一. C关键字(C98) 二、C的第一个程序 三、命名空间 3.1.namespace的价值 3.2.namespace的定义 3.2.命名空间使用 总结&#xff1a;在项目当中第一、第二种方法搭配使用&#xff0c;第三种冲突风险非常大&#xff0c;仅适合练习使用。 四、C输入&输出 五、缺省…

调试分析:[跳数度量]更改为[距离度量]后的 routing_bellmanford 算法

回顾复习2023年8月的《★修改Exata6.2源码&#xff1a;〔修改Bellmanford最短路径路由的衡量标准从【路由跳数】改为【“路由器节点间的物理距离”】&#xff0c;并动画演示〕》&#xff0c;VS2015调试Exata&#xff0c;跟踪调试修改后的[ routing_bellmanford.cpp ]源码&#…

k8s架构,从clusterIP到光电半导体,再从clusterIP到企业管理

clusterIP作为k8s中的服务&#xff0c; 也是其他三个服务的基础 ~]$ kubectl create service clusterip externalname loadbalancer nodeport 客户端的流量到service service分发给pod&#xff0c;pod由控制器自动部署&#xff0c;自动维护 那么问题是service的可用…

计算机网络期末复习真题(附真题答案)

前言&#xff1a; 本文是笔者在大三学习计网时整理的笔记&#xff0c;哈理工的期末试题范围基本就在此范畴内&#xff0c;就算真题有所更改&#xff0c;也仅为很基础的更改数值&#xff0c;大多跑不出这些题&#xff0c;本文包含简答和计算等大题&#xff0c;简答的内容也可能…

【RADARSAT Constellation Mission(RCM)卫星星座简介】

RADARSAT Constellation Mission&#xff08;RCM&#xff09;卫星星座是加拿大太空局&#xff08;CSA&#xff09;的下一代C波段合成孔径雷达&#xff08;SAR&#xff09;卫星星座&#xff0c;以下是对其的详细介绍&#xff1a; 一、基本信息 发射时间&#xff1a;2019年6月…

基于微信小程序的四六级词汇+ssm(lw+演示+源码+运行)

摘 要 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;四六级词汇小程序被用户普遍使用&#xff0c;为方便用户能…

容器适配器-stack、queue、priority_queue和仿函数

目录 1.什么是适配器 2.deque 1.简单了解结构 2.deque的缺陷 3.为什么选择deque作为stack和queue的底层默认容器 3.stack&#xff08;栈&#xff09; 4.queue&#xff08;队列&#xff09; 5.仿函数 6.priority_queue&#xff08;优先级队列&#xff09;&#xff08;堆…

微信小程序map组件自定义气泡真机不显示

最近遇到一个需求需要使用uniapp的map自定义气泡 &#xff0c;做完之后发现在模拟器上好好的&#xff0c;ios真机不显示&#xff0c;安卓页数时好时不好的 一番查询发现是小程序的老问题了&#xff0c;网上的方法都试了也没能解决 后来看到有人说用nvue可以正常显示&#xff0c…

会议平台后端优化方案

会议平台后端优化方案 通过RTC的学习&#xff0c;我了解到了端对端技术&#xff0c;就想着做一个节省服务器资源的会议平台 之前做了这个项目&#xff0c;快手二面被问到卡着不知如何介绍&#xff0c;便有了这篇文章 分析当下机制 相对于传统视频平台&#xff08;SFU&#xff…

Nagle 算法:优化 TCP 网络中小数据包的传输

1. 前言 在网络通信中&#xff0c;TCP&#xff08;传输控制协议&#xff09;是最常用的协议之一&#xff0c;广泛应用于各种网络应用&#xff0c;如网页浏览、文件传输和在线游戏等。然而&#xff0c;随着互联网的普及&#xff0c;小数据包的频繁传输成为一个不容忽视的问题。…

828华为云征文 | 云服务器Flexus X实例:向量数据库 pgvector 部署,实现向量检索

目录 一、什么是向量数据库 pgvector &#xff1f; 二、pgvector 部署 2.1 安装 Docker 2.2 拉取镜像 2.3 添加规则 三、pgvector 运行 3.1 运行 pgvector 3.2 连接 pgvector 3.3 pgvector 常见操作 四、总结 本篇文章通过 云服务器Flexus X实例 部署向量数据库 pgve…

Windows11系统下SkyWalking环境搭建教程

目录 前言SkyWalking简介SkyWalking下载Agent监控实现启动配置SkyWalking启动Java应用程序启动Elasticsearch安装总结 前言 本文为博主在项目环境搭建时记录的SkyWalking安装流程&#xff0c;希望对大家能够有所帮助&#xff0c;不足之处欢迎批评指正&#x1f91d;&#x1f91…

计算机毕业设计之:音乐媒体播放及周边产品运营平台(源码+文档+讲解)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

Json 在线可视化工具,分享几个

文章目录 1.json.cn2.json4u.cn3.jsonvisual.com4.jsoncrack5.altearius.github.io6.json.wanvb.com 前序&#xff1a;本文是对多种 Json 在线可视化工具 的介绍、分享。Json官网 https://www.json.org/json-en.html 个人比较中意第四款&#xff1a; https://jsoncrack.com/ed…