2010.10.30———Android 03


内容一
*******************************
SQLite 数据操作
*******************************

name varchar(20)

name 定义的20长度的字符串
这在SQLite里面是无效的 只是为了阅读方便
SQLite依然可以存放大于20的数据,并且不一定为字符串

SQLite的分页

分页和mysql类似 获取5条记录 跳过前面3条记录

select * from Account limit 5 offset 3 或者select * from Acount limit 3,5


SQLite应用:

1、用户第一次使用应用时 创建数据库

写一个类继承SQLiteOpenHelper抽象类
写完后 就会报错 提示必须显示的调用父类的构造方法

此类有三个重要的方法


A:构造方法
public OpenDBHelper(Context context, String name, CursorFactory factory,int version){supert(context,"lp.db",null,1);}第一个参数 上下文对象第二个参数 是数据库 因为SQLite是通过文件存储的 最好定义一个后缀 以便以后查看第三个参数 是游标工厂 一般设为null 用系统自带的游标工厂 对结果集进行数据访问的第四个参数 版本号 为现在所创建的数据库定义版本号 不能取0 建议>0 这个版本号发生变化时 会触发Upgrade()事件


B:onCreate()

此方法只会被调用一次 仅仅在表被创建时 调用
如果数据库文件已经存在 此方法就不会被调用

因为前面构造方法里面仅仅是创造了数据库
所以 此方法一般用来创建表和初始化数据
public void onCreate(SQLiteDatabase db){String sql = "CREATE TABLE person (personid integer primary key autoincrement, name varchar(20))";db.execSQL(sql)}


这样 当调用这个方法时 就可以创建一张表了

execSSL() 用来执行有修改行为的sql语句 不能执行查询语句

假如说 我们创建了OpenDBHelper extends SQLiteOpenHelper
那么 我们创建数据库 时
OpenDBHelper  db = new OpenDBHelper(this.getContext());

当调用
db.getWritableDatabase();

这个方法时 就已经创建了数据库和表 并且存放在/data/dat/包应用名/databases/lp.db


C:Upgrade()

当调用
db.getWritableDatabase();


如果发现数据库的版本号版本号不一致 就会调用次方法

一般用来更改数据库文件的表结构

首先,要更改构造方法的版本号
然后,更改表结构 添加列
public void onUpgrade(SQLiteDatabase db ,int oldVersion,int newVersion){String sql = "ALTER TABLE person ADD phone VARCHAR(12) NULL ";db.execSQL(sql);}




2、增删改查

这四个操作都需要SQLiteDatabase对象


增删改 一般使用
db.getWritableDatabase();
来获得SQLiteDatabase对象

db.execSQL(sql)
调用这个方法 传入sql语句就可以了

查 使用

db.getReadableDatabase();
来获得SQLiteDatabase对象

其实 getReadableDatabase方法是可以执行增删改的 因为 它内部会尝试去返回一个getWritableDatabase

Cursor cursor = SQLiteDatabase.rawQuery(sql,参数数组);//第一个参数是sql 有占位符//第二个参数数组是对占位符进行赋值//返回游标对象 返回时游标对象指向结果集第一条记录的上面//当根据主键查时 可以用moveToFirst方法//因为结果集只有0个或者1个记录//当没有值时 会返回falseif(cursor.moveToFirst()){//一系列方法//这些方法需要参数是:索引值//所以要通过cursor.getColumnIndex("id")来获得属性的索引值cursor.getInt(cursor.getColumnIndex("id"));cursor.getString();...}//游标一旦关闭 结果集就不能访问了 cursor.close();//当结果集是一个list时 //用moveToNext来遍历结果集while(cursor.moveToNext()){...}

除了自己用sql语句来完成增删改查之外 还可以用Android提供的方法
//ContentValues和map类似ContentValues values = new ContentValues()values.put("name",name);values.put("phone",phone);//第一个参数是表名//第三个参数是值SQLiteDatabase.insert("person",null,values);


注意 :调用insert必须添加一条记录
即使values为null 它也会向数据库插入一条数据

