SQLite数据库
SQLite数据库简介
SQLite是一个轻量级数据库,它是D.Richard Hipp建立的公有领域项目,在2000年发布了第一个版本。它的设计目标是嵌入式的,而且占用资源非常低,在内存中只需要占用几百KB的存储空间,这也是Android移动设备采用SQLite的原因之一。
SQLite没有服务器进程,它通过文件保存数据,该文件是跨平台的,可以放在其他平台中使用。并且在保存数据时,支持null(零)、integer(整数)、real(浮点数字)、text(字符串文本)和blob(二进制对象)5种数据类型。
数据库的创建
Android系统推荐使用SQLiteOpenHelper
的子类创建数据库,因此需要创建一个类继承自SQLiteOpenHelper
,并重写该类中的onCreat()
方法和onUpgrade()
方法即可,示例代码如下:
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import androidx.annotation.Nullable;
public class MyHelper extends SQLiteOpenHelper {
public MyHelper(Context context) {
super(context, "itcast.db", null, 2);//上下文对象,数据库名称,游标工厂(通常是null),数据库版本
}
//数据库第一次被创建时调用该方法
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE information(_id INTEGER PRIMARY KEY AUTOINCREMENT,name VARCHAR(20),price INTEGER)");
}
//当数据库的版本号增加时调用
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
数据库的使用
SQLite的基本操作
-
增加一条数据
public void insert(String name, String price) { SQLiteDatabase db = helper.getWritableDatabase(); //获取可读写 SQLiteDatabase 对象 ContentValues values = new ContentValues(); //创建 ContentValues 对象 values.put("name", name); //将数据添加到 ContentValues 对象 values.put("price", price); long id = db.insert("information", null, values); //插入一条数据到information表 db.close(); //关闭数据库 }
使用完
SQLiteDatabase
对象后一定要调用close()
方法关闭,否则数据库连接会一直村咋子,不断消耗内存,当系统内存不足时将获取不到SQLiteDatabase
对象,并且会爆出数据库未关闭异常。 -
修改一条数据
public int update(String name, String price) { SQLiteDatabase db = helper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put("price", price ); int number = db.update("information", values, "name=?", new String[]{name}); return number; }
update()
方法接收4个参数,第一个参数表示表名,第二个参数接收一个ContentValues
对象,第三个参数为可选的where语句,第四个参数表示whereClause语句中表达式的占位参数列表,这些字符会替换掉where条件中的 “ ? ”。 -
删除一条数据
public int delete(long id) { SQLiteDatabase db = helper.getWritableDatabase(); int number = db.delete("information", "_id=?", new String[]{id + ""}); Toast.makeText(MainActivity.this, "删除成功", Toast.LENGTH_SHORT).show(); return number; }
-
查询一条数据
public boolean find(long id) { SQLiteDatabase db = helper.getReadableDatabase(); //获取可读 SQLiteDatabase 对象 Cursor cursor = db.query("information", null, "_id=?", new String[]{id + ""}, null, null, null); boolean result = cursor.moveToNext(); cursor.close(); //关闭游标 db.close(); return result; }
query()
方法接收7个参数,第一个参数表示表的名称,第二个参数表示查询的列名,第三个参数接收查询条件子句,第四个参数接收查询子句对应的条件值,第五个参数表示分组方式,第六个参数接收having条件,即定义组的过滤器,第七个参数表示排序方式。 -
删除所有数据
public void deleteAll(){ db = helper.getWritableDatabase(); db.execSQL("delete from information"); //只删除表的数据,不破坏表的结构 }
SQLite中的事务
事务是一个对数据库执行工作的单元,是针对数据库的一组操作,它可以由一条或者多条SQL语句组成。事务是以逻辑顺序完成的工作单位或者序列,可以是由用户手动操作完成,也可以是由某种数据库程序自动完成。同一个事物的操作具备同步的特点,如果其中有一条语句无法执行,那么所有的语句都不会执行。
MyHelper helper = new MyHelper(MainActivity.this);
SQLiteDatabase db = helper.getWritableDatabase();
db.beginTransaction(); //开始数据库事务
try {
db.execSQL("update person set account = account-1000 where name =?",
new Object[]{"zhangsan"}); //执行转出操作*
db.execSQL("update person set account = account+1000 where name =?",
new Object[]{"wangwu"}); //执行转入操作
db.setTransactionSuccessful(); //标记数据库事务执行成功
} catch (Exception e) {
Log.i("事务处理失败", e.toString());
} finally {
db.endTransaction(); //关闭事物
db.close(); //关闭数据库
}
数据展示控件
Listview控件
ListView
是以列表的形式展示具体数据内容。当数据过多时会出现滚动条,并且能够根据数据的长度自适应屏幕显示。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".MainActivity">
<ListView
android:id="@+id/LV"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:divider="#d9d9d9"
android:dividerHeight="1dp" />
</RelativeLayout>
class MyBaseAdapter extends BaseAdapter {
@Override
public int getCount() {
return names.length;
}
@Override
public Object getItem(int position) {
return names[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = View.inflate(MainActivity.this,R.layout.list_item,null);
TextView TV = (TextView) view.findViewById(R.id.TV);
TV.setText(names[position]);
ImageView imageView = (ImageView) view.findViewById(R.id.image);
imageView.setBackgroundResource(imgs[position]);
return view;
}
class ViewHolder {
TextView TV;
ImageView img;
}
}
ListView
在定义了id属性之后,才会看到如下图所示的界面。如果ListView
没有进行数据适配,那么程序运行之后界面空白,无数据显示。
ListView的优化
在使用 ListView 展示数据时需要创建对应的 Item 条目展示每条数据。如果展示的数据有成千上万条,那么就需要创建成千上万个 Item,这样会 大大增加内存的消耗,甚至会由于内存溢出导致程序崩溃。为了防止这种情况的出现,就需要对 ListView 进行优化。ListView 优化有两种方式,一种是复用 convertview,一种是使用 ViewHolder 类。
-
复用 convertView
在 ListView 第一次展示时,系统会根据屏幕的高度和 ltem 的高度创建一定数量的 convertView。当滑动 ListView 时,顶部的 Item 会滑出屏幕,同时释放它所使用的 convertView, 底部新的数据会进入屏幕进行展示,这时新的数据会使用顶部滑出 Item 的converView,从而使整个 ListView 展示数据的过程使用固定数量的 convertView,避免了每次创建新的 Item 而消耗大量内存。
-
使用 ViewHolder 类
在加载 Item 布局时,会使用 findViewByld()方法找到 Item 布局中的各个控件,在每一次加 载新的 ltem 数据时都会进行控件寻找,这样也会产生耗时操作。为了进一步优化 Listview 减少耗时操作,可以将要加载的子 View 放在 ViewHolder 类中,当第一次创建 convertView 时将这些控件找出,在第二次重用 convertView 时就可直接通过 convertView 中的 getTag()方法获得这些控件。
接下来使用上述两种优化方式对上一小节代码进行优化,示例代码如下:
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = LayoutInflater.from(
getApplicationContext()).inflate(R.layout.list_item, parent, false);
holder = new ViewHolder();
holder.TV = (TextView) convertView.findViewById(R.id.TV);
holder.img = (ImageView) convertView.findViewById(R.id.image);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.TV.setText(names[position]);
holder.img.setBackgroundResource(imgs[position]);
return convertView;
}
class ViewHolder {
TextView TV;
ImageView img;
}
常用的数据适配器
-
BaseAdapter
BaseAdapter
实际上是一个抽象类,通常在使用自定义适配器时需要继承BaseAdapter
,该类拥有4个抽象方法。即:
方法名称 功能描述 public int getCount() 得到Item的条数 public Object getItem(int position) 根据position(位置)得到某个Item的对象 public long getItemId(int position) 根据position(位置)得到某个Item的id public View getView(int position, View convertView, ViewGroup parent) 得到相应position对应的Item视图,position是当前Item的位置,convertView用于复用旧视图,parent用于加载XML布局 -
SimpleAdapter
SimpleAdapter
继承自BaseAdapter
,实现了BaseAdapter
的4个抽象方法并进行了封装。因此在使用SimpleAdapter
进行数据是配时,只需要在构造方法里传入相应的参数即可,SimpleAdapter的构造方法如下所示:public SimpleAdapter(Context context, List<? extends Map<String, ?>> data,int resource,String[] from,int[] to);
所对应的参数分别是:Context上下文对象、数据集合,data中的每一项对应着ListView中的每一项数据、Item布局的资源id、Map集合里的key值,Item布局相应的控件id。
-
ArrayAdapter
ArrayAdapter也是BaseAdapter的子类,用法和SimpleAdapter类似。ArrayAdapter通常用于适配TextView控件,例如Android系统中的Setting(设置菜单)。
public ArrayAdapter(Context context, int resource); public ArrayAdapter(Context context, int resource, int textViewResourceId); public ArrayAdapter(Context context, int resource, T[] objects); public ArrayAdapterContext context, int resource, int textViewResourceId, T[] objects); public ArrayAdapter(Context context, int resource, List<T> objects); public ArrayAdapter(Context context, int resource, int textViewResourceId, List<T> objects)
ArrayAdapter构造方法中的参数:
- Context context:Context上下文对象。
- int resource:Item布局的资源id。
- int textViewResourceId:Item布局中相应TextView的id。
- T[] objects:需要适配的数据数组,数据类型数据。
- List objects:需要适配的数据数组,List类型数据。