在Android的项目开发中,都会用到数据库,SQLite作为本地数据库,是一定要会的。Android团队封装了很多对SQLite操作的API。我这里自己写了一个Demo来总结一下SQLit的基本使用方法。
先上截图
Android专门提供了一个SQLiteOpenHelper帮助类,可以非常简单地对数据库进行创建和升级。
首先创建数据库,我们这里创建一个类继承SQLiteOpenHelper类,并重写onCreate()和onUpgrade()方法:
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
* Created by lenovo on 2018/10/14.
*/
public class DatabaseUtil extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "PhoneBook.db"; //数据库名
private static final int DATABASE_VERSION = 1; //数据库版本号
public DatabaseUtil(Context context){
super(context,DATABASE_NAME,null,DATABASE_VERSION);
}
/**
* 创建数据库
* */
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
createTable(sqLiteDatabase);
}
/**
* 建立数据表
* */
private void createTable(SQLiteDatabase db){
db.execSQL("create table UserInfo(" +
"id integer primary key autoincrement," +
"userName text," +
"userPhone text)");
}
/**
* 升级数据库
* */
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
这个类主要用于建立数据库和更新数据库
实例化这个类的时候构造函数传入上下文,并继承父类构造函数,数据库名称和版本号都已经写成了常量。onCreate()方法在创建时和创建后只会调用一次,所以在这里面创建一次数据表就行了,而onUpgrade()方法只有在数据库版本号大于上次传入的值时调用,用于对数据库进行更新操作,如新建表,更改列等。
创建一个Utildao类专门对数据库进行增删改查操作,主要目的是与逻辑代码分开便于代码维护,附上代码:
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.example.lenovo.work.entity.User;
import java.util.ArrayList;
import java.util.List;
/**
* Created by lenovo on 2018/10/16.
*/
public class UtilDao {
private DatabaseUtil du;
private SQLiteDatabase db;
public UtilDao(Context context){
du = new DatabaseUtil(context);
db = du.getWritableDatabase();
}
/**
* 添加数据
* */
public void addData(String tableName,String[] key,String[] values){
ContentValues contentValues = new ContentValues();
for(int i = 0; i < key.length; i ++){
contentValues.put(key[i],values[i]);
}
db.insert(tableName,null,contentValues);
contentValues.clear();
}
/**
* 删除数据
* */
public int delData(String where,String[] values){
int del_data;
del_data = db.delete("UserInfo",where,values);
return del_data;
}
/**
* 修改数据
* */
public void update(String[] values){
db.execSQL("update UserInfo set userName=?,userPhone=? where userName=? ",values);
}
/**
* 查询数据
* */
public List<User> inquireData(){
List<User> list = new ArrayList<>();
Cursor cursor = db.rawQuery("select userName,userPhone" +
" from UserInfo",null);
while(cursor.moveToNext()){
String name = cursor.getString(0);
String phone = cursor.getString(1);
User user = new User();
user.setName(name);
user.setPhone(phone);
list.add(user);
}
return list;
}
/**
* 关闭数据库连接
* */
public void getClose(){
if(db != null){
db.close();
}
}
}
我们先调用帮助类的getWritableDatabase()方法,获取可写入的权限。
Android有两种方法对数据进行增删改查操作,一种是Android封装好的方法,另一种是通用的直接执行SQL语句的方法,我这里为了方便部分使用了面向对象方法,部分是直接执行SQL语句的。使用execSQL()方法直接执行SQL语句没有返回值且容易出错,所以我推荐使用Android自带封装好的方法操作数据库。
添加:
这里调用了帮助类的insert方法,第一个参数传入表名,第二个参数暂时用不到传入null,第三个参数传入ContentValues对象,ContentValues对象提供了put()方法重载,用于向ContentValues中添加数据。
/**
* 添加数据
* */
public void addData(String tableName,String[] key,String[] values){
ContentValues contentValues = new ContentValues();
for(int i = 0; i < key.length; i ++){
contentValues.put(key[i],values[i]);
}
db.insert(tableName,null,contentValues);
contentValues.clear();
}
删除:
调用delete方法,第一个参数传入表名,第二个参数写条件where语句,通常写列名,不写的话删除所有行,第三个传入列名对应的值,最后返回删除的行数。
/**
* 删除数据
* */
public int delData(String where,String[] values){
int del_data;
del_data = db.delete("UserInfo",where,values);
return del_data;
}
修改:
我这里调用了execSQL方法直接写SQL语句,封装的方法为update请自行搜索,这里第一个值是SQL语句没什么好说的,第二个值为传入的条件值,对应SQL语句里的"?"通配符。
/**
* 修改数据
* */
public void update(String[] values){
db.execSQL("update UserInfo set userName=?,userPhone=? where userName=? ",values);
}
查询:
查询代码就比较多了,先调用rawQuery方法查询出结果,再把值赋给Cursor对象,它是一个游标,通过while判断它指向的行下面是否还有数据,若有则把当前行的值存储到User实体类里,然后添加到List数组链表中,循环下一次。这里用到List是因为这需要返回给前台的ListView做数据源。
/**
* 查询数据
* */
public List<User> inquireData(){
List<User> list = new ArrayList<>();
Cursor cursor = db.rawQuery("select userName,userPhone" +
" from UserInfo",null);
while(cursor.moveToNext()){
String name = cursor.getString(0);
String phone = cursor.getString(1);
User user = new User();
user.setName(name);
user.setPhone(phone);
list.add(user);
}
return list;
}
到这里数据访问层和dao层就写好了,接下来实现功能。
因为UtilDao这个类里面的数据库操作方法以后会经常用到,如果每次都 new 一个对象来使用的话会很麻烦,所以我这里使用了MyApplication类来将 UtilDao 类设为全局变量且只有一个实例,这样就方便多了。
import android.app.Application;
import com.example.lenovo.work.dbutil.UtilDao;
/**
* Created by lenovo on 2018/10/16.
*/
public class MyApplication extends Application {
private UtilDao dao;
/**
* 创建时调用
* */
@Override
public void onCreate() {
super.onCreate();
dao = new UtilDao(this);
}
/**
* 后台进程终止,前台程序需要内存时调用此方法,用于释放内存
* 用于关闭数据库连接
* */
@Override
public void onLowMemory() {
super.onLowMemory();
dao.getClose();
}
public UtilDao getDao() {
return dao;
}
}
因为Application组件优先于Activity,在程序运行时最先创建且只创建一次。需要在AndroidManifest.xml里<application>标签里添加name属性,这点很重要!!!不然程序崩溃。
android:name=".MyApplication"
布局很简单,这里我就不过多的解释,自行理解:
<?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="com.example.lenovo.work.MainActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/main_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="联系人"
android:textSize="20sp"
android:layout_centerHorizontal="true"
android:layout_alignBaseline="@id/main_but"/>
<TextView
android:id="@+id/main_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="(0)"
android:layout_toRightOf="@id/main_text"
android:layout_alignBaseline="@id/main_text"/>
<Button
android:id="@+id/main_but"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="添加"/>
</RelativeLayout>
<ListView
android:id="@+id/main_list_view"
android:layout_below="@id/main_but"
android:layout_width="match_parent"
android:layout_height="wrap_content"></ListView>
</LinearLayout>
我们先建一个实体类,用于存储用户信息,作为ListView 的数据源:
public class User {
private String name;
private String phone;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
ListView子布局(item):
<?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="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_margin="10dp">
<TextView
android:id="@+id/item_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="张三"
android:textSize="18sp"
android:textColor="#000000"/>
<TextView
android:id="@+id/item_phone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="15234569876"/>
</LinearLayout>
</LinearLayout>
ListView数据适配器:
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import com.example.lenovo.work.R;
import com.example.lenovo.work.entity.User;
import java.util.List;
/**
* Created by lenovo on 2018/10/14.
*/
public class MyAdapter extends ArrayAdapter<User> {
int resource;
//构造方法传递三个参数,分别为:上下文,列表子布局和列表所需数据
public MyAdapter(Context context, int resource, List<User> list){
//继承父类构造
super(context,resource,list);
//后面会用到
this.resource = resource;
}
//加载适配器时会调用此方法
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
//获得当前显示项的User对象
User user = getItem(position);
ViewHolder holder;
//若是第一次加载页面则调用此方法初始化
if(convertView == null){
convertView = LayoutInflater.from(getContext()).inflate(resource,parent,false);
holder = new ViewHolder();
holder.tv_name = convertView.findViewById(R.id.item_name);
holder.tv_phone = convertView.findViewById(R.id.item_phone);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
//将数据传递给控件并显示
holder.tv_name.setText(user.getName());
holder.tv_phone.setText(user.getPhone());
return convertView;
}
//缓存类,用于存放已存在的对象
class ViewHolder{
TextView tv_name;
TextView tv_phone;
}
}
MainActivity:
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import com.example.lenovo.work.adapter.MyAdapter;
import com.example.lenovo.work.dbutil.UtilDao;
import com.example.lenovo.work.entity.User;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView textNum;
private Button button;
private ListView listView;
private List<User> list,newList;
private UtilDao dao;
private MyAdapter adapter;
private int listNum = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化控件
initWidget();
//实例dao
DbUtil();
//显示ListView
showListView();
//显示listView的条目数量
linkmanNum();
}
/**
* 初始化控件
* */
private void initWidget(){
button = findViewById(R.id.main_but);
listView = findViewById(R.id.main_list_view);
textNum = findViewById(R.id.main_num);
newList = new ArrayList<>();
list = new ArrayList<>();
}
/**
* 显示ListView
* */
public void showListView(){
//查询数据
/**
* 添加数据到链表中
* **/
list = dao.inquireData();
/**
* 创建并绑定适配器
* */
adapter = new MyAdapter(this,R.layout.item,list);
listView.setAdapter(adapter);
/**
* ListView事件监听
* */
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
dialogList();
listNum = i;
}
});
button.setOnClickListener(this);
}
/**
* 普通对话框
* */
public void dialogNormal(){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
DialogInterface.OnClickListener dialogOnClick = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
User userDel = list.get(listNum);
switch (i){
case DialogInterface.BUTTON_POSITIVE:
dao.delData("userName=?",new String[]{userDel.getName()});
refresh();
break;
case DialogInterface.BUTTON_NEGATIVE:
break;
default:break;
}
}
};
builder.setTitle("删除联系人");
builder.setMessage("确定要删除吗?");
builder.setPositiveButton("确定", dialogOnClick);
builder.setNegativeButton("取消",dialogOnClick);
builder.create().show();
}
/**
* 选项列表
* */
public void dialogList(){
final String[] items = {"拨打电话","发送短信","编辑","删除"};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setItems(items, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
//拿到当前选中项的 User 对象
User userNum = list.get(listNum);
Intent intent;
switch (i){
//拨打电话
case 0: intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:" + userNum.getPhone()));
startActivity(intent);
break;
//发送短信
case 1: intent = new Intent(Intent.ACTION_SENDTO);
intent.setData(Uri.parse("smsto:" + userNum.getPhone()));
startActivity(intent);
break;
case 2: intent = new Intent(MainActivity.this,AddData.class);
//传入当前选中项的姓名和电话以在编辑页面中显示在输入框中
intent.putExtra("edit_name",userNum.getName().toString());
intent.putExtra("edit_phone",userNum.getPhone().toString());
startActivityForResult(intent,2);
break;
//弹出对话框提示是否删除
case 3: dialogNormal();
break;
default:
break;
}
}
});
builder.create().show();
}
//刷新
public void refresh(){
//最后查询数据刷新列表
getNotifyData();
}
//页面顶部显示ListView条目数
public void linkmanNum(){
textNum.setText("("+list.size()+")");
}
//点击添加按钮
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.main_but:
//跳转到 AddData Activity 传入请求码 1
Intent intent = new Intent(MainActivity.this,AddData.class);
startActivityForResult(intent,1);
break;
default:break;
}
}
public void DbUtil(){
dao = ((MyApplication)this.getApplication()).getDao();
}
/**
* 当页面回到此活动时,调用此方法,刷新ListView
* */
@Override
protected void onResume() {
super.onResume();
getNotifyData();
}
/**
* 这个是用来动态刷新 * */
public void getNotifyData(){
//使用新的容器获得最新查询出来的数据
newList = dao.inquireData();
//清除原容器里的所有数据
list.clear();
//将新容器里的数据添加到原来容器里
list.addAll(newList);
//更新页面顶部括号里显示数据
linkmanNum();
//刷新适配器
adapter.notifyDataSetChanged();
}
/**
* 上一个页面传回来的值
* */
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode){
//请求码为1,表示点击了添加按钮
case 1:
//执行添加方法
if(resultCode == RESULT_OK){
String[] key = data.getStringArrayExtra("key");
String[] values = data.getStringArrayExtra("values");
dao.addData("UserInfo",key,values);
}
break;
//请求码为2,表示点击了编辑按钮
case 2:
//执行修改方法
if(resultCode == RESULT_OK){
User user = list.get(listNum);
String name = data.getStringExtra("name");
String phone = data.getStringExtra("phone");
String[] values = {name,phone,user.getName()};
dao.update(values);
}
break;
}
}
}
添加修改页面,这两个功能都用的是一个Activity,通过请求码和结果码判断是哪个按钮触发了这个Activity从而实现对应功能业务。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="20dp">
<EditText
android:id="@+id/add_edit_name"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="姓名"/>
<EditText
android:id="@+id/add_edit_phone"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="电话"
android:layout_below="@id/add_edit_name"/>
<Button
android:id="@+id/add_but"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="确定"
android:layout_below="@id/add_edit_phone"
android:layout_alignParentRight="true"/>
</RelativeLayout>
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import com.example.lenovo.work.dbutil.UtilDao;
/**
* Created by lenovo on 2018/10/14.
*/
public class AddData extends AppCompatActivity {
private EditText edit_name,edit_phone;
private Button but;
private UtilDao dao;
private Intent intent;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_adddata);
//初始化组件
initWidget();
DbUtil();
/**
* 点击编辑按钮传过来的值
* 用于显示当前编辑项的数据信息
* */
intent = getIntent();
String user_name = intent.getStringExtra("edit_name");
String user_phone = intent.getStringExtra("edit_phone");
edit_name.setText(user_name);
edit_phone.setText(user_phone);
but.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//获取到两个输入框的值
String name = edit_name.getText().toString();
String phone = edit_phone.getText().toString();
if(!name.equals("") && !phone.equals("")){
/**
* 数据库操作需要用到的数据
* 详情请查看 UtilDao 类下的 addData() 方法
* */
String[] key = {"userName","userPhone"};
String[] values = {name,phone};
intent = new Intent();
//点击添加按钮则返回 key 和 values 数组
intent.putExtra("key",key);
intent.putExtra("values",values);
//点击编辑按钮则返回 name 和 phone 字符串
intent.putExtra("name",name);
intent.putExtra("phone",phone);
setResult(RESULT_OK,intent);
finish();
} else if(name.equals("") || phone.equals("")){
finish();
}
}
});
}
/**
* 初始化控件
* */
private void initWidget(){
edit_name = findViewById(R.id.add_edit_name);
edit_phone = findViewById(R.id.add_edit_phone);
but = findViewById(R.id.add_but);
}
public void DbUtil(){
dao = ((MyApplication)this.getApplication()).getDao();
}
}
OK!大功告成!
最后附上AndroidManifest.xml文件代码:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.lenovo.work" >
<uses-permission android:name="android.permission.CALL_PHONE"/>
<application
android:allowBackup="true"
android:icon="@drawable/txl"
android:label="@string/app_name"
android:roundIcon="@drawable/txl"
android:supportsRtl="true"
android:name=".MyApplication"
android:theme="@style/AppTheme" >
<activity android:name=".MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".AddData"/>
</application>
</manifest>
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------