1、使用嵌入式关系型SQLite数据库存储数据

Android平台上,集成了一个嵌入式关系型数据库—SQLiteSQLite3支持NULLINTEGERREAL(浮点数字)、TEXT(字符串文本)BLOB(二进制对象)数据类型,虽然它支持的类型只有五种,但实际上sqlite3也接受varchar(n)char(n)decimal(p,s)等数据类型,只不过在运算或保存时会转成对应的五种数据类型。SQLite最大的特点是你可以把各种类型的数据保存到任何字段中,而不用关心字段声明的数据类型是什么。例如:可以在Integer类型的字段中存放字符串,或者在布尔型字段中存放浮点数,或者在字符型字段中存放日期型值。但有一种情况例外:定义为INTEGERPRIMARYKEY的字段只能存储64位整数,当向这种字段保存除整数以外的数据时,将会产生错误。另外,SQLite在解析CREATETABLE语句时,会忽略CREATETABLE语句中跟在字段名后面的数据类型信息,如下面语句会忽略name字段的类型信息:

CREATETABLEperson(personidintegerprimarykeyautoincrement,namevarchar(20))

SQLite可以解析大部分标准SQL语句,如:

查询语句:select*from表名where条件子句groupby分组字句having...orderby排序子句

如:select*fromperson

select*frompersonorderbyiddesc

selectnamefrompersongroupbynamehavingcount(*)>1

分页SQLmysql类似,下面SQL语句获取5条记录,跳过前面3条记录

select*fromAccountlimit5offset3或者select*fromAccountlimit3,5

插入语句:insertinto表名(字段列表)values(值列表)。如:insertintoperson(name,age)values(‘传智’,3)

更新语句:update表名set字段名=where条件子句。如:updatepersonsetname=‘传智‘whereid=10

删除语句:deletefrom表名where条件子句。如:deletefrompersonwhereid=10

2、使用SQLiteOpenHelper对数据库进行版本管理

我们在编写数据库应用软件时,需要考虑这样的问题:因为我们开发的软件可能会安装在很多用户的手机上,如果应用使用到了SQLite数据库,我们必须在用户初次使用软件时创建出应用使用到的数据库表结构及添加一些初始化记录,另外在软件升级的时候,也需要对数据表结构进行更新。那么,我们如何才能实现在用户初次使用或升级软件时自动在用户的手机上创建出应用需要的数据库表呢?总不能让我们在每个需要安装此软件的手机上通过手工方式创建数据库表吧?因为这种需求是每个数据库应用都要面临的,所以在Android系统,为我们提供了一个名为SQLiteOpenHelper的抽象类,必须继承它才能使用,它是通过对数据库版本进行管理来实现前面提出的需求。

为了实现对数据库版本进行管理,SQLiteOpenHelper类提供了两个重要的方法,分别是onCreate(SQLiteDatabasedb)onUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion),前者用于初次使用软件时生成数据库表,后者用于升级软件时更新数据库表结构。当调用SQLiteOpenHelpergetWritableDatabase()或者getReadableDatabase()方法获取用于操作数据库的SQLiteDatabase实例的时候,如果数据库不存在,Android系统会自动生成一个数据库,接着调用onCreate()方法,onCreate()方法在初次生成数据库时才会被调用,onCreate()方法里可以生成数据库表结构及添加一些应用使用到的初始化数据。onUpgrade()方法在数据库的版本发生变化时会被调用,一般在软件升级时才需改变版本号,而数据库的版本是由程序员控制的,假设数据库现在的版本是1,由于业务的变更,修改了数据库表结构,这时候就需要升级软件,升级软件时希望更新用户手机里的数据库表结构,为了实现这一目的,可以把原来的数据库版本设置为2(有同学问设置为3行不行?当然可以,如果你愿意,设置为100也行),并且在onUpgrade()方法里面实现表结构的更新。当软件的版本升级次数比较多,这时在onUpgrade()方法里面可以根据原版号和目标版本号进行判断,然后作出相应的表结构及数据更新。

getWritableDatabase()getReadableDatabase()方法都可以获取一个用于操作数据库的SQLiteDatabase实例。但getWritableDatabase()方法以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘若使用getWritableDatabase()打开数据库就会出错。getReadableDatabase()方法先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。

publicclassDatabaseHelperextendsSQLiteOpenHelper{

//类没有实例化,是不能用作父类构造器的参数,必须声明为静态

privatestaticfinalStringname="itcast";//数据库名称

privatestaticfinalintversion=1;//数据库版本

publicDatabaseHelper(Contextcontext){

//第三个参数CursorFactory指定在执行查询时获得一个游标实例的工厂类,设置为null,代表使用系统默认的工厂类

super(context,name,null,version);

}

@OverridepublicvoidonCreate(SQLiteDatabasedb){

db.execSQL("CREATETABLEIFNOTEXISTSperson(personidintegerprimarykeyautoincrement,namevarchar(20),ageINTEGER)");

}

@OverridepublicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){

db.execSQL("ALTERTABLEpersonADDphoneVARCHAR(12)NULL");//往表中增加一列

//DROPTABLEIFEXISTSperson删除表

}

}

在实际项目开发中,当数据库表结构发生更新时,应该避免用户存放于数据库中的数据丢失。

3、使用SQLiteDatabase操作SQLite数据库

Android提供了一个名为SQLiteDatabase的类,该类封装了一些操作数据库的API,使用该类可以完成对数据进行添加(Create)、查询(Retrieve)、更新(Update)和删除(Delete)操作(这些操作简称为CRUD)。对SQLiteDatabase的学习,我们应该重点掌握execSQL()rawQuery()方法。execSQL()方法可以执行insertdeleteupdateCREATETABLE之类有更改行为的SQL语句;rawQuery()方法用于执行select语句。

execSQL()方法的使用例子:

SQLiteDatabasedb=....;

db.execSQL("insertintoperson(name,age)values('传智播客',4)");

db.close();

执行上面SQL语句会往person表中添加进一条记录,在实际应用中,语句中的“传智播客”这些参数值会由用户输入界面提供,如果把用户输入的内容原样组拼到上面的insert语句,当用户输入的内容含有单引号时,组拼出来的SQL语句就会存在语法错误。要解决这个问题需要对单引号进行转义,也就是把单引号转换成两个单引号。有些时候用户往往还会输入像“&”这些特殊SQL符号,为保证组拼好的SQL语句语法正确,必须对SQL语句中的这些特殊SQL符号都进行转义,显然,对每条SQL语句都做这样的处理工作是比较烦琐的。SQLiteDatabase类提供了一个重载后的execSQL(Stringsql,Object[]bindArgs)方法,使用这个方法可以解决前面提到的问题,因为这个方法支持使用占位符参数(?)使用例子如下:

