SQLite 是android系统集成的一个轻量级数据库。SQLite 是一个嵌入式的数据库引擎,专门适用于资源有限的设备上,如Android和IOS 上 都是支持的SQLite数据库。本质上SQLite数据库只是一个文件。也就是说,当我们的程序创建或者打开一个SQLite数据库时,其实只是打开了一个文件准备读写。
SQLiteDatabase
android提供了一个SQLiteDatabase代表一个数据库,一旦程序获取了代表指定数据库的SQLiteDatabase对象,就可以通过此对象来对数据库进行操作和管理。
SQLiteDatabase提供了几个静态方法来打开一个文件对应的数据库:
- static SQLiteDataBase openDatabase(String path,SQLiteDataBase.CursorFactoty factory,int flags) :打开path文件所代表的数据库。
- static SQLiteDataBase openOrCreateDatabase(File file ,SQLiteDataBase.CursorFactoty factory) : 打开或者创建(如果不存在)file 文件所代表的数据库
- static SQLiteDataBase openOrCreateDatabase(String path ,SQLiteDataBase.CursorFactoty factory) : 打开或者创建(如果不存在)path路径文件所代表的数据库
获取到SQLiteDatabase对象后,可以通过SQLiteDatabase中的方法来操作数据库:
1. execSQL(String sql,Object [] bindArgs ) :执行带占位符的SQL语句
2. execSQL(String sql) :执行SQL语句
3. insert(String table,String nullColumn,ContentValues values) 执行向表中插入数据
4. update(String table,ContentValues values,String whereClause ,String []whereArgs) 更新指定表中的特点数据
5. delete(String table,String whereClause ,String [] whereArgs ) 删除指定表中的特点数据。
6. Cursor query(String table,String [] columns,String selection,String [] selectionArgs,String groupBy,String having,String orderBy) 对执行数据表执行查询
7. Cursor query(String table,String [] columns,String selection,String [] selectionArgs,String groupBy,String having,String orderBy,String limit) 对执行数据表执行查询,limit 控制最多查询几条数据
8. Cursor query(boolean distinct,String table,String [] columns,String selection,String [] selectionArgs,String groupBy,String having,String orderBy,String limit) 对执行数据表执行查询,limit 控制最多查询几条数据,第一个参数表示是否去掉重复的。
9. rawQuery(String sql,String [] selectionArgs) 执行带占位符的SQL查询
10. beginTransaction() 开始事物
11. endTransaction() 结束事物
其中的增删改查 完全可以通过SQL语句去完成。
所有的查询都返回一个Cursor对象,cursor有以下几种方法移动查询结果的记录指针
1. move(int offset) 将记录指针向上或者向下移动指的行数。正数为向上,负数为向下。
2. boolean moveToLast() 将记录指针移动到最后一行,成功则返回true
3. boolean moveToNext() 将记录指针移动到下一行,成功返回true
4. boolean moveToPosition(int position) 将记录指针移动到指的行,成功返回true
5. boolean moveToPrevious() 将记录指针移动到上一行,移动成功则返回true
一旦指针移动到指定行后,就可以调用Cursor 的 getXXX()方法获取改行的指定列的值。
Android提供的增删改查
1. 使用 insert 方法 插入数据:
SQLiteDatabase 的 insert方法 签名为 long insert(String table,String nullColumnHack,ContentValues values) 这个方法的参数含义为:
table: 插入数据的表名
nullColumnHack :强行插入null值的数据列的列名
values :代表一行记录的数据。
ContentValues 类似于Map,提供了 put(String key,Xxx value) 存入数据,其中key值为列名,提供了getAsXXX(String key) 来取出数据。
如:
ContentValues value = new ContentValues();
value.put("user_name","丿一朵遗憾");
value.put("user_age","18");
//返回新添加记录的行号,行号是一个内部值,与主键id无关,插入失败返回-1
long rowid = db.insert("user_info",null,value);
不管ContentVaules 是否包含数据,执行insert()方法总会插入一条记录,如果为空,则会添加一条除了主键之外的其他字段值都为null的记录。
我们直接用SQL语句来实现则是;“insert into user_info (user_name,user_age) values(“丿一朵遗憾”,“18”)”
2. 使用 update方法 更新数据:
SQLiteDatabase 的update 方法的签名为 update(String table,ContentValues values ,String whereClause ,String [] whereArgs),四个参数含义为:
table 表名
values 更新的数据
whereClause 满足此whereClause 子句的记录将会被更新。
whereArgs 用于为whereClause 子句传递参数。
例如我们更新 name 为 丿一朵遗憾 的年龄,那么可以:
ContentValues values= new ContentValues();
values.put("user_age","25");
int result = db.update("user_info",values,"user_name = ?",new String []{"丿一朵遗憾"});
我们用SQL语句来实现则为:(如果修改多个字段则set 后面的参数用逗号隔开)
“update user_info set user_age = '25' where user_name = '丿一朵遗憾'”;
3. 使用delete 方法删除记录
SQLiteDatabase 的 delete 方法的签名为 delete(String table,String whereClause,String [] whereArgs) 参数说明为:
table 表名
whereClause 满足该whereClause 子句的记录将会被删除
whereArgs 用来为whereClause 子句传入参数
应用为: int result = db.delete(“user_info”,”user_name=?”,String []{“丿一朵遗憾”});
SQL 语句为 : “delete user_info where user_name=‘丿一朵遗憾’”;
4. 使用 query 方法查询记录
SQLiteDataBase 的 query 方法的签名为 query(boolean distinct,String table,String [] columns,String selection, String [] selectionArgs ,String groupBy,String having ,String orderBy,String limit), query 方法的参数含义为:
distinct 是否去除重复记录
table 表名
columns 要查询出来的列名
selection 查询条件子句,相当于select语句where 关键字后面的部分,允许使用占位符“?”
selectionArgs用来为selection子句传入参数,值在数组中的位置必须与占位符在语句中的位置一致,否则会出现异常
groupBy 控制分组,相当于 select 语句 group by 后面的部分
having 用来对分组进行过滤,相当于 select 语句 having 后面的部分
orderBy 用来对记录进行排序,相当于 select 语句 order by 后面的部分 (如desc,asc 等)
limit 用来进行分页
SQLiteOpenHelper 类
SQLiteOpenHelper 类是Android 为我们提供的一个管理数据库的工具类。可以用于管理数据库的创建和版本更新。一般我们创建SQLiteOpenHelper 的子类, 然后扩展onCreate(SQLiteDatabase db) 和 onUpgrade(SQLiteDatabase db,int oldVersion, int newVersion) 方法
SQLiteOpenHelper 包含以下的常用方法:
- SQLiteDatabase getReadableDatabase() 以读写的方式打开数据库对应的SQLiteDatabase 对象。
- SQLiteDatabase getWritableDatabase() 以写的方式打开数据库对应的SQLiteDatabase对象
- abstract void onCreate(SQLiteDatabase db) 当第一次创建数据库时回调。
- abstract void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion); 当数据库版本更新时回调该方法
- synchronized void close() 关闭所有打开的db
onCreate 方法用于初次使用软件时生成数据库表,当调用 SQLiteOpenHelper 类的 getReadableDatabase() 或者getWritableDatabase() 方法时 来获取操作数据库的实例 SQLiteDatabase 时,如果数据库不存在,Android 系统会自动生成一个数据库,接着调用onCreate()方法,onCreate()方法在初次生成数据库时才会被调用,在onCreate()方法里可以生成数据库表结构以及添加一些数据的初始化操作。
onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)方法 用于升级软件时更新数据库表结构,方法在数据库版本发生变化时会被调用,oldVersion 代表旧版本号,newVersion代表新版本号,当我们创建SQLiteOpenHelper时,必须指定一个version 参数,这参数就是数据库的初始版本号。
只要某次创建SQLiteOpenHelper 对象时,指定的版本号高于之前的版本号,系统就会自动触发onUpgrade()方法,程序可以在此方法中对表结构进行更新。
以getWritableDatabase() 方法来打开数据库,如果数据库的磁盘空间满了,就只能读,不能写,用这种方法打开就会出错。
以getReadableDatabase() 方法来打开数据库,如果磁盘空间满了就会打开失败,当点打开失败后,会继续尝试以只读的方式打开数据库。
用法也不复杂;
// MyDBHelper dbHelper = new MyDBHelper(this,”user.db3”,null,1);
// SQLiteDatabase db = dbHelper.getReadableDatabase();
public class MyDBHelper extends SQLiteOpenHelper {
private String CREATE_TABLE = "create table user_info(_id integer primary key autoincrement, user_name varchar(50),user_age varchar(50),user_sex varchar(10))";
public MyDBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
System.out.println("oldVersion="+oldVersion+"\n"+"newVersion="+newVersion);
}
}
实例测试
大概步骤:
1. 创建一个db
2. 创建一个user_info的表,里面包含字段为 _id,user_name,user_age,user_sex
3. 添加一个列表来显示我们表里的所有数据。
4. 放置几个按钮来实现增、删、改、查
!!!!!如果你没有检查权限的包,你可以注释掉权限检查的那里
Activity的布局代码 activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btn_insert"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="插入" />
<Button
android:id="@+id/btn_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="删除" />
<Button
android:id="@+id/btn_updata"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="修改" />
<Button
android:id="@+id/btn_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="查询" />
</LinearLayout>
<ListView
android:id="@+id/listview_show"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
MainActivity.java
public class MainActivity extends PermissionActivity implements View.OnClickListener {
SQLiteDatabase db;
String name, age, sex;
private MyAdapter mAdapter;
private ArrayList<UserInfo> list = new ArrayList<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//首先检查是否有读写的权限(需要第三方库的支持!!!)
checkPermission(new CheckPermListener() {
@Override
public void superPermission() {
initViews();
}
}, R.string.perm_tip, Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
/**
* 初始化界面中的控件
*/
private void initViews() {
/**打开或者创建数据库*/
db = SQLiteDatabase.openOrCreateDatabase(MainActivity.this.getFilesDir().toString() + "/user.db3", null);
//添加四个按钮的监听
findViewById(R.id.btn_insert).setOnClickListener(this);
findViewById(R.id.btn_delete).setOnClickListener(this);
findViewById(R.id.btn_updata).setOnClickListener(this);
findViewById(R.id.btn_select).setOnClickListener(this);
//初始化ListView 并且设置适配器
ListView mListView = (ListView) findViewById(R.id.listview_show);
mAdapter = new MyAdapter(this, list);
mListView.setAdapter(mAdapter);
/**
* 点击修改
* */
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
showMyDialog(3, position, "修改");
}
});
/**
* 长按删除
* */
mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
deleteThisItem(position);//删除这条数据
return true;//如果这里是false 那么执行完onItemLongClickListener之后还会执行OnItemClickListener
}
});
}
/**
* 实现控件中的监听事件
*/
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_insert://新增
showMyDialog(1, 0, "新增");
break;
case R.id.btn_updata://修改
Toast.makeText(this, "请点击item去修改", Toast.LENGTH_SHORT).show();
break;
case R.id.btn_delete://删除
Toast.makeText(this, "请长按item去删除", Toast.LENGTH_SHORT).show();
break;
case R.id.btn_select://查询
selectAll();
break;
}
}
/**
* 更新列表显示
*/
private void initListView(Cursor cursor) {
list.clear();
//遍历表中的所有数据
while (cursor.moveToNext()) {
UserInfo info = new UserInfo();
info.setId(cursor.getInt(0));
info.setUserName(cursor.getString(1));
info.setUserAge(cursor.getString(2));
info.setUserSex(cursor.getString(3));
list.add(0, info);
}
mAdapter.notifyDataSetChanged();
}
/**
* 自定义对话框
*/
private void showMyDialog(final int flag, final int position, String title) {
View view = LayoutInflater.from(this).inflate(R.layout.my_dialog, null);
//对话框
final Dialog dialog = new AlertDialog.Builder(MainActivity.this, R.style.NobackDialog).create();
dialog.show();
dialog.getWindow().setContentView(view);
dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE |
WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
dialog.setTitle(title);
//新增
final EditText mName = (EditText) view.findViewById(R.id.et_name);
final EditText mSex = (EditText) view.findViewById(R.id.et_sex);
final EditText mAge = (EditText) view.findViewById(R.id.et_age);
//如果是修改则先将原来的数据显示出来
if (flag == 3) {
mName.setText(list.get(position).getUserName());
mAge.setText(list.get(position).getUserAge());
mSex.setText(list.get(position).getUserSex());
mName.setSelection(mName.getText().toString().length());//将光标移动到最后
mAge.setSelection(mAge.getText().toString().length());//将光标移动到最后
mSex.setSelection(mSex.getText().toString().length());//将光标移动到最后
}
Button mEnsure = (Button) view.findViewById(R.id.btn_ensure);
Button mCancel = (Button) view.findViewById(R.id.btn_cancel);
mEnsure.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
name = mName.getText().toString();
sex = mSex.getText().toString();
age = mAge.getText().toString();
if (TextUtils.isEmpty(name) || TextUtils.isEmpty(sex) || TextUtils.isEmpty(age)) {
Toast.makeText(MainActivity.this, "不能留空", Toast.LENGTH_SHORT).show();
} else {
if (flag == 3) {
update(position, name, age, sex);
} else {
insert(name, age, sex);//插入到数据库中
}
dialog.dismiss();
selectAll();//重新遍历所有数据,显示到listview中
}
}
});
mCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
}
/**
* 查询所有数据
*/
private void selectAll() {
//查表获取到cursor对象,如果出错,则先去创建一个表,然后再差
Cursor cursor;
try {
cursor = db.rawQuery("select * from user_info", null);
} catch (SQLiteException se) {
db.execSQL("create table user_info(_id integer primary key autoincrement, user_name varchar(50),user_age varchar(50),user_sex varchar(10))");
cursor = db.rawQuery("select * from user_info", null);
}
/*更新列表的显示*/
initListView(cursor);
}
/**
* 删除一条数据
*/
private void deleteThisItem(int position) {
//两种写法都行
// int flag = db.delete("user_info", "_id =?", new String[]{list.get(position).getId().toString()});
db.execSQL("delete from user_info where _id=" + list.get(position).getId().toString());
try {
Cursor cursor = db.rawQuery("select * from user_info", null);
initListView(cursor);
} catch (Exception e) {
Toast.makeText(this, String.valueOf(e), Toast.LENGTH_SHORT).show();
}
}
/**
* 将内容插入到db中
*/
private void insert(String name, String age, String sex) {
//直接执行SQL语句
// db.execSQL("insert into user_info values(null,?,?,?)", new String[]{name, age, sex});
db.execSQL("insert into user_info(user_name,user_age,user_sex) valuse(name,age,sex)");
//Android中提供的写法
// ContentValues cv = new ContentValues();
// cv.put("user_name", name);
// cv.put("user_age", age);
// cv.put("user_sex", sex);
// db.insert("user_info",null,cv);
}
/**
* 更新一条数据
*/
private void update(int position, String name, String age, String sex) {
//两种写法 直接执行sql语句时候 一定要注意 user_name = 'xxx' 不然语法是错误的!!!!
db.execSQL("update user_info set user_name='" + name + "',user_age='" + age + "',user_sex='" + sex + "' where _id=" + list.get(position).getId());
// ContentValues cv = new ContentValues();
// cv.put("user_name", name);
// cv.put("user_age", age);
// cv.put("user_sex", sex);
// db.update("user_info", cv, "_id=?", new String[]{list.get(position).getId().toString()});
}
@Override
protected void onDestroy() {
super.onDestroy();
db.close();//关闭数据库 释放资源。
}
}
适配器MyAdapter.java
public class MyAdapter extends BaseAdapter {
ArrayList<UserInfo> list;
Context mContext;
public MyAdapter(Context mContent, ArrayList<UserInfo> list) {
this.mContext = mContent;
this.list = list;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int i) {
return list.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder holder = null;
if (view == null) {
view = LayoutInflater.from(mContext).inflate(R.layout.item, null);
holder = new ViewHolder();
holder.tv_name = (TextView) view.findViewById(R.id.item_name);
holder.tv_sex = (TextView) view.findViewById(R.id.item_sex);
holder.tv_age = (TextView) view.findViewById(R.id.item_age);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
holder.tv_name.setText(list.get(i).getUserName()+" "+list.get(i).getId());
holder.tv_sex.setText(list.get(i).getUserSex());
holder.tv_age.setText(list.get(i).getUserAge());
return view;
}
class ViewHolder {
TextView tv_name, tv_sex, tv_age;
}
}
自定义dialog:my_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="20dp"
android:background="@android:color/white"
android:orientation="vertical">
<LinearLayout
android:id="@+id/layout_insert"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:id="@+id/et_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入姓名" />
<EditText
android:id="@+id/et_sex"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入性别" />
<EditText
android:id="@+id/et_age"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入年龄" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btn_ensure"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="确定" />
<Button
android:id="@+id/btn_cancel"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="取消" />
</LinearLayout>
</LinearLayout>
Dialog中的背景样式:
<style name="NobackDialog" parent="@android:style/Theme.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
</style>
检查权限时候的字符串:
<string name="perm_tip">
当前应用缺少必要权限。\n请点击"设置"-"权限"-打开所需权限。\n最后点击两次后退按钮,即可返回。
</string>
方上此demo的源码:http://download.csdn.net/detail/qq_27561483/9636187