Android数据库编程

小朋友,你是不是有很多问号???

数据库编程

一、SQLite数据库简介

  • SQLite是一个轻量级数据库,第一个版本诞生于2000年5月。它最初是为嵌入式设计的,占用资源非常低,在内存中只需要占用几百KB的存储空间。 My sql structure query language
  • SQLite是遵守ACID关联式的数据库管理系统。ACID是指数据库事务正确执行的基本要素,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。
  • SQLite没有服务器进程,它通过文件保存数据,该文件是跨平台的,可以放在其他平台中使用。并且支持 NULL、INTEGER、REAL(浮点数字)、TEXT(字符串文本)和BLOB(二进制对象)五种数据类型。

1、相关sql语句

//增删改查
insert into info (name,phone) values ("王五","138");
update info set phone="13856675089" where name = "王五";
delete from info where name ="王五";
select name,phone from info;
//创建一个表
create table info2(
     _id int primary key ,
     name varchar(20)
     );
//id一般为_d,自增创建表格
db.execSQL("create table info(_id integer primary key autoincrement,name varchar(20))");
//修改表格
db.execSQL("alter table info add phone varchar(20)");

2、什么时候使用数据库

有大量相似结构的数据需要存储的时候

id 一般为写为_id

这些类型在底层都是String,不区分数据类型,但是写sql还是要按照标准的sql语句写

二、创建数据库,并对其操作

1、创建一个类继承抽象类SQLiteOpenHelper

实现其中的三个方法

/**
* context 上下文 
* name:数据库的名字 
* factory:创建cursor(光标,指针)对象 ,相当于Resultset(结果集)
 * version:数据库的版本 从1开始,只能变大,不能变小
 */
1、 实现其构造方法
 super(context, "ZQ.db", null, 4);
2、onCreate方法,用于创建数据库		//当数据库第一次被创建的时候被调用 这个方法特别适合做表结构的初始化 创建表就是写sql语句
3、onUpgrade方法,用于数据库版本的更新		//当数据库版本升级的时候调用,这个方法适合做表结构的更新
4、使用SQLite Expert这个工具可以打开我们创建的数据库

2、使用sql语句对数据库进行增删改查

缺点:sql语句容易写错

​ 执行sql语句没有返回值,不容易进行判断 void

优点:容易多表查询

	private void insert() {
		// 获取数据库对象
		SQLiteDatabase writableDatabase = myOpenHelpernew.getWritableDatabase();
		// 执行insert的sql语句
        //有两种execSQL方法
		writableDatabase.execSQL("insert into info (name,phone) values (?,?)",
				new Object[] { "张三", "13856676089" });
		// 数据库用完需要关闭
		writableDatabase.close();
		Toast.makeText(getApplicationContext(), "插入成功", 0).show();
	}

	private void delete() {
		// 获取数据库对象
		SQLiteDatabase writableDatabase = myOpenHelpernew.getWritableDatabase();
		// 执行delete的sql语句
		writableDatabase.execSQL("delete from info where name =?",
				new Object[] { "张三" });
		// 数据库用完需要关闭
		writableDatabase.close();
		Toast.makeText(getApplicationContext(), "删除成功", 0).show();
	}

	private void update() {
		// 获取数据库对象
		SQLiteDatabase writableDatabase = myOpenHelpernew.getWritableDatabase();
		// 执行update的sql语句
		writableDatabase.execSQL("update info set phone=? where name = ?",
				new Object[] { "110", "张三" });
		// 数据库用完需要关闭
		writableDatabase.close();
		Toast.makeText(getApplicationContext(), "更新成功", 0).show();
	}

	private void select() {
		// 获取数据库对象
		SQLiteDatabase writableDatabase = myOpenHelpernew.getWritableDatabase();
		// 执行select的sql语句
		// 返回类型cursor(Resultset)
		Cursor cursor = writableDatabase.rawQuery("select * from info", null);
		if (cursor != null && cursor.getCount() > 0) {
			while(cursor.moveToNext()){
			// columnIndex代表列的索引
			int id = cursor.getInt(0);
			String name = cursor.getString(1);
			String phone = cursor.getString(2);
			System.out.println("id="+id+" name="+name+" phone="+phone);
			}	
		}
		// 数据库用完需要关闭
		writableDatabase.close();
	}