SQLiteDatabasedb=....;

db.execSQL("insertintoperson(name,age)values(?,?)",newObject[]{"传智播客",4});

db.close();

execSQL(Stringsql,Object[]bindArgs)方法的第一个参数为SQL语句,第二个参数为SQL语句中占位符参数的值,参数值在数组中的顺序要和占位符的位置对应。

SQLiteDatabaserawQuery()用于执行select语句,使用例子如下:
SQLiteDatabasedb=....;

Cursorcursor=db.rawQuery(select*fromperson,null);

while(cursor.moveToNext()){

intpersonid=cursor.getInt(0);//获取第一列的值,第一列的索引从0开始

Stringname=cursor.getString(1);//获取第二列的值

intage=cursor.getInt(2);//获取第三列的值

}

cursor.close();

db.close();

rawQuery()方法的第一个参数为select语句;第二个参数为select语句中占位符参数的值,如果select语句没有使用占位符,该参数可以设置为null。带占位符参数的select语句使用例子如下:

Cursorcursor=db.rawQuery("select*frompersonwherenamelike?andage=?",newString[]{"%传智%","4"});

Cursor是结果集游标,用于对结果集进行随机访问,如果大家熟悉jdbc,其实CursorJDBC中的ResultSet作用很相似。使用moveToNext()方法可以将游标从当前行移动到下一行,如果已经移过了结果集的最后一行,返回结果为false,否则为true。另外Cursor还有常用的moveToPrevious()方法(用于将游标从当前行移动到上一行,如果已经移过了结果集的第一行,返回值为false,否则为true)、moveToFirst()方法(用于将游标移动到结果集的第一行,如果结果集为空,返回值为false,否则为true)和moveToLast()方法(用于将游标移动到结果集的最后一行,如果结果集为空,返回值为false,否则为true)。

除了前面给大家介绍的execSQL()rawQuery()方法,SQLiteDatabase还专门提供了对应于添加、删除、更新、查询的操作方法:insert()delete()update()query()。这些方法实际上是给那些不太了解SQL语法的菜鸟使用的,对于熟悉SQL语法的程序员而言,直接使用execSQL()rawQuery()方法执行SQL语句就能完成数据的添加、删除、更新、查询操作。

Insert()方法用于添加数据,各个字段的数据使用ContentValues进行存放。ContentValues类似于MAP,相对于MAP,它提供了存取数据对应的put(Stringkey,Xxxvalue)getAsXxx(Stringkey)方法,key为字段名称,value为字段值,Xxx指的是各种常用的数据类型,如:StringInteger等。

SQLiteDatabasedb=databaseHelper.getWritableDatabase();

ContentValuesvalues=newContentValues();

values.put("name","传智播客");

values.put("age",4);

longrowid=db.insert(person,null,values);//返回新添记录的行号,与主键id无关

不管第三个参数是否包含数据,执行Insert()方法必然会添加一条记录,如果第三个参数为空,会添加一条除主键之外其他字段值为Null的记录。Insert()方法内部实际上通过构造insertSQL语句完成数据的添加,Insert()方法的第二个参数用于指定空值字段的名称,相信大家对该参数会感到疑惑,该参数的作用是什么?是这样的:如果第三个参数valuesNull或者元素个数为0,由于Insert()方法要求必须添加一条除了主键之外其它字段为Null值的记录,为了满足SQL语法的需要,insert语句必须给定一个字段名,如:insertintoperson(name)values(NULL),倘若不给定字段名,insert语句就成了这样:insertintoperson()values(),显然这不满足标准SQL的语法。对于字段名,建议使用主键之外的字段,如果使用了INTEGER类型的主键字段,执行类似insertintoperson(personid)values(NULL)insert语句后,该主键字段值也不会为NULL。如果第三个参数values不为Null并且元素的个数大于0,可以把第二个参数设置为null

delete()方法的使用:

SQLiteDatabasedb=databaseHelper.getWritableDatabase();

db.delete("person","personid<?",newString[]{"2"});

db.close();

上面代码用于从person表中删除personid小于2的记录。

update()方法的使用:

SQLiteDatabasedb=databaseHelper.getWritableDatabase();

ContentValuesvalues=newContentValues();

values.put(name,“传智播客”);//key为字段名,value为值

db.update("person",values,"personid=?",newString[]{"1"});

db.close();

上面代码用于把person表中personid等于1的记录的name字段的值改为“传智播客”。

query()方法实际上是把select语句拆分成了若干个组成部分,然后作为方法的输入参数:

SQLiteDatabasedb=databaseHelper.getWritableDatabase();

Cursorcursor=db.query("person",newString[]{"personid,name,age"},"namelike?",newString[]{"%传智%"},null,null,"personiddesc","1,2");

while(cursor.moveToNext()){

intpersonid=cursor.getInt(0);//获取第一列的值,第一列的索引从0开始

Stringname=cursor.getString(1);//获取第二列的值

intage=cursor.getInt(2);//获取第三列的值

}

cursor.close();

db.close();

上面代码用于从person表中查找name字段含有“传智”的记录,匹配的记录按personid降序排序,对排序后的结果略过第一条记录,只获取2条记录。

query(table,columns,selection,selectionArgs,groupBy,having,orderBy,limit)方法各参数的含义:

table:表名。相当于select语句from关键字后面的部分。如果是多表联合查询,可以用逗号将两个表名分开。

columns:要查询出来的列名。相当于select语句select关键字后面的部分。

selection:查询条件子句,相当于select语句where关键字后面的部分,在条件子句允许使用占位符“?

selectionArgs:对应于selection语句中占位符的值,值在数组中的位置与占位符在语句中的位置必须一致,否则就会有异常。

groupBy:相当于select语句groupby关键字后面的部分

having:相当于select语句having关键字后面的部分

orderBy:相当于select语句orderby关键字后面的部分,如:personiddesc,ageasc;

limit:指定偏移量和获取的记录数,相当于select语句limit关键字后面的部分。

数据库实例

packagecom.itheima.db.dao;

importjava.util.ArrayList;

importjava.util.List;

importandroid.content.ContentValues;

importandroid.content.Context;

importandroid.database.Cursor;

importandroid.database.sqlite.SQLiteDatabase;

importcom.itheima.db.PersonDBOpenHelper;

importcom.itheima.db.domain.Person;