而第二个参数 就是为了这种情况存在的 空值字段
当第三个参数为null是
insert int person(name,phone) values(null)
这种sql语句是错误的 因为只有一个value值

第三个参数 就是你要赋予空值的字段 当且仅当values为null时
SQLiteDatabase.insert("person","name",values);
当values为null时,sql语句就是
insert int person(name) values(null)

3、事务

public void pay(){SQLiteDatabase db = dbHelper.getWritableDatabase();//开启事务db.beginTransaction();db.execSQL("update person set amount=amount-10 where personid = 1");db.execSQL("update person set amount=amount-10 where personid = 2");//默认是回滚db.endTransaction();//结束事务时 是提交还是回滚 由事务的标志来决定 true 就提交 否则 回滚 默认 标志位false 即回滚}


要想提交事务 必须调用

db.setTransactionSuccessful();

在结束事务前


内容二
***********************************
ListView控件显示列表
***********************************



适配器 实现数据的绑定 把数据绑定到指定的界面上

SimpleAdapter adapter = new SimpleAdapter(context,List<Map<String,Object>>,layoutId,数据key数组,组建id数组)


第一个参数 是一个上下文对象
第二个参数 是需要绑定的数据 必须是一个List,list里面是Map对象 并且map对象的key为String
第三个参数 是要绑定的资源文件的id 就是说是绑定到那个布局xml文件 注意新建的布局xml 名字必须为a-z 0-9不能为大写 这个是android规定的
后面两个参数 是数据里的map中的key与布局文件里面组件id的一一对应
第三个参数 貌似对应的是数据库里面的名字

listView.setAdapter(adapter);listView.setOnItemClickListener(new OnItemClickListener(){public void OnItemClickListen(AdapterView<?> parent,View view,int position,long id){ListView lv = (ListView)parent;Map<String,Object> map = (HashMap<String,Object>)lv.getItemAtPosition(position);Toast.makeText(MianActivity.this, "所点击的姓名: "+map.get("name").toString(), 1).show();}});parent:当前被点击的条目的listView对象view:代表当前条目对应的view对象 就是ListView控件最外层的那个LinearLayout 当然 它里面还是有一些子控件的position: 条目所绑定的数据在数据集合中的位置id: 条目所绑定的组件在view所处的位置

当然 我们可以不用上面的适配器

SimpleCursorAdapter adapter = new SimpleCursorAdapter(context,layoutId,Cursor,from,to);listView.setAdapter(adapter);

这个适配器 不要list 需要一个游标对象 这个也很方便 因为我们查询数据的时候 就是对Cursor对象进行解析 然后返回了list
这样我们就可以不去处理Cursor对象了
但是 当你运行时 总是会报一个 ***"_id"列不存在*** 的错误

这个原因是Android默认采用_id作为每一个表的主键

所以 解决办法 有两种
1、主键以后就设为_id
2、sql取别名来处理


内容三
*********************************
内容提供者 ContentProvider
********************************

ContentProvider 在android中的作用是对外共享数据,
也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,
其他应用可以通过ContentProvider 对你应用中的数据进行添删改查。

如果采用文件操作模式对外共享数据,数据的访问方式会因数据存储的方式而不同,导致数据的访问方式无法统一,
如:采用xml文件对外共享数据,需要进行xml解析才能读取数据;
采用sharedpreferences共享数据,需要使用sharedpreferences API读取数据。

使用ContentProvider对外共享数据的好处是统一了数据的访问方式。

ContentProvider应用:

1、建的类必须继承ContentProvider类

2、因为ContentProvider和Activity一样是组件
所以需要在清单文件中进行配置

在Application下面

<provider android:name=".PersonContentProvider" android:authorities="lp.providers.XXXXprovider"/>


android:authorities 唯一标识
ContentProvider 采用了authorities(主机名/域名)对它进行唯一标识,
你可以把 ContentProvider看作是一个网站 authorities 就是他的域名
为了能让其他应用找到该ContentProvider

3、当你继承ContentProvider类后 会有几个方法可以实现

onCreate()query()insert()delete()update()


getType() 返回目前操作的数据的MIME类型 类似于 text/plain等

如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头,
例如:要得到所有person记录的Uri为content://cn.itcast.provider.personprovider/person,
那么返回的MIME类型字符串应该为:“vnd.android.cursor.dir/person”。
如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头,
例如:得到id为10的person记录,Uri为content://cn.itcast.provider.personprovider/person/10,
那么返回的MIME类型字符串应该为:“vnd.android.cursor.item/person”。

4、然后我们可以在其他应用中来访问这个ContentProvider

测试:
我们新建一个other工程 在里面建一个测试类 来访问一下 试试


怎样访问ContentProvider

ContentResolver resolver = this.getContext().getContentResolver();//  "content://" 代表是ContentProvider 这个scheme已经由Android规定了 只要访问ContentProvider 就必须以此开头//后面跟唯一标识 authoritiesUri uri = Uri.parse("content://lp.providers.XXXXprovider/path");//调用ContentResolver的insert方法resolver.insert(uri,ContentValues);


path:用来表示我们要操作的数据,路径的构建应根据业务而定,如下:要操作person表中id为10的记录,可以构建这样的路径:/person/10要操作person表中id为10的记录的name字段, person/10/name要操作person表中的所有记录,可以构建这样的路径:/person要操作xxx表中的记录,可以构建这样的路径:/xxx当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下:要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name



内容四
*****************************************
监听ContentProvider数据的改变
*****************************************

如果有两个应用 都在访问ContentProvider
A改变了ContentResolver的数据,
那么 B如何能马上获知呢?
这时 我们就需要在B应用里面监听ContentProvider数据的变化
同时 ContentProvider要发出数据变化的通知


1、ContentProvider要发出数据变化的通知

在ContentProvider的insert语句中添加:
getContext().getContextResolver().notifyChange(uri, null);

2、B应用监听ContentProvider数据

Uri uri = Uri.parse("content://lp.providers.PersonContentProvider/person");        //B应用监听ContentProvider数据 注册一个监听器        //当监听到这个uri的数据发生变化时 就出发ContentObserver的onChanger()方法        this.getContentResolver().registerContentObserver(uri, true, new ContentObserver(new Handler()){        //我们通过这个方法 找到最新插入的那条记录@Overridepublic void onChange(boolean selfChange) {ContentResolver contentResolver = MainActivity.this.getContentResolver();Uri uri = Uri.parse("content://lp.providers.PersonContentProvider/person");//我们可以在onChange方法里面 查找ContentProvider的所有数据,//然后排序得到id最大的一条数据 就是刚插进去的数据 //select * from person order by personid desc limit 1;Cursor cursor = contentResolver.query(uri, null, null, null, "personid desc limit 1");while(cursor.moveToNext()){Log.i(TAG, cursor.getString(cursor.getColumnIndex("name")));Toast.makeText(MainActivity.this, "刚插入的数据姓名为:"+cursor.getString(cursor.getColumnIndex("name")), 1);}}                });


























更多相关文章

  1. Android实现button居中的方法
  2. Android(安卓),,Menu
  3. Mars视频笔记——ExpandableListActivity
  4. Android判断WIFI是否打开的方法
  5. 浅谈Java中Collections.sort对List排序的两种方法
  6. mybatisplus的坑 insert标签insert into select无参数问题的解决
  7. python起点网月票榜字体反爬案例
  8. Python技巧匿名函数、回调函数和高阶函数
  9. Python list sort方法的具体使用

随机推荐

  1. Eclipse android 项目转android studio填
  2. Android中App可分配内存的大小
  3. android The project target (Android 2.
  4. Android XML布局文件优化
  5. Android WebView中javascript和java的互
  6. usbmanger android 底下USB的工作模式
  7. Android 颜色和颜色透明度列表
  8. 第四章 Android开发三大基石—Activity、
  9. Android Touch 触摸事件
  10. android 播放rtsp协议流媒体