//创建或者打开数据库,如果是第一次就是创建
getWritableDatabase
//创建或者打开数据库,如果是第一次就是创建 如果磁盘满了,返回只读的对象
getReadableDatabase

Cursor接口是一个游标接口,在数据库操作中作为返回值,相当于结果集ResultSet。

3、sqlite3工具

  • 说明:sqlite3.exe是一个简单的SQLite数据库管理工具,位于Android ADT Eclipse中的sdk/tools目录下。
  • 在Windows的cmd中(如果配置了环境变量,直接就可以adb shell就可进入root@android:/ #模式;如果事先没有配置环境变量,则需C:\adt-bundle-windows-x86_64-20140702\sdk\platform-tools>adb shell)
//改变dos编码方式
1、chcp	936		//GBK
2、chcp	65001	//utf-8

C:\Users\赵启>adb shell
root@android:/ # cd /data/data/com.example.sqlite/databases
cd /data/data/com.example.sqlite/databases
root@android:/data/data/com.example.sqlite/databases # ls
ls
ZQ.db
ZQ.db-journal
root@android:/data/data/com.example.sqlite/databases # sqlite3 ZQ.db
sqlite3 ZQ.db
SQLite version 3.7.11 2012-03-20 11:35:50
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> select * from info;
select * from info;
138|寮犱笁|13856676089		//乱码了,因为默认编码方式是GBK
139|寮犱笁|13856676089

//将dos编码方式改为utf-8
C:\Users\赵启>chcp 65001
Active code page: 65001
.
.
.
sqlite> select * from info;
select * from info;
138|张三|13856676089
139|张三|13856676089

三、使用谷歌封装好的API进行增删改查

优点:写法简单,不需要写复杂的sql语句,不容易写错

​ 有返回值,方便开发者进行开发

缺点:如果有多张表,使用谷歌封装的API不容易进行查询

private void insert() {
		// 获取数据库对象
		SQLiteDatabase writableDatabase = myOpenHelpernew.getWritableDatabase();
		/**
		 * table:表名
		 * nullColumnHack:可以为空
		 * ContentValues:内部封装了一个map;key:列名,values:值
		 */
		ContentValues values = new ContentValues();
		values.put("name", "王五");
		values.put("phone", "119");
		//返回值代表插入新行的id
		long insert = writableDatabase.insert("info", null, values);//底层在组拼sql语句
		writableDatabase.close();
		if(insert>0){
			Toast.makeText(getApplicationContext(), "添加成功", 0).show();
		}else{
			Toast.makeText(getApplicationContext(), "添加失败", 0).show();
		}
	}

	private void delete() {
		// 获取数据库对象
		SQLiteDatabase writableDatabase = myOpenHelpernew.getWritableDatabase();
		/**
		 * whereClause:删除的条件
		 * whereArgs:内容,为String数组
		 */
		//返回值为受影响的行数
		int delete = writableDatabase.delete("info", "name=?", new String[]{"王五"});
		writableDatabase.close();	
		Toast.makeText(getApplicationContext(), "删除了"+delete+"行", 0).show();
	}

	private void update() {
		// 获取数据库对象
		SQLiteDatabase writableDatabase = myOpenHelpernew.getWritableDatabase();
	     ContentValues values = new ContentValues();
	     values.put("phone", "120");
		int update = writableDatabase.update("info", values, "name=?", new String[]{"王五"});
		writableDatabase.close();
		Toast.makeText(getApplicationContext(), "更新了"+update+"行", 0).show();
	}

	private void select() {
		// 获取数据库对象
		SQLiteDatabase writableDatabase = myOpenHelpernew.getWritableDatabase();
		/**
		 * columns:需要查询哪些列,为String数组,可以new String[]{"name","phone"},null代表查询所有
		 * selection:查询的条件
		 * selectionArgs:查询条件的具体内容
		 * groupBy:分组
		 * having:过滤条件
		 * orderBy:排序
		 */
		Cursor cursor = writableDatabase.query("info", null, "name=?", new String[]{"王五"}, null, null, null);
		if (cursor != null && cursor.getCount() > 0) {
			while(cursor.moveToNext()){
			// columnIndex代表列的索引
			int id = cursor.getInt(0);
			String name = cursor.getString(1);
			String phone = cursor.getString(2);
			// 把数据封装到javabean中
				Info info = new Info();
				info.setId(id);
				info.setName(name);
				info.setPhone(phone);
				// 把javabean对象加入到集合
				lists.add(info);
			}	
            //设置数据适配器
			lv.setAdapter(new myListAdapter());
		}
		writableDatabase.close();
	}

四、数据库的事务介绍

db.beginTransaction();//开启事务
   try {//写具体的逻辑
     ...
     //给当前事务设置一个成功的标记,失败则回滚
     db.setTransactionSuccessful();
   } catch(Exception e){
			Toast.makeText(getApplicationContext(), "服务器忙,请稍后再试", 0).show();
   } finally {
     db.endTransaction();//关闭事务
   }

五、ListView

1、ListView入门

1.1在布局定义ListView

    <ListView
        android:id="@+id/lv"
        android:layout_width="match_parent"		//均需填充框体
        android:layout_height="match_parent"	//均需填充框体,如果为包裹内容,listview会做多次的校验,降低效率。
        android:fastScrollEnabled="true" >		//滚动条
    </ListView>

1.2定义ListView的数据适配器

// 显示数据 和其他控件有点区别,数据来源于ListAdapter(接口)
		lv.setAdapter(new myListAdapter());
// 定义listView数据适配器,其中BaseAdapter interface ListAdapter
	public class myListAdapter extends BaseAdapter {
	
	}

1.3实现BaseAdapter的getCount和getView方法

// 一共有多少条数据需要展示
		public int getCount() {
			// TODO Auto-generated method stub
			return 15;
		}
		/**
		 * 获取一个view 用来显示listView的数据,会作为listView的一个条目出现 
		 * convertView 历史缓存对象
		 */
		public View getView(int position, View convertView, ViewGroup parent) {
			TextView tv;
			if (convertView == null) {
				// 创建新的缓存对象
				tv = new TextView(getApplicationContext());
			} else {
				//复用历史缓存对象
				tv = (TextView) convertView;
			}
			return tv;
		}
	}