/**

*person表增删改查的工具类

*

*@authorAdministrator

*

*/

publicclassPersonDao{

privatePersonDBOpenHelperhelper;

//在构造方法里面初始化了数据库的帮助类

publicPersonDao(Contextcontext){

helper=newPersonDBOpenHelper(context);

}

/**

*

*@paramname

*@paramphone

*@return返回值代表添加这一行的id返回-1代表插入失败

*/

publiclongadd(Stringname,Stringphone){

SQLiteDatabasedb=helper.getWritableDatabase();

//db.execSQL("insertintoperson(name,phone)values(?,?)",new

//Object[]{name,phone});

//其实就是一个map集合

ContentValuesvalues=newContentValues();

values.put("name",name);

values.put("phone",phone);

longresult=db.insert("person",null,values);

db.close();

returnresult;

}

/**

*

*@paramname

*@return删除成功多少行

*/

publicintdelete(Stringname){

SQLiteDatabasedb=helper.getWritableDatabase();

//db.execSQL("deletefrompersonwherename=?",newObject[]{name});

intresult=db.delete("person","name=?",newString[]{name});

db.close();

returnresult;

}

publicintupdate(Stringname,Stringnewphone){

SQLiteDatabasedb=helper.getWritableDatabase();

//db.execSQL("updatepersonsetphone=?wherename=?",new

//Object[]{newphone,name});

ContentValuesvalues=newContentValues();

values.put("phone",newphone);

intresult=db.update("person",values,"name=?",newString[]{name});

db.close();

returnresult;

}

//查询

publicbooleanfind(Stringname){

booleanresult;

SQLiteDatabasedb=helper.getReadableDatabase();

//Cursorcursor=db.rawQuery("select*frompersonwherename=?",new

//String[]{name});

Cursorcursor=db.query("person",null,"name=?",

newString[]{name},null,null,null);

if(cursor.moveToNext()){

result=true;

}else{

result=false;

}

cursor.close();

db.close();

returnresult;

}

/**

*查找全部

*

*@return

*/

publicList<Person>findAll(){

SQLiteDatabasedb=helper.getReadableDatabase();

List<Person>persons=newArrayList<Person>();

//Cursorcursor=db.rawQuery("selectid,name,phonefromperson",null);

Cursorcursor=db.query("person",

newString[]{"id","name","phone"},null,null,null,null,null);

while(cursor.moveToNext()){

intid=cursor.getInt(0);

Stringname=cursor.getString(1);

Stringphone=cursor.getString(2);

Personperson=newPerson();

person.setId(id);

person.setPhone(phone);

person.setName(name);

persons.add(person);

}

cursor.close();

db.close();

returnpersons;

}

}

4使用SQLiteOpenHelper获取用于操作数据库的SQLiteDatabase实例

privatestaticfinalStringname="itcast";//数据库名称

privatestaticfinalintversion=1;//数据库版本

......

}

publicclassHelloActivityextendsActivity{

@OverridepublicvoidonCreate(BundlesavedInstanceState){

......

Buttonbutton=(Button)this.findViewById(R.id.button);

button.setOnClickListener(newView.OnClickListener(){

publicvoidonClick(Viewv){

DatabaseHelperdatabaseHelper=newDatabaseHelper(HelloActivity.this);

SQLiteDatabasedb=databaseHelper.getWritableDatabase();

db.execSQL("insertintoperson(name,age)values(?,?)",newObject[]{"传智播客",4});

db.close();

}});

}

}

第一次调用getWritableDatabase()getReadableDatabase()方法后,SQLiteOpenHelper会缓存当前的SQLiteDatabase实例,SQLiteDatabase实例正常情况下会维持数据库的打开状态,所以在你不再需要SQLiteDatabase实例时,请及时调用close()方法释放资源。一旦SQLiteDatabase实例被缓存,多次调用getWritableDatabase()getReadableDatabase()方法得到的都是同一实例。

5使用事务操作SQLite数据库

使用SQLiteDatabasebeginTransaction()方法可以开启一个事务,程序执行到endTransaction()方法时会检查事务的标志是否为成功,如果程序执行到endTransaction()之前调用了setTransactionSuccessful()方法设置事务的标志为成功则提交事务,如果没有调用setTransactionSuccessful()方法则回滚事务。使用例子如下:
SQLiteDatabasedb=....;

db.beginTransaction();//开始事务

try{

db.execSQL("insertintoperson(name,age)values(?,?)",newObject[]{"传智播客",4});

db.execSQL("updatepersonsetname=?wherepersonid=?",newObject[]{"传智",1});

db.setTransactionSuccessful();//调用此方法会在执行到endTransaction()时提交当前事务,如果不调用此方法会回滚事务

}finally{

db.endTransaction();//由事务的标志决定是提交事务,还是回滚事务

}

db.close();

上面两条SQL语句在同一个事务中执行。

packagecom.itheima.db.test;

importcom.itheima.db.PersonDBOpenHelper;

importandroid.database.sqlite.SQLiteDatabase;

importandroid.test.AndroidTestCase;

publicclassTestTransctionextendsAndroidTestCase{

Strings;

publicvoidtestSendMoney()throwsException{

PersonDBOpenHelperhelper=newPersonDBOpenHelper(getContext());

SQLiteDatabasedb=helper.getWritableDatabase();

db.beginTransaction();

try{

db.execSQL("updatepersonsetmoney=money-10whereid='1'");

//s.equals("haha");

db.execSQL("updatepersonsetmoney=money+10whereid='2'");

db.setTransactionSuccessful();//代表是事务处理成功.

}finally{

db.endTransaction();//检查是否设置了事务成功的标志,如果设置了提交数据,

//如果没有设置,回滚..

}

}

}

6、Androidsqlite3工具的使用

1cmdàadbshell首先挂载到linux

2cddata/data/com.android.contacts.provider

3cddatabase

4sqlite3contacts打开数据库eg:sqlite3contacts.db

5.tables查看所有的表eg:.table

6.schema查看所有的创建表、视图的语句eg:.schema

7.help查看帮助eg:.help

8.header(s)NO|OFF是否显示列头信息eg:headersON

9.modeMODE?table?指定数据显示风格eg:.modecolumn

10.nullValueNULL空值数据显示问题eg:.nullValueNULL

7、使用ContentProvider(内容提供者)共享数据

