上次练习了ContentProvider,知道了一些基本原理,这次接着学习关于里面的SQLite部分。
这次练习的大致内容:SQLite的增,删,查询功能(这次是存放一个Programmer类的数据)。
大致实现思路:(借鉴了其他人的CSDN博客)
1.一个封装数据的Programmer类(包含,id,name,age,level,info信息)
2.数据库帮助管理类:DBHelpManager(继承自SQLiteOpenHelper类,里面负责数据库的创建以及更新,外部可以通过此类的getWritableDatabase()方法来创建或得到一个具有写入权限的SQLiteDatabase,通过getReadableDatabase()来得到一个具有读取权限的SQLiteDatabase)
3.一个数据库操作的规范接口SQLOperate:(里面声明一些对数据库的操作方法)
4.一个数据库操作的具体实现类SQLOperateEntity(实现SQLOperate接口):(具体定义数据库的增,删,查询等功能)
5.一个存放数据库操作的常量的类: SQLMetaData(里面定义一些静态常量,如数据库名,表名,表中的具体属性等)
6.测试所需的Activity:SqlDemoActivity(添加文本输入框,按钮,显示列表等,然后将按钮功能与具体数据库的操作绑定)
错误小结以及解决方法:
1.一些容易出错的 地方要常用try...exception(最好指明具体的错误类型,如SQLException).比如获取EditText里面的文本并且转换为int型时.
2.list
未来展望:
1.这次的数据库是使用了OpenHelper类的自动创建方法,所以会创建在(data/data/packagename/)目录下,下次自己定义创建路径(SD卡)
方法(1.1):继承并重写ContextWrapper的方法,使得创建的时候自定义选择路径
方法(1.2):放弃使用OpenHelper,自定义数据库的创建,删除等操作方法
2.放弃使用OpenHelper类,自己定义数据库插入,删除等方法(灵活,而且可以用statement,事务支持等)
编程有感:一个小小的程序都得耗费N多时间。
总结:不积跬步无以至千里,继续努力吧!
10/28日更新内容:
1.完成了自定义数据库创建路径,通过继承ContextWrapper并改写Context行为
2.优化了EditText组件
新的工程路径:http://download.csdn.net/detail/u010979495/8091361
1.Programmer类
/**该类的作用是封装数据,与对应的表格相应*/
public class Programmer {
private int _id;//与所建立的表对应,与SQLite中的主键完全一致
private String name;
private int age;
private int level;
private String info;
public Programmer(int _id,String name,int age,int level,String info)
{
this._id=_id;
this.name=name;
this.age=age;
this.level=level;
if(info!=null) this.info=info;
}
//默认构造,全为空值
public Programmer()
{
this._id=0;
this.name="";
this.age=0;
this.level=0;
this.info="";
}
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;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
2.DBHelpManager类
/**数据库操作的帮助类*/
public class DBHelpManager extends SQLiteOpenHelper{
private static final String TAG="DBHelpManager";
//定义创建数据库的SQL语句
private static final String CREATE_TABLE="CREATE TABLE "
+SQLMetaData.P1_TABLE_NAME
+" ("
+TableMetaData._ID+" INTEGER PRIMARY KEY, "
+TableMetaData.PROGRAMMER_NAME+" TEXT, "
+TableMetaData.PROGRAMMER_AGE+" INTEGER, "
+TableMetaData.PROGRAMMER_LEVEL+" INTEGER, "
+TableMetaData.PROGRAMMER_INFO+" TEXT"
+");";
public DBHelpManager(Context context) {
super(context, SQLMetaData.DATABASE_NAME,
null, SQLMetaData.DATABASE_VERSION);
}
//数据库第一次被创建时调用
//会默认创建在"/data/data/packagename/"目录下
@Override
public void onCreate(SQLiteDatabase db) {
Log.i(TAG,"创建表:"+db.getPath());
db.execSQL(CREATE_TABLE);
}
//版本升级时调用
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i(TAG,"更新数据库,从"+oldVersion+"到"
+newVersion+",以前的数据会被销毁");
//销毁的sql语句
String sql="DROP TABLE IF EXISTS"+SQLMetaData.P1_TABLE_NAME;
//执行
db.execSQL(sql);
//重新创建db
onCreate(db);
}
}
3.SQLOperate接口
/**定义一个SQLite操作规范的接口---采用接口单一原则*/
public interface SQLOperate {
public abstract void add(Programmer p);
//只有id具有唯一性
public abstract void delete(int id);
public abstract void update(Programmer p);
//查询,全部,单一
public abstract List find();
public abstract Programmer fingById(int id);
}
4.SQLOperateEntity
/**数据库操作的具体类,实现操作规范的接口*/
public class SQLOperateEntity implements SQLOperate{
private static final String TAG="SQLOperateEntity";
//数据库帮助对象的引用
private DBHelpManager dbOpenHelper;
/**构造方法*/
public SQLOperateEntity(Context context)
{
//产生一个DB帮助对象,里面创建一个SQLite数据库
Log.i(TAG,TAG+"中创建数据库帮助类对象dbOpenHelper");
dbOpenHelper=new DBHelpManager(context);
}
/**
* 增,用insert向数据库中插入数据
*/
@Override
public void add(Programmer p) {
Log.i(TAG,TAG+"中插入数据");
//其实在执行getWritableDatabase()时,dbOpenHelper会进行判定(打开还是创建数据库)
SQLiteDatabase db=dbOpenHelper.getWritableDatabase();
ContentValues values=new ContentValues();
values.put(TableMetaData._ID,p.get_id());
values.put(TableMetaData.PROGRAMMER_NAME, p.getName());
values.put(TableMetaData.PROGRAMMER_AGE, p.getAge());
values.put(TableMetaData.PROGRAMMER_LEVEL, p.getLevel());
values.put(TableMetaData.PROGRAMMER_INFO, p.getInfo());
//其实这种错误捕获方法是没用的,因为底层的SQLiteDatabase已经自动进行了错误捕获
db.insert(SQLMetaData.P1_TABLE_NAME, null, values);
}
/**
* 删,通过id删除数据
*/
@Override
public void delete(int id) {
Log.i(TAG,TAG+"中删除数据");
SQLiteDatabase db=dbOpenHelper.getWritableDatabase();
String whereClause=TableMetaData._ID+"=?";//删除某个键值的判断
String[] whereArgs=new String[]{String.valueOf(id)};//得到ID的string
db.delete(SQLMetaData.P1_TABLE_NAME, whereClause, whereArgs);
}
/**
* 改,修改指定id的数据
*/
@Override
public void update(Programmer p) {
Log.i(TAG,TAG+"中更新数据");
SQLiteDatabase db=dbOpenHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(TableMetaData._ID,p.get_id());
values.put(TableMetaData.PROGRAMMER_NAME, p.getName());
values.put(TableMetaData.PROGRAMMER_AGE, p.getAge());
values.put(TableMetaData.PROGRAMMER_LEVEL, p.getLevel());
values.put(TableMetaData.PROGRAMMER_INFO, p.getInfo());
//根据id进行更新的
String whereClause=TableMetaData._ID+"=?";//删除某个键值的判断
String[] whereArgs=new String[]{String.valueOf(p.get_id())};//得到ID的string
db.update(SQLMetaData.P1_TABLE_NAME, values, whereClause, whereArgs);
}
/**
* 查,查询表中所有的数据
* 查询时不使用etWritableDatabase()而是ReadableDatabase()
*/
@Override
public List find() {
Log.i(TAG,TAG+"中查询全部数据");
List programmers=null;
SQLiteDatabase db=dbOpenHelper.getReadableDatabase();
Cursor cursor=null;
//得到整个表的Cursor
cursor = db.query(SQLMetaData.P1_TABLE_NAME,
null, null, null, null, null, null);
if(cursor !=null)
{
programmers=new ArrayList();
//循环完所有的记录
for(cursor.moveToFirst();!cursor.isAfterLast();cursor.moveToNext())
{
Programmer programmer=new Programmer();
//得到id的对应索引和值
int _id=cursor.getInt(cursor.getColumnIndex
(TableMetaData._ID));
//得到name的对应索引和值
String name=cursor.getString(cursor.getColumnIndex
(TableMetaData.PROGRAMMER_NAME));
//得到age的对应索引和值
int age=cursor.getInt(cursor.getColumnIndex
(TableMetaData.PROGRAMMER_AGE));
//得到level的对应索引和值
int level=cursor.getInt(cursor.getColumnIndex
(TableMetaData.PROGRAMMER_LEVEL));
//得到info的对应索引和值
String info=cursor.getString(cursor.getColumnIndex
(TableMetaData.PROGRAMMER_INFO));
programmer.set_id(_id);
programmer.setName(name);
programmer.setAge(age);
programmer.setLevel(level);
programmer.setInfo(info);
//添加进对应的list
programmers.add(programmer);
}
}
return programmers;
}
/**
* 查询指定id的数据
*/
@Override
public Programmer fingById(int id) {
Log.i(TAG,TAG+"中查询单个数据:id="+id);
SQLiteDatabase db=dbOpenHelper.getReadableDatabase();
//得到某一条数据的Cursor
String selection=TableMetaData._ID+"=?";
String[] selectionArgs=new String[]{String.valueOf(id)};
Cursor cursor=null;
try {
cursor = db.query(SQLMetaData.P1_TABLE_NAME,
null,selection, selectionArgs, null, null, null);
} catch (Exception e) {
Log.i(TAG,"单个查询错误!"+e.getMessage());
}
Programmer programmer=null;
//只有一条记录
if(cursor!=null&&cursor.moveToFirst())
{
programmer=new Programmer();
//得到id的对应索引和值
int _id=cursor.getInt(cursor.getColumnIndex
(TableMetaData._ID));
//得到name的对应索引和值
String name=cursor.getString(cursor.getColumnIndex
(TableMetaData.PROGRAMMER_NAME));
//得到age的对应索引和值
int age=cursor.getInt(cursor.getColumnIndex
(TableMetaData.PROGRAMMER_AGE));
//得到level的对应索引和值
int level=cursor.getInt(cursor.getColumnIndex
(TableMetaData.PROGRAMMER_LEVEL));
//得到info的对应索引和值
String info=cursor.getString(cursor.getColumnIndex
(TableMetaData.PROGRAMMER_INFO));
programmer.set_id(_id);
programmer.setName(name);
programmer.setAge(age);
programmer.setLevel(level);
programmer.setInfo(info);
}
if(programmer==null)
Log.i(TAG,"单个查询结果为空!");
return programmer;
}
}
5.SQLMetaData
/**定义一些常用的量*/
public class SQLMetaData {
//数据库名
public static final String DATABASE_NAME="Programmer_dlc.db";
//版本号
public static final int DATABASE_VERSION=1;
//表名,一下是所有需要用到的表的名字
public static final String P1_TABLE_NAME="ProgrammerTable";
/**内部类,封装关于表的字段信息,实现BaseColumns接口
* 开发人员不必在定义字段_ID和_Count了(因为实现了BaseColumns)
* static声明--只属于类而不是属于对象
* */
public static final class TableMetaData implements BaseColumns{
//某一个表中的所有属性的定义
public static final String _ID="_id";//表中的主键
public static final String PROGRAMMER_NAME="name";
public static final String PROGRAMMER_AGE="age";
public static final String PROGRAMMER_LEVEL="level";
public static final String PROGRAMMER_INFO="info";
//DESC(降序),ASC(升序),这句话的意思为按ID升序
public static final String DEFAULT_SORT_ORDER=_ID+" ASC";
}
}
6.SqlDemoActivity
/**测试数据库操作的Activity*/
public class SqlDemoActivity extends Activity implements OnClickListener{
private static final String TAG="SqlDemoActivity";
//数据库操作对象
SQLOperateEntity sqlOperateEntity;
private Button btn_insert;
private Button btn_delete;
private Button btn_query;
private EditText edt_id;
private EditText edt_name;
private EditText edt_age;
private EditText edt_level;
private EditText edt_info;
private ListView listViewContent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sqldemo_view);
init();
}
/**功能函数*/
private void init()
{
sqlOperateEntity=new SQLOperateEntity(this);
bindWidgets();
setListeners();
}
private void bindWidgets()
{
Log.i(TAG,"Widget绑定");
edt_id=(EditText) findViewById(R.id.edt_id);
edt_name=(EditText) findViewById(R.id.edt_name);
edt_age=(EditText) findViewById(R.id.edt_age);
edt_level=(EditText) findViewById(R.id.edt_level);
edt_info=(EditText) findViewById(R.id.edt_info);
btn_insert=(Button) findViewById(R.id.btn_insert);
btn_delete=(Button) findViewById(R.id.btn_delete);
btn_query=(Button) findViewById(R.id.btn_query);
listViewContent=(ListView) findViewById(R.id.list_content);
}
private void setListeners()
{
Log.i(TAG,"设置监听函数");
btn_insert.setOnClickListener(this);
btn_delete.setOnClickListener(this);
btn_query.setOnClickListener(this);
}
/**插入*/
private void onInsert(Programmer p)
{
Log.i(TAG,"开始插入数据");
if(p.get_id()==-1&&p.getAge()==-1&&p.getLevel()==-1)//发现为默认数据时
{
Log.w(TAG,"没有输入数据,插入无效!");
}
else
{
sqlOperateEntity.add(p);
}
}
/**删除*/
private void onDelete(int _id)
{
Log.i(TAG,"开始删除记录");
sqlOperateEntity.delete(_id);
}
/**查询*/
private List onQuery(int _id)
{
List promrammers=new ArrayList();
if(_id==-1)//默认为-1,代表查询全部
{
Log.i(TAG,"开始查询全部数据!");
promrammers=sqlOperateEntity.find();
}
else
{
Log.i(TAG,"开始查询单条数据!");
Programmer p;
p=sqlOperateEntity.fingById(_id);
if(p!=null)
promrammers.add(p);
else
Log.w(TAG,"没有查询到数据!");
}
return promrammers;
}
/**这里用到集合类的组合
* ArrayList>
* */
/***/
private void onRefreshView(List programmers)
{
if(!programmers.isEmpty())
{
Log.i(TAG,"开始刷新查询数据!");
}
else
{
Log.i(TAG,"空数据不能刷新查询!");
}
List> items = onFillMaps(programmers); //查询添加到列表
ListAdapter listAdapter = new SimpleAdapter(
this,items,R.layout.list,
new String[]{"_id","name","age","level","info"},
new int[]{R.id.list_id,R.id.list_name,
R.id.list_age,R.id.list_level,R.id.list_info});
listViewContent.setAdapter(listAdapter);
}
/**刷新*/private List> onFillMaps(List programmers)
{
Log.i(TAG,"正在刷新查询数据!");
List> items=new ArrayList>();
//循环
for(Programmer p:programmers)
{
HashMap map=new HashMap();
map.put("_id",String.valueOf(p.get_id()));
map.put("name", p.getName());
map.put("age",String.valueOf(p.getAge()));
map.put("level",String.valueOf(p.getLevel()));
map.put("info", p.getInfo());
items.add(map);
}
return items;
}
@Override
public void onClick(View v) {
int _id=-1;
String name="";
int age=-1;
int level=-1;
String info="";
try {
_id=Integer.parseInt(edt_id.getText().toString().trim());
name=edt_name.getText().toString().trim();
age=Integer.parseInt(edt_age.getText().toString().trim());
level=Integer.parseInt(edt_level.getText().toString().trim());
info=edt_info.getText().toString().trim();
} catch (NumberFormatException e) {
Log.i(TAG,"得到editText数据时出错!"+e.getMessage());
}
Programmer p=new Programmer(_id,name,age,level,info);
switch(v.getId())
{
case R.id.btn_insert:
onInsert(p);
onRefreshView(onQuery(_id));
break;
case R.id.btn_delete:
onDelete(_id);
onRefreshView(onQuery(_id));
break;
case R.id.btn_query:
onRefreshView(onQuery(_id));
break;
default:
break;
}
}
}
效果图1:(查询单条记录,程序里面填写好相应的ID)
效果图2:(查询全部记录,不填ID)
完整工程:http://download.csdn.net/detail/u010979495/8088497