2、ListView显示数据的原理

mvc

  • javaweb

    m:mode数据

    v:view视图 jsp

    c:controller servlet

  • Android

    m:mode数据(javabean)

    v:view listview

    c:adapter

3、打气筒inflate

线性布局,相对布局都继承于ViewGroup,可以有自己的孩子

通过一个打气筒inflate,可以把一个布局转换成一个view对象

public View getView(int position, View convertView, ViewGroup parent) {
			// 想办法将自己的布局转换成一个view对象就可以了
			View view;
			if (convertView == null) {
				// 创建新的布局对象 可以通过打气筒把一个布局资源转换为一个view对象
				// resource 就是我们定义的布局文件
				// root 把view加到ViewGroup里
				/**
				 * 获取打气筒服务常用的三种方法
				 */
				//1、获取打气筒服务
				view = View.inflate(getApplicationContext(),
						R.layout.activity_item, null);
                
				//2、获取打气筒服务
//				  view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.activity_item, null);
				
				//3、获取打气筒服务(此方法为Google工程师使用)
//				LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
//				view = inflater.inflate(R.layout.activity_item, null);
			} else {
				// 复用历史缓存对象
				view = convertView;
			}
			return view;
		}
	}

4、数组适配器ArrayAdapter

//也可以是列表
String objects[] = { "张三", "李四", "王五", "花花", "草草" };