ContentProviderandroid中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider对你应用中的数据进行添删改查。关于数据共享,以前我们学习过文件操作模式,知道通过指定文件的操作模式为Context.MODE_WORLD_READABLEContext.MODE_WORLD_WRITEABLE同样也可以对外共享数据。那么,这里为何要使用ContentProvider对外共享数据呢?是这样的,如果采用文件操作模式对外共享数据,数据的访问方式会因数据存储的方式而不同,导致数据的访问方式无法统一,如:采用xml文件对外共享数据,需要进行xml解析才能读取数据;采用sharedpreferences共享数据,需要使用sharedpreferencesAPI读取数据。

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

当应用需要通过ContentProvider对外共享数据时,第一步需要继承ContentProvider并重写下面方法:

publicclassPersonContentProviderextendsContentProvider{

publicbooleanonCreate()

publicUriinsert(Uriuri,ContentValuesvalues)

publicintdelete(Uriuri,Stringselection,String[]selectionArgs)

publicintupdate(Uriuri,ContentValuesvalues,Stringselection,String[]selectionArgs)

publicCursorquery(Uriuri,String[]projection,Stringselection,String[]selectionArgs,StringsortOrder)

publicStringgetType(Uriuri)}

第二步需要在AndroidManifest.xml使用<provider>对该ContentProvider进行配置,为了能让其他应用找到该ContentProviderContentProvider采用了authorities(主机名/域名)对它进行唯一标识,你可以把ContentProvider看作是一个网站(想想,网站也是提供数据者),authorities就是他的域名:

<manifest....>

<applicationandroid:icon="@drawable/icon"android:label="@string/app_name">

<providerandroid:name=".PersonContentProvider"android:authorities="cn.itcast.providers.personprovider"/>

</application>

</manifest>

packagecn.itcast.db;

importcn.itcast.service.DBOpenHelper;

importandroid.content.ContentProvider;

importandroid.content.ContentUris;

importandroid.content.ContentValues;

importandroid.content.UriMatcher;

importandroid.database.Cursor;

importandroid.database.sqlite.SQLiteDatabase;

importandroid.net.Uri;

publicclassPersonContentProviderextendsContentProvider{

privatestaticUriMatchermatcher=newUriMatcher(UriMatcher.NO_MATCH);

privatestaticfinalintPERSONS=1;

privatestaticfinalintPERSON=2;

privateDBOpenHelperdbOpenHelper;

static{

matcher.addURI("cn.itcast.providers.personprovider","person",PERSONS);

matcher.addURI("cn.itcast.providers.personprovider","person/#",PERSON);

}

@Override

publicbooleanonCreate(){

dbOpenHelper=newDBOpenHelper(this.getContext());

returntrue;

}

@Override

publicintdelete(Uriuri,Stringselection,String[]selectionArgs){

SQLiteDatabasedb=dbOpenHelper.getWritableDatabase();

intnum=0;//已经删除的记录数量

switch(matcher.match(uri)){

casePERSONS:

num=db.delete("person",selection,selectionArgs);

break;

casePERSON:

longid=ContentUris.parseId(uri);

Stringwhere="personid="+id;

if(selection!=null&&!"".equals(selection)){//personid=12andname=?

where=where+"and"+selection;

}

num=db.delete("person",where,selectionArgs);

break;

default:

thrownewIllegalArgumentException("UnkownUri:"+uri);

}

getContext().getContentResolver().notifyChange(uri,null);

returnnum;

}

publicStringgetType(Uriuri){//返回当前操作的数据类型

switch(matcher.match(uri)){

casePERSONS://操作的是集合类型数据

return"vnd.android.cursor.dir/person";

casePERSON:

return"vnd.android.cursor.item/person";

default:

thrownewIllegalArgumentException("UnkownUri:"+uri);

}

}

@Override

publicUriinsert(Uriuri,ContentValuesvalues){

SQLiteDatabasedb=dbOpenHelper.getWritableDatabase();

longid=0;

switch(matcher.match(uri)){

casePERSONS:

id=db.insert("person","personid",values);//得到记录的id

getContext().getContentResolver().notifyChange(uri,null);

returnContentUris.withAppendedId(uri,id);//返回代表新增记录的Uri

casePERSON:

id=db.insert("person","personid",values);//得到记录的id

StringstrUri=uri.toString();

UripersonUri=Uri.parse(strUri.substring(0,strUri.lastIndexOf("/")));

getContext().getContentResolver().notifyChange(personUri,null);

returnContentUris.withAppendedId(personUri,id);

default:

thrownewIllegalArgumentException("UnkownUri:"+uri);

}

}

@Override

publicCursorquery(Uriuri,String[]projection,Stringselection,String[]selectionArgs,StringsortOrder){

SQLiteDatabasedb=dbOpenHelper.getReadableDatabase();

switch(matcher.match(uri)){

casePERSONS:

returndb.query("person",projection,selection,selectionArgs,null,null,sortOrder);

casePERSON:

longid=ContentUris.parseId(uri);

Stringwhere="personid="+id;

if(selection!=null&&!"".equals(selection)){//personid=12andname=?

where=where+"and"+selection;

}

returndb.query("person",projection,where,selectionArgs,null,null,sortOrder);

default:

thrownewIllegalArgumentException("UnkownUri:"+uri);

}

}

@Override

publicintupdate(Uriuri,ContentValuesvalues,Stringselection,String[]selectionArgs){

SQLiteDatabasedb=dbOpenHelper.getWritableDatabase();

intnum=0;//已经修改的记录数量

switch(matcher.match(uri)){

casePERSONS:

num=db.update("person",values,selection,selectionArgs);

break;

casePERSON:

longid=ContentUris.parseId(uri);

Stringwhere="personid="+id;

if(selection!=null&&!"".equals(selection)){

where=where+"and"+selection;

}

num=db.update("person",values,where,selectionArgs);

break;

default:

thrownewIllegalArgumentException("UnkownUri:"+uri);

}

getContext().getContentResolver().notifyChange(uri,null);//通知数据发生变化

returnnum;

}

}

8Uri介绍

Uri代表了要操作的数据,Uri主要包含了两部分信息:1》需要操作的ContentProvider2》对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:

ContentProvider(内容提供者)的scheme已经由Android所规定,scheme为:content://

主机名(或叫Authority)用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。

路径(path)可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:

要操作person表中id10的记录,可以构建这样的路径:/person/10

要操作person表中id10的记录的name字段,person/10/name

要操作person表中的所有记录,可以构建这样的路径:/person

要操作xxx表中的记录,可以构建这样的路径:/xxx

当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下:

要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name

如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:

Uriuri=Uri.parse("content://cn.itcast.provider.personprovider/person")

9UriMatcher类使用介绍

因为Uri代表了要操作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcherContentUris。掌握它们的使用,会便于我们的开发工作。

UriMatcher类用于匹配Uri,它的用法如下:

首先第一步把你需要匹配Uri路径全部给注册上,如下:

//常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码

UriMatchersMatcher=newUriMatcher(UriMatcher.NO_MATCH);

//如果match()方法匹配content://cn.itcast.provider.personprovider/person路径,返回匹配码为1

sMatcher.addURI(cn.itcast.provider.personprovider,person,1);//添加需要匹配uri,如果匹配就会返回匹配码

//如果match()方法匹配content://cn.itcast.provider.personprovider/person/230路径,返回匹配码为2

sMatcher.addURI(cn.itcast.provider.personprovider,person/#,2);//#号为通配符

switch(sMatcher.match(Uri.parse("content://cn.itcast.provider.personprovider/person/10"))){

case1

break;

case2

break;

default://不匹配

break;

}

注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,假设匹配content://cn.itcast.provider.personprovider/person路径,返回的匹配码为1

10ContentUris类使用介绍

1ContentUris类用于获取Uri路径后面的ID部分,它有两个比较实用的方法:

withAppendedId(uri,id)用于为路径加上ID部分:

Uriuri=Uri.parse("content://cn.itcast.provider.personprovider/person")

UriresultUri=ContentUris.withAppendedId(uri,10);

//生成后的Uri为:content://cn.itcast.provider.personprovider/person/10

2parseId(uri)方法用于从路径中获取ID部分:

Uriuri=Uri.parse("content://cn.itcast.provider.personprovider/person/10")

longpersonid=ContentUris.parseId(uri);//获取的结果为:10

11使用ContentProvider共享数据

ContentProvider类主要方法的作用:

publicbooleanonCreate()

该方法在ContentProvider创建后就会被调用,Android开机后,ContentProvider在其它应用第一次访问它时才会被创建。

publicUriinsert(Uriuri,ContentValuesvalues)

该方法用于供外部应用往ContentProvider添加数据。

publicintdelete(Uriuri,Stringselection,String[]selectionArgs)

该方法用于供外部应用从ContentProvider删除数据。

publicintupdate(Uriuri,ContentValuesvalues,Stringselection,String[]selectionArgs)

该方法用于供外部应用更新ContentProvider中的数据。

publicCursorquery(Uriuri,String[]projection,Stringselection,String[]selectionArgs,StringsortOrder)

该方法用于供外部应用从ContentProvider中获取数据。

publicStringgetType(Uriuri)

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

12使用ContentResolver操作ContentProvider中的数据

当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver类来完成,要获取ContentResolver对象,可以使用Activity提供的getContentResolver()方法。ContentResolver类提供了与ContentProvider类相同签名的四个方法:

publicUriinsert(Uriuri,ContentValuesvalues)

该方法用于往ContentProvider添加数据。

publicintdelete(Uriuri,Stringselection,String[]selectionArgs)

该方法用于从ContentProvider删除数据。

publicintupdate(Uriuri,ContentValuesvalues,Stringselection,String[]selectionArgs)

该方法用于更新ContentProvider中的数据。

publicCursorquery(Uriuri,String[]projection,Stringselection,String[]selectionArgs,StringsortOrder)

该方法用于从ContentProvider中获取数据。

这些方法的第一个参数为Uri,代表要操作的ContentProvider和对其中的什么数据进行操作,假设给定的是:Uri.parse(content://cn.itcast.providers.personprovider/person/10),那么将会对主机名为cn.itcast.providers.personproviderContentProvider进行操作,操作的数据为person表中id10的记录。

使用ContentResolverContentProvider中的数据进行添加、删除、修改和查询操作:

ContentResolverresolver=getContentResolver();

Uriuri=Uri.parse("content://cn.itcast.provider.personprovider/person");

//添加一条记录

ContentValuesvalues=newContentValues();

values.put("name","itcast");

values.put("age",25);

resolver.insert(uri,values);

//获取person表中所有记录

Cursorcursor=resolver.query(uri,null,null,null,"personiddesc");

while(cursor.moveToNext()){

Log.i("ContentTest","personid="+cursor.getInt(0)+",name="+cursor.getString(1));

}

//id1的记录的name字段值更改新为liming

ContentValuesupdateValues=newContentValues();

updateValues.put("name","liming");

UriupdateIdUri=ContentUris.withAppendedId(uri,2);

resolver.update(updateIdUri,updateValues,null,null);

//删除id2的记录

UrideleteIdUri=ContentUris.withAppendedId(uri,2);

resolver.delete(deleteIdUri,null,null);

数据库的内容提供者

packagecom.itheima.db;

importandroid.content.ContentProvider;

importandroid.content.ContentValues;

importandroid.content.UriMatcher;

importandroid.database.Cursor;

importandroid.database.sqlite.SQLiteDatabase;

importandroid.net.Uri;

publicclassPersonDBProviderextendsContentProvider{

//返回一组的数据

privatestaticfinalintPERSONS=1;

privatestaticfinalintAAABBBCCC=2;

//返回一个person对象

privatestaticfinalintPERSON=3;

privatePersonDBOpenHelperhelper;

//电话号码的匹配器

privatestaticUriMatchermUriMatcher=newUriMatcher(UriMatcher.NO_MATCH);

//确定电话匹配的规则

static{

mUriMatcher.addURI("com.itheima.listdb.person","person",PERSONS);

mUriMatcher.addURI("com.itheima.listdb.person","person/#",PERSON);

mUriMatcher.addURI("com.itheima.listdb.person","aaabbbccc",AAABBBCCC);

}

@Override

publicbooleanonCreate(){

helper=newPersonDBOpenHelper(getContext());

returnfalse;

}

//查询的方法

@Override

publicCursorquery(Uriuri,String[]projection,Stringselection,

String[]selectionArgs,StringsortOrder){

if(mUriMatcher.match(uri)==PERSONS){

System.out.println("满足person的匹配规则");

SQLiteDatabasedb=helper.getReadableDatabase();

returndb.query("person",projection,selection,selectionArgs,null,null,sortOrder);

}elseif(mUriMatcher.match(uri)==PERSON){

System.out.println("满足一个person的匹配规则");

Stringpath=uri.toString();

System.out.println("path:"+path);

Stringid=path.substring(path.lastIndexOf("/")+1);

SQLiteDatabasedb=helper.getReadableDatabase();

returndb.query("person",projection,"id=?",newString[]{id},null,null,null);

}else{

thrownewIllegalArgumentException("路径不匹配,口令错误...滚一边去");

}

}

//返回当前数据的mime的类型主要作用区分数据是一个集合还是单独一个条目

@Override

publicStringgetType(Uriuri){

if(mUriMatcher.match(uri)==PERSONS){

return"vnd.android.cursor.dir/persons";

}elseif(mUriMatcher.match(uri)==PERSON){

return"vnd.android.cursor.item/person";

}

returnnull;

}

@Override

publicUriinsert(Uriuri,ContentValuesvalues){

if(mUriMatcher.match(uri)==PERSON){

System.out.println("满足person的匹配规则");

SQLiteDatabasedb=helper.getWritableDatabase();

db.insert("person",null,values);

}else{

thrownewIllegalArgumentException("路径不匹配,口令错误...滚一边去");

}

returnnull;

}

@Override

publicintdelete(Uriuri,Stringselection,String[]selectionArgs){

if(mUriMatcher.match(uri)==PERSON){

System.out.println("满足person的匹配规则");

SQLiteDatabasedb=helper.getWritableDatabase();

db.delete("person",selection,selectionArgs);

}else{

thrownewIllegalArgumentException("路径不匹配,口令错误...滚一边去");

}

return0;

}

@Override

publicintupdate(Uriuri,ContentValuesvalues,Stringselection,

String[]selectionArgs){

if(mUriMatcher.match(uri)==PERSON){

System.out.println("满足person的匹配规则");

SQLiteDatabasedb=helper.getWritableDatabase();

db.update("person",values,selection,selectionArgs);

}else{

thrownewIllegalArgumentException("路径不匹配,口令错误...滚一边去");

}

return0;

}

}

<application

android:allowBackup="true"

android:icon="@drawable/ic_launcher"

android:label="@string/app_name"

android:theme="@style/AppTheme">

<!--测试的指令集需要的函数库-->

<uses-libraryandroid:name="android.test.runner"/>

<activity

android:name="com.itheima.db.MainActivity"

android:label="@string/app_name">

<intent-filter>

<actionandroid:name="android.intent.action.MAIN"/>

<categoryandroid:name="android.intent.category.LAUNCHER"/>

</intent-filter>

</activity>

<provider

android:name="com.itheima.db.PersonDBProvider"

android:authorities="com.itheima.listdb.person">

</provider>

</application>

读取用户的短信

packagecom.itheima.readsms;

importjava.io.File;

importjava.io.FileNotFoundException;

importjava.io.FileOutputStream;

importjava.io.IOException;

importorg.xmlpull.v1.XmlSerializer;

importandroid.app.Activity;

importandroid.content.ContentResolver;

importandroid.database.Cursor;

importandroid.net.Uri;

importandroid.os.Bundle;

importandroid.util.Xml;

importandroid.view.View;

importandroid.widget.Toast;

publicclassMainActivityextendsActivity{

@Override

protectedvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}

publicvoidreadSms(Viewview){

//得到一个内容解析者

ContentResolverresolver=getContentResolver();

Uriuri=Uri.parse("content://sms/");

Cursorcursor=resolver.query(uri,newString[]{"address","type","date","body"},null,null,null);

XmlSerializerserializer=Xml.newSerializer();

try{

Filefile=newFile(getFilesDir(),"sms.xml");

FileOutputStreamos=newFileOutputStream(file);

serializer.setOutput(os,"utf-8");

serializer.startDocument("utf-8",true);

serializer.startTag(null,"smss");

while(cursor.moveToNext()){

serializer.startTag(null,"sms");

Stringaddress=cursor.getString(0);

serializer.startTag(null,"address");

serializer.text(address);

serializer.endTag(null,"address");

Stringtype=cursor.getString(1);

serializer.startTag(null,"type");

serializer.text(type);

serializer.endTag(null,"type");

Stringdate=cursor.getString(2);

serializer.startTag(null,"date");

serializer.text(date);

serializer.endTag(null,"date");

Stringbody=cursor.getString(3);

serializer.startTag(null,"body");

serializer.text(body);

serializer.endTag(null,"body");

System.out.println("address="+address);

System.out.println("type="+type);

System.out.println("date="+date);

System.out.println("body="+body);

System.out.println("----------------");

serializer.endTag(null,"sms");

}

serializer.endTag(null,"smss");

serializer.endDocument();

os.close();

Toast.makeText(this,"备份短信完成",0).show();

}catch(Exceptione){

e.printStackTrace();

Toast.makeText(this,"备份短信失败",0).show();

}

}

}

还原一条短信

packagecom.itheima.restoresms;

importandroid.app.Activity;

importandroid.content.ContentResolver;

importandroid.content.ContentValues;

importandroid.net.Uri;

importandroid.os.Bundle;

importandroid.view.View;

publicclassMainActivityextendsActivity{

@Override

protectedvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}

publicvoidclick(Viewview){

newThread(){

publicvoidrun(){

try{

Thread.sleep(10000);

}catch(InterruptedExceptione){

e.printStackTrace();

}

ContentResolverresolver=getContentResolver();

Uriuri=Uri.parse("content://sms/");

ContentValuesvalues=newContentValues();

values.put("address","95533");

values.put("date",System.currentTimeMillis());

values.put("type","1");

values.put("body","尊敬的建行客户张先生,您的尾号为201的建行卡在1647分收入,银行转账1,000,000,000,000.22人民币,活期余额2,080,000,000,020.22");

resolver.insert(uri,values);

};

}.start();

}

}