// 创建一个ArrayAdapter
		// 有多种方法
		// ArrayAdapter<String> adapter = new ArrayAdapter<String>(
		// getApplicationContext(), R.layout.activity_item1, objects);
		/**
		 * 第三个参数textViewResourceId :必须是textView的id
		 */
		ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
				R.layout.activity_item2, R.id.item2, objects);

5、SimpleAdapter

// 准备listview要显示的数据data
		List<Map<String, String>> data = new ArrayList<Map<String, String>>();
		Map<String, String> map1 = new HashMap<String, String>();
		map1.put("name", "张飞");
		map1.put("phone", "110");
// 把map加入集合中
		data.add(map1);
// 创建一个SimpleAdapter
		/**
		 * 第二个参数data:List<Map<String, String>> 
		 * 第四个参数from:map集合的key 
		 * 第五个参数to:需要显示在哪个控件上的id
		 */
		SimpleAdapter adapter = new SimpleAdapter(this, data,
				R.layout.activity_item, new String[] { "name", "phone" },
				new int[] { R.id.tv_name, R.id.tv_phone });

6、查出数据库的内容然后显示到ListView上

//Info:javabean,用来封装数据
List<Info> lists = new ArrayList<Info>();	
//查出数据库的内容
private void select() {
		// 获取数据库对象
		SQLiteDatabase writableDatabase = myOpenHelpernew.getWritableDatabase();

		Cursor cursor = writableDatabase.query("info", null, null, null, null,
				null, null);//表示查询所有数据
		if (cursor != null && cursor.getCount() > 0) {
			while (cursor.moveToNext()) {
				// columnIndex代表列的索引
				String id = cursor.getString(0);
				String name = cursor.getString(1);
				String phone = cursor.getString(2);
				// 把数据封装到javabean中
				Info info = new Info();
				info.setId(id);
				info.setName(name);
				info.setPhone(phone);
				// 把javabean对象加入到集合
				lists.add(info);
			}
			//设置数据适配器
			lv.setAdapter(new myListAdapter());
		}
		writableDatabase.close();
	}
//把数据显示到ListView上
public View getView(int position, View convertView, ViewGroup parent) {
			// 想办法将自己的布局转换成一个view对象就可以了
			View view;
			if (convertView == null) {
				// 获取打气筒服务
				view = View.inflate(getApplicationContext(),
						R.layout.activity_item, null);
			} else {
				// 复用历史缓存对象
				view = convertView;
			}
//			找到控件用来显示数据,小技巧:view.
			TextView tv_id = (TextView) view.findViewById(R.id.tv_id);
			TextView tv_name = (TextView) view.findViewById(R.id.tv_name);
			TextView tv_phone = (TextView) view.findViewById(R.id.tv_phone);
			
//			如何显示数据
			Info info = lists.get(position);
			tv_id.setText(info.getId());
			tv_name.setText(info.getName());
			tv_phone.setText(info.getPhone());

			return view;
		}
	}

7、补充

弹出一个对话框

// 弹出一个对话框的方法
			private void showmyDialog(final int position, final Product info) {
				// 弹出一个对话框
				AlertDialog.Builder builder = new Builder(MainActivity.this);
				builder.setTitle("是否确定删除该条目");
				builder.setPositiveButton("确定",
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog,
									int which) {
								// 把选中的条目从集合中删除
								lists.remove(position);
								// 把当前这个条目从数据库中删除
								productDao.delete(info.getId());
								// 更新一下ui
								notifyDataSetChanged();
							}

						});
				builder.setNegativeButton("取消",
						new DialogInterface.OnClickListener() {

							public void onClick(DialogInterface dialog,
									int which) {
								// TODO Auto-generated method stub
							}
						});
				// 对话框一定要记得show出来
				builder.show();
			}

@CopyRight名侦探柯小启

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章