13监听ContentProvider中数据的变化

如果ContentProvider的访问者需要知道ContentProvider中的数据发生了变化,可以在ContentProvider发生数据变化时调用getContentResolver().notifyChange(uri,null)来通知注册在此URI上的访问者,例子如下:

publicclassPersonContentProviderextendsContentProvider{

publicUriinsert(Uriuri,ContentValuesvalues){

db.insert("person","personid",values);

getContext().getContentResolver().notifyChange(uri,null);

}

}

如果ContentProvider的访问者需要得到数据变化通知,必须使用ContentObserver对数据(数据采用uri描述)进行监听,当监听到数据变化通知时,系统就会调用ContentObserveronChange()方法:

getContentResolver().registerContentObserver(Uri.parse("content://cn.itcast.providers.personprovider/person"),

true,newPersonObserver(newHandler()));

publicclassPersonObserverextendsContentObserver{

publicPersonObserver(Handlerhandler){

super(handler);

}

publicvoidonChange(booleanselfChange){

//此处可以进行相应的业务处理

}

}

14、窃听用户发出的短信

用户使用系统自带的短信程序发送短信,程序会通过ContentProvider把短信保存进数据库,并且发出一个数据变化通知,使用ContentObserver对数据变化进行监听,在用户发送短信时,就会被ContentObserver窃听到短信:

注册监听:

getContentResolver().registerContentObserver(Uri.parse("content://sms"),true,newSmsObserver(newHandler()));

监听类:

privatefinalclassSmsObserverextendsContentObserver{

publicSmsObserver(Handlerhandler){

super(handler);

}

publicvoidonChange(booleanselfChange){//查询发送箱中的短信(处于正在发送状态的短信放在发送箱)

Cursorcursor=getContentResolver().query(Uri.parse("content://sms/outbox"),null,null,null,null);

while(cursor.moveToNext()){

StringBuildersb=newStringBuilder();

sb.append("_id=").append(cursor.getInt(cursor.getColumnIndex("_id")));

sb.append(",address=").append(cursor.getString(cursor.getColumnIndex("address")));

sb.append(";body=").append(cursor.getString(cursor.getColumnIndex("body")));

sb.append(";time=").append(cursor.getLong(cursor.getColumnIndex("date")));

Log.i("ReceiveSendSMS",sb.toString());

}}

}

15、通信录操作

使用ContentResolver对通信录中的数据进行添加、删除、修改和查询操作:

加入读写联系人信息的权限

<uses-permissionandroid:name="android.permission.READ_CONTACTS"/>

<uses-permissionandroid:name="android.permission.WRITE_CONTACTS"/>

加入读取联系人信息的权限

<uses-permissionandroid:name="android.permission.READ_CONTACTS"/>

content://com.android.contacts/contacts操作的数据是联系人信息Uri

content://com.android.contacts/data/phones联系人电话Uri

content://com.android.contacts/data/emails联系人EmailUri

读取联系人信息

Cursorcursor=getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,

null,null,null,null);

while(cursor.moveToNext()){

StringcontactId=cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));

Stringname=cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));

Cursorphones=getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,

null,

ContactsContract.CommonDataKinds.Phone.CONTACT_ID+"="+contactId,

null,null);

while(phones.moveToNext()){

StringphoneNumber=phones.getString(phones.getColumnIndex(

ContactsContract.CommonDataKinds.Phone.NUMBER));

Log.i("RongActivity","phoneNumber="+phoneNumber);

}

phones.close();

Cursoremails=getContentResolver().query(ContactsContract.CommonDataKinds.Email.CONTENT_URI,

null,

ContactsContract.CommonDataKinds.Email.CONTACT_ID+"="+contactId,

null,null);

while(emails.moveToNext()){

//Thiswouldallowyougetseveralemailaddresses

StringemailAddress=emails.getString(emails.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));

Log.i("RongActivity","emailAddress="+emailAddress);

}

emails.close();

}

cursor.close();

====================添加联系人===========================

方法一:

/**

*首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获取系统返回的rawContactId

*这时后面插入data表的依据,只有执行空值插入,才能使插入的联系人在通讯录里面可见

*/

publicvoidtestInsert(){

ContentValuesvalues=newContentValues();

//首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获取系统返回的rawContactId

UrirawContactUri=this.getContext().getContentResolver().insert(RawContacts.CONTENT_URI,values);

longrawContactId=ContentUris.parseId(rawContactUri);

//data表入姓名数据

values.clear();

values.put(Data.RAW_CONTACT_ID,rawContactId);

values.put(Data.MIMETYPE,StructuredName.CONTENT_ITEM_TYPE);//内容类型

values.put(StructuredName.GIVEN_NAME,"李天山");

this.getContext().getContentResolver().insert(android.provider.ContactsContract.Data.CONTENT_URI,values);

//data表入电话数据

values.clear();

values.put(Data.RAW_CONTACT_ID,rawContactId);

values.put(Data.MIMETYPE,Phone.CONTENT_ITEM_TYPE);

values.put(Phone.NUMBER,"13921009789");

values.put(Phone.TYPE,Phone.TYPE_MOBILE);

this.getContext().getContentResolver().insert(android.provider.ContactsContract.Data.CONTENT_URI,values);

//data表入Email数据

values.clear();

values.put(Data.RAW_CONTACT_ID,rawContactId);

values.put(Data.MIMETYPE,Email.CONTENT_ITEM_TYPE);

values.put(Email.DATA,"liming@itcast.cn");

values.put(Email.TYPE,Email.TYPE_WORK);

this.getContext().getContentResolver().insert(android.provider.ContactsContract.Data.CONTENT_URI,values);

}

方法二:批量添加,处于同一个事务中

publicvoidtestSave()throwsThrowable{

//文档位置:reference\android\provider\ContactsContract.RawContacts.html

ArrayList<ContentProviderOperation>ops=newArrayList<ContentProviderOperation>();

intrawContactInsertIndex=0;

ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)

.withValue(RawContacts.ACCOUNT_TYPE,null)

.withValue(RawContacts.ACCOUNT_NAME,null)

.build());

//文档位置:reference\android\provider\ContactsContract.Data.html

ops.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)

.withValueBackReference(Data.RAW_CONTACT_ID,rawContactInsertIndex)

.withValue(Data.MIMETYPE,StructuredName.CONTENT_ITEM_TYPE)

.withValue(StructuredName.GIVEN_NAME,"赵薇")

.build());

ops.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)

.withValueBackReference(Data.RAW_CONTACT_ID,rawContactInsertIndex)

.withValue(Data.MIMETYPE,Phone.CONTENT_ITEM_TYPE)

.withValue(Phone.NUMBER,"13671323809")

.withValue(Phone.TYPE,Phone.TYPE_MOBILE)

.withValue(Phone.LABEL,"手机号")

.build());

ops.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)

.withValueBackReference(Data.RAW_CONTACT_ID,rawContactInsertIndex)

.withValue(Data.MIMETYPE,Email.CONTENT_ITEM_TYPE)

.withValue(Email.DATA,"liming@itcast.cn")

.withValue(Email.TYPE,Email.TYPE_WORK)

.build());

ContentProviderResult[]results=this.getContext().getContentResolver()

.applyBatch(ContactsContract.AUTHORITY,ops);

for(ContentProviderResultresult:results){

Log.i(TAG,result.uri.toString());

}

}

16、Listview数据适配器

listview列表view

1.知道一共要显示有多少个条目

2.知道一个屏幕上最多能显示多个条目

3.创建一个集合双向链表

4.滑动界面的时候最上面条目移除屏幕双向链表移除对象.双向链表添加对象.

m:model数据模型Person

v:view展示视图ListView

c:controller控制器adapter

ListView数据库界面展现

<?xmlversion="1.0"encoding="utf-8"?>

<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="wrap_content">

<TextView

android:id="@+id/tv_name"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_alignParentLeft="true"

android:layout_alignParentTop="true"

android:text="姓名"

android:textColor="#000000"

android:textSize="20sp"/>

<TextView

android:id="@+id/tv_id"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_below="@id/tv_name"

android:text="联系人id"

android:textColor="#66000000"

android:textSize="14sp"/>

<TextView

android:id="@+id/tv_phone"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_alignParentRight="true"

android:layout_centerVertical="true"

android:text="电话号码"

android:textColor="#000000"

android:textSize="16sp"/>

<ImageView

android:layout_toLeftOf="@id/tv_phone"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerVertical="true"

android:src="@drawable/phone"/>

</RelativeLayout>

packagecom.itheima.db;

importjava.util.List;

importandroid.app.Activity;

importandroid.os.Bundle;

importandroid.util.Log;

importandroid.view.View;

importandroid.view.ViewGroup;

importandroid.widget.BaseAdapter;

importandroid.widget.LinearLayout;

importandroid.widget.ListAdapter;

importandroid.widget.ListView;

importandroid.widget.RelativeLayout;

importandroid.widget.TextView;

importcom.itheima.db.dao.PersonDao;

importcom.itheima.db.domain.Person;

importcom.itheima.listdb.R;

publicclassMainActivityextendsActivity{

publicstaticfinalStringTAG="MainActivity";

privateListViewlv;

privateList<Person>persons;

@Override

protectedvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

lv=(ListView)findViewById(R.id.lv);

PersonDaodao=newPersonDao(this);

persons=dao.findAll();

lv.setAdapter(newMyAdapter());

}

privateclassMyAdapterextendsBaseAdapter{

/**

*返回整个数据适配器列表里面有多少个条目

*/

@Override

publicintgetCount(){

returnpersons.size();

}

/**

*返回某个位置要显示的view对象

*/

@Override

publicViewgetView(intposition,ViewconvertView,ViewGroupparent){

//根据layout目录下list_item的布局为模板创建一个view对象.

//一般情况下创建的view对象都是独立的view对象第三个参数null

Viewview=View.inflate(getApplicationContext(),R.layout.list_item,null);

TextViewtv_name=(TextView)view.findViewById(R.id.tv_name);

TextViewtv_id=(TextView)view.findViewById(R.id.tv_id);

TextViewtv_phone=(TextView)view.findViewById(R.id.tv_phone);

Personperson=persons.get(position);

tv_id.setText("联系人id:"+person.getId());

tv_name.setText(person.getName());

tv_phone.setText(person.getPhone());

returnview;

}

@Override

publicObjectgetItem(intposition){

returnnull;

}

@Override

publiclonggetItemId(intposition){

return0;

}

}

}

ArrayAdapter实例:

<?xmlversion="1.0"encoding="utf-8"?>

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:gravity="center_vertical"

android:orientation="horizontal">

<ImageView

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/ic_launcher"/>

<TextView

android:id="@+id/tv_info"

android:text="哈哈"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:textColor="#000000"

android:textSize="20sp"/>

</LinearLayout>

packagecom.itheima.arrayadapter;

importandroid.os.Bundle;

importandroid.app.Activity;

importandroid.view.Menu;

importandroid.widget.ArrayAdapter;

importandroid.widget.ListView;

publicclassMainActivityextendsActivity{

@Override

protectedvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

ListViewlv=(ListView)findViewById(R.id.lv);

lv.setAdapter(newArrayAdapter<String>(this,R.layout.list_item,

R.id.tv_info,newString[]{"功能1","功能2","功能3","功能4","功能5",

"功能1","功能2","功能3","功能4","功能5"}));

}

}

SimpleAdapter数据库界面展现

<?xmlversion="1.0"encoding="utf-8"?>

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:gravity="center_vertical"

android:orientation="horizontal">

<ImageView

android:id="@+id/iv_icon"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/ic_launcher"/>

<TextView

android:id="@+id/tv_info"

android:text="哈哈"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:textColor="#000000"

android:textSize="20sp"/>

</LinearLayout>

packagecom.itheima.simpleadapter;

importjava.util.ArrayList;

importjava.util.HashMap;

importjava.util.List;

importjava.util.Map;

importandroid.app.Activity;

importandroid.os.Bundle;

importandroid.widget.ListView;

importandroid.widget.SimpleAdapter;

publicclassMainActivityextendsActivity{

privateListViewlv;

@Override

protectedvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

lv=(ListView)findViewById(R.id.lv);

List<Map<String,Object>>data=newArrayList<Map<String,Object>>();

//准备第一个map对象第一个要显示条目对应的数据

Map<String,Object>map1=newHashMap<String,Object>();

map1.put("image",R.drawable.app);

map1.put("text","功能1");

Map<String,Object>map2=newHashMap<String,Object>();

map2.put("image",R.drawable.atools);

map2.put("text","功能2");

Map<String,Object>map3=newHashMap<String,Object>();

map3.put("image",R.drawable.safe);

map3.put("text","功能3");

Map<String,Object>map4=newHashMap<String,Object>();

map4.put("image",R.drawable.settings);

map4.put("text","功能4");

data.add(map1);

data.add(map2);

data.add(map3);

data.add(map4);

lv.setAdapter(newSimpleAdapter(this,data,R.layout.list_item,

newString[]{"image","text"},newint[]{R.id.iv_icon,R.id.tv_info}));

}

}

更多相关文章

  1. Android多媒体数据库详解
  2. Android SQLite 数据库的使用
  3. MTK 添加宏控方法
  4. Android AsyncTask onProgressUpdate 方法的些许研究
  5. Android Studio中genymotion安装方法
  6. Android使用HttpClient方法和易错问题
  7. Android开机自启动程序设置及控制方法思路浅谈
  8. android获取当前运行Activity名字的方法
  9. android异步任务加载数据界面实现

随机推荐

  1. 聊聊 Android 的网络请求框架 Retrofit 2
  2. LinearLayout和RelativeLayout绘制过程的
  3. MTK Android Driver:EINT
  4. android Handler/Looper 总结
  5. android锁屏页面的实现
  6. android的m、mm、mmm编译命令的使用
  7. Android(安卓)Monkey压力测试
  8. Android(安卓)JNI开发入门之一
  9. 屏幕适配那点事
  10. Android 解析 HTML