版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Android应用开发——进阶知识应用纲要数据存储与IO深入理解ActivityAndroid网络应用BroadcastReceiver应用效劳——service通知管理——Notification数据存储与IO文件存储SharedPreferencesSqlite数据库ContentProvider文件存储提供了openFileOutput()和openFileInput()方法进行IO操作。openFileOutput()首先给大家介绍使用文件如何对数据进行存储,Activity提供了openFileOutput()方法可以用于把数据输出到文件中,具体的实现过程与在J2SE环境中保存数据到文件中是一样的。privatevoidwrite(Stringcontent) { try { //以追加模式翻开文件输出流 FileOutputStreamfos=openFileOutput(FILE_NAME,MODE_APPEND); //将FileOutputStream包装成PrintStream PrintStreamps=newPrintStream(fos); //输出文件内容 ps.println(content); //关闭文件输出流 ps.close(); } catch(Exceptione) { e.printStackTrace(); } }文件存储openFileOutput()openFileOutput()方法的第一参数用于指定文件名称,不能包含路径分隔符“/”,如果文件不存在,Android会自动创立它。创立的文件保存在/data/data/<packagename>/files目录,如:,通过点击Eclipse菜单“Window”-“ShowView”-“Other”,在对话窗口中展开android文件夹,选择下面的FileExplorer视图,然后在FileExplorer视图中展开/data/data/<packagename>/files目录就可以看到该文件。openFileOutput()方法的第二参数用于指定操作模式,有四种模式,分别为:Context.MODE_PRIVATE=0Context.MODE_APPEND=32768Context.MODE_WORLD_READABLE=1Context.MODE_WORLD_WRITEABLE=2文件存储openFileOutput()Context.MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可以使用Context.MODE_APPENDContext.MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否那么就创立新文件。Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE用来控制其他应用是否有权限读写该文件。MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。如果希望文件被其他应用读和写,可以传入:openFileOutput("itcast.txt",Context.MODE_WORLD_READABLE+Context.MODE_WORLD_WRITEABLE);android有一套自己的平安模型,当应用程序(.apk)在安装时系统就会分配给他一个userid,当该应用要去访问其他资源比方文件的时候,就需要userid匹配。默认情况下,任何应用创立的文件,sharedpreferences,数据库都应该是私有的〔位于/data/data/<packagename>/files〕,其他程序无法访问。除非在创立时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE,只有这样其他程序才能正确访问。文件存储openFileInput()如果要翻开存放在/data/data/<packagename>/files目录应用私有的文件,可以使用Activity提供openFileInput()方法。privateStringread() { try { //翻开文件输入流 FileInputStreamfis=openFileInput(FILE_NAME); byte[]buff=newbyte[1024]; inthasRead=0; StringBuildersb=newStringBuilder(""); //读取文件内容 while((hasRead=fis.read(buff))>0) { sb.append(newString(buff,0,hasRead)); } //关闭文件输入流 fis.close(); returnsb.toString(); } catch(Exceptione) { e.printStackTrace(); } returnnull; }文件存储openFileInput()或者直接使用文件的绝对路径:Filefile=newFile("/data/data//files/itcast.txt");FileInputStreaminStream=newFileInputStream(file);Log.i("FileTest",readInStream(inStream));注意:上面文件路径中的“cn.itcast.action”为应用所在包,当你在编写代码时应替换为你自己应用使用的包。对于私有文件只能被创立该文件的应用访问,如果希望文件能被其他应用读和写,可以在创立文件时,指定Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE权限。Activity还提供了getCacheDir()和getFilesDir()方法:getCacheDir()方法用于获取/data/data/<packagename>/cache目录getFilesDir()方法用于获取/data/data/<packagename>/files目录SharedPreferences很多时候我们开发的软件需要向用户提供软件参数设置功能,例如我们常用的QQ,用户可以设置是否允许陌生人添加自己为好友。对于软件配置参数的保存,如果是window软件通常我们会采用ini文件进行保存,如果是j2se应用,我们会采用properties属性文件进行保存。如果是Android应用,我们最适合采用什么方式保存软件配置参数呢?Android平台给我们提供了一个SharedPreferences类,它是一个轻量级的存储类,特别适合用于保存软件配置参数。使用SharedPreferences保存数据,其背后是用xml文件存放数据,文件存放在/data/data/<packagename>/shared_prefs目录下:SharedPreferencessharedPreferences=getSharedPreferences("itcast",Context.MODE_PRIVATE);Editoreditor=sharedPreferences.edit();//获取编辑器editor.putString("name","jack");editor.putInt("age",4);editormit();//提交修改生成的itcast.xml文件内容如下:<?xmlversion='1.0'encoding='utf-8'standalone='yes'?><map><stringname="name">Jack</string><intname="age"value="4"/></map>因为SharedPreferences背后是使用xml文件保存数据,getSharedPreferences(name,mode)方法的第一个参数用于指定该文件的名称,名称不用带后缀,后缀会由Android自动加上。方法的第二个参数指定文件的操作模式,共有四种操作模式,这四种模式前面介绍使用文件方式保存数据时已经讲解过。如果希望SharedPreferences背后使用的xml文件能被其他应用读和写,可以指定Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE权限。另外Activity还提供了另一个getPreferences(mode)方法操作SharedPreferences,这个方法默认使用当前类不带包名的类名作为文件的名称。SharedPreferences访问SharedPreferences中的数据代码如下:SharedPreferencessharedPreferences=getSharedPreferences("itcast",Context.MODE_PRIVATE);//getString()第二个参数为缺省值,如果preference中不存在该key,将返回缺省值Stringname=sharedPreferences.getString("name","");intage=sharedPreferences.getInt("age",1);如果访问其他应用中的Preference,前提条件是:该preference创立时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE权限。如:有个<packagename>为的应用使用下面语句创立了preference。getSharedPreferences("itcast",Context.MODE_WORLD_READABLE);其他应用要访问上面应用的preference,首先需要创立上面应用的Context,然后通过Context访问preference,访问preference时会在应用所在包下的shared_prefs目录找到preference:ContextotherAppsContext=createPackageContext("cn.itcast.action",Context.CONTEXT_IGNORE_SECURITY);SharedPreferencessharedPreferences=otherAppsContext.getSharedPreferences("itcast",Context.MODE_WORLD_READABLE);Stringname=sharedPreferences.getString("name","");intage=sharedPreferences.getInt("age",0);如果不通过创立Context访问其他应用的preference,可以以读取xml文件方式直接访问其他应用preference对应的xml文件,如:FilexmlFile=newFile(“/data/data/<packagename>/shared_prefs/itcast.xml”);//<packagename>应替换成应用的包名SQLite数据库除了可以使用文件或SharedPreferences存储数据,还可以选择使用SQLite数据库存储数据。在Android平台上,集成了一个嵌入式关系型数据库—SQLite,SQLite3支持NULL、INTEGER、REAL〔浮点数字〕、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*frompersonselect*frompersonorderbyiddescselectnamefrompersongroupbynamehavingcount(*)>1分页SQL与mysql类似,下面SQL语句获取5条记录,跳过前面3条记录select*fromAccountlimit5offset3或者select*fromAccountlimit3,5插入语句:insertinto表名(字段列表)values(值列表)。如:insertintoperson(name,age)values(‘Jack’,3)更新语句:update表名set字段名=值where条件子句。如:updatepersonsetname=‘Jack‘whereid=10删除语句:deletefrom表名where条件子句。如:deletefrompersonwhereid=10使用SQLiteDatabase操作SQLite数据库Android提供了一个名为SQLiteDatabase的类,该类封装了一些操作数据库的API,使用该类可以完成对数据进行添加(Create)、查询(Retrieve)、更新(Update)和删除(Delete)操作〔这些操作简称为CRUD〕。对SQLiteDatabase的学习,我们应该重点掌握execSQL()和rawQuery()方法。execSQL()方法可以执行insert、delete、update和CREATETABLE之类有更改行为的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语句中占位符参数的值,参数值在数组中的顺序要和占位符的位置对应。使用SQLiteDatabase操作SQLite数据库使用SQLiteDatabase操作SQLite数据库SQLiteDatabase的rawQuery()用于执行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[]{"%Jack%","4"});Cursor是结果集游标,用于对结果集进行随机访问,如果大家熟悉jdbc,其实Cursor与JDBC中的ResultSet作用很相似。使用moveToNext()方法可以将游标从当前行移动到下一行,如果已经移过了结果集的最后一行,返回结果为false,否那么为true。另外Cursor还有常用的moveToPrevious()方法〔用于将游标从当前行移动到上一行,如果已经移过了结果集的第一行,返回值为false,否那么为true〕、moveToFirst()方法〔用于将游标移动到结果集的第一行,如果结果集为空,返回值为false,否那么为true〕和moveToLast()方法〔用于将游标移动到结果集的最后一行,如果结果集为空,返回值为false,否那么为true〕。使用SQLiteDatabase操作SQLite数据库使用SQLiteDatabase操作SQLite数据库除了前面给大家介绍的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指的是各种常用的数据类型,如:String、Integer等。SQLiteDatabasedb=databaseHelper.getWritableDatabase();ContentValuesvalues=newContentValues();values.put("name","传智播客");values.put("age",4);longrowid=db.insert(“person”,null,values);//返回新添记录的行号,与主键id无关不管第三个参数是否包含数据,执行Insert()方法必然会添加一条记录,如果第三个参数为空,会添加一条除主键之外其他字段值为Null的记录。Insert()方法内部实际上通过构造insert语句完成数据的添加,Insert()方法的第二个参数用于指定空值字段的名称,相信大家对此参数会感到疑惑,此参数的作用是干嘛的?是这样的:如果第三个参数values为Null或者元素个数为0,Insert()方法必然要添加一条除了主键之外其它字段为Null值的记录,为了满足这条insert语句的语法,insert语句必须给定一个字段名,如:insertintoperson(name)values(NULL),倘假设不给定字段名,insert语句就成了这样:insertintoperson()values(),显然这不满足标准SQL的语法。对于字段名,建议使用主键之外的字段,如果使用了INTEGER类型的主键字段,执行类似insertintoperson(personid)values(NULL)的insert语句后,该主键字段值也不会为NULL。如果第三个参数values不为Null并且元素的个数大于0,可以把第二个参数设置为null。使用SQLiteDatabase操作SQLite数据库使用SQLiteDatabase操作SQLite数据库delete()方法的使用:SQLiteDatabasedb=databaseHelper.getWritableDatabase();db.delete("person","personid<?",newString[]{"2"});db.close();上面代码用于从person表中删除personid小于2的记录。update()方法的使用:SQLiteDatabasedb=databaseHelper.getWritableDatabase();ContentValuesvalues=newContentValues();values.put(“name”,“Jack”);//key为字段名,value为值db.update("person",values,"personid=?",newString[]{"1"});db.close();上面代码用于把person表中personid等于1的记录的name字段的值改为“Jack”。使用SQLiteDatabase操作SQLite数据库使用SQLiteDatabase操作SQLite数据库query()方法实际上是把select语句拆分成了假设干个组成局部,然后作为方法的输入参数:SQLiteDatabasedb=databaseHelper.getWritableDatabase();Cursorcursor=db.query("person",newString[]{"personid,name,age"},"namelike?",newString[]{"%Jack%"},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关键字后面的局部。使用SQLiteOpenHelper对数据库进行版本管理如果应用使用到了SQLite数据库,在用户初次使用软件时,需要创立应用使用到的数据库表结构及添加一些初始化记录,另外在软件升级的时候,也需要对数据表结构进行更新。在Android系统,为我们提供了一个名为SQLiteOpenHelper的类,该类用于对数据库版本进行管理,该类是一个抽象类,必须继承它才能使用。为了实现对数据库版本进行管理,SQLiteOpenHelper类有两种重要的方法,分别是onCreate(SQLiteDatabasedb)和onUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion)当调用SQLiteOpenHelper的getWritableDatabase()或者getReadableDatabase()方法获取用于操作数据库的SQLiteDatabase实例的时候,如果数据库不存在,Android系统会自动生成一个数据库,接着调用onCreate()方法,onCreate()方法在初次生成数据库时才会被调用,在onCreate()方法里可以生成数据库表结构及添加一些应用使用到的初始化数据。onUpgrade()方法在数据库的版本发生变化时会被调用,数据库的版本是由程序员控制的,假设数据库现在的版本是1,由于业务的需要,修改了数据库表的结构,这时候就需要升级软件,升级软件时希望更新用户里的数据库表结构,为了实现这一目的,可以把原来的数据库版本设置为2(有同学问设置为3行不行?当然可以,如果你愿意,设置为100也行),并且在onUpgrade()方法里面实现表结构的更新。当软件的版本升级次数比较多,这时在onUpgrade()方法里面可以根据原版号和目标版本号进行判断,然后作出相应的表结构及数据更新。getWritableDatabase()和getReadableDatabase()方法都可以获取一个用于操作数据库的SQLiteDatabase实例。但getWritableDatabase()方法以读写方式翻开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘假设使用的是getWritableDatabase()方法就会出错。getReadableDatabase()方法先以读写方式翻开数据库,如果数据库的磁盘空间满了,就会翻开失败,当翻开失败后会继续尝试以只读方式翻开数据库。使用SQLiteOpenHelper对数据库进行版本管理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("DROPTABLEIFEXISTSperson");onCreate(db);}}上面onUpgrade()方法在数据库版本每次发生变化时都会把用户上的数据库表删除,然后再重新创立。一般在实际工程中是不能这样做的,正确的做法是在更新数据库表结构时,还要考虑用户存放于数据库中的数据不会丧失。使用SQLiteOpenHelper获取用于操作数据库的SQLiteDatabase实例publicclassDatabaseHelperextendsSQLiteOpenHelper{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()方法得到的都是同一实例。使用事务操作SQLite数据库使用SQLiteDatabase的beginTransaction()方法可以开启一个事务,程序执行到endTransaction()方法时会检查事务的标志是否为成功,如果为成功那么提交事务,否那么回滚事务。当应用需要提交事务,必须在程序执行到endTransaction()方法之前使用setTransactionSuccessful()方法设置事务的标志为成功,如果不调用setTransactionSuccessful()方法,默认会回滚事务。使用例子如下:
SQLiteDatabasedb=....;db.beginTransaction();//开始事务try{db.execSQL("insertintoperson(name,age)values(?,?)",newObject[]{"Jack",4});db.execSQL("updatepersonsetname=?wherepersonid=?",newObject[]{"Jack",1});db.setTransactionSuccessful();//调用此方法会在执行到endTransaction()时提交当前事务,如果不调用此方法会回滚事务}finally{db.endTransaction();//由事务的标志决定是提交事务,还是回滚事务}db.close();上面两条SQL语句在同一个事务中执行。ContentProvider使用ContentProvider共享数据当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据;采用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进行配置,为了能让其他应用找到该ContentProvider,ContentProvider采用了authorities〔主机名/域名〕对它进行唯一标识,你可以把ContentProvider看作是一个网站〔想想,网站也是提供数据者〕,authorities就是他的域名:<manifest....><applicationandroid:icon="@drawable/icon"android:label="@string/app_name"><providerandroid:name=".PersonContentProvider"android:authorities="vider.personprovider"/></application></manifest>注意:一旦应用继承了ContentProvider类,后面我们就会把这个应用称为ContentProvider〔内容提供者〕。Uri介绍Uri介绍Uri代表了要操作的数据,Uri主要包含了两局部信息:1》需要操作的ContentProvider,2》对ContentProvider中的什么数据进行操作,一个Uri由以下几局部组成:ContentProvider〔内容提供者〕的scheme已经由Android所规定,scheme为:content://主机名〔或叫Authority〕用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。路径〔path〕可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:要操作person表中id为10的记录,可以构建这样的路径:/person/10要操作person表中id为10的记录的name字段,person/10/name要操作person表中的所有记录,可以构建这样的路径:/person要操作xxx表中的记录,可以构建这样的路径:/xxx当然要操作的数据不一定来自数据库,也可以是文件等他存储方式,如下:要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:Uriuri=Uri.parse("content://vider.personprovider/person")
UriMatcher类使用介绍因为Uri代表了要操作的数据,所以我们很经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher和ContentUris。掌握它们的使用,会便于我们的开发工作。UriMatcher类用于匹配Uri,它的用法如下:首先第一步把你需要匹配Uri路径全部给注册上,如下://常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码UriMatchersMatcher=newUriMatcher(UriMatcher.NO_MATCH);//如果match()方法匹配路径,返回匹配码为1sMatcher.addURI(“vider.personprovider”,“person”,1);//添加需要匹配uri,如果匹配就会返回匹配码//如果match()方法匹配路径,返回匹配码为2sMatcher.addURI(“vider.personprovider”,“person/#”,2);//#号为通配符switch(sMatcher.match(Uri.parse("content://vider.personprovider/person/10"))){case1break;case2break;default://不匹配
break;}注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,假设匹配路径,返回的匹配码为1ContentUris类使用介绍ContentUris类用于获取Uri路径后面的ID局部,它有两个比较实用的方法:withAppendedId(uri,id)用于为路径加上ID局部:Uriuri=Uri.parse("content://vider.personprovider/person")UriresultUri=ContentUris.withAppendedId(uri,10);//生成后的Uri为:parseId(uri)方法用于从路径中获取ID局部:Uriuri=Uri.parse("content://vider.personprovider/person/10")longpersonid=ContentUris.parseId(uri);//获取的结果为:10使用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类型字符串应该以开头,例如:要得到所有person记录的Uri为,那么返回的MIME类型字符串应该为:“vnd.android.cursor.dir/person”。如果要操作的数据属于单一数据,那么MIME类型字符串应该以开头,例如:得到id为10的person记录,Uri为,那么返回的MIME类型字符串应该为:“vnd.android.cursor.item/person”。使用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://vider.personprovider/person/10”),那么将会对主机名为的ContentProvider进行操作,操作的数据为person表中id为10的记录。使用ContentResolver操作ContentProvider中的数据使用ContentResolver对ContentProvider中的数据进行添加、删除、修改和查询操作:ContentResolverresolver=getContentResolver();Uriuri=Uri.parse("content://vider.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));}//把id为1的记录的name字段值更改新为limingContentValuesupdateValues=newContentValues();updateValues.put("name","liming");UriupdateIdUri=ContentUris.withAppendedId(uri,2);resolver.update(updateIdUri,updateValues,null,null);//删除id为2的记录UrideleteIdUri=ContentUris.withAppendedId(uri,2);resolver.delete(deleteIdUri,null,null);为应用添加新的Activity第一步:新建一个继承Activity的类,如:NewActivitypublicclassNewActivityextendsActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState); //这里可以使用setContentView(R.layout.xxx)显示某个视图....}}第二步:需要在功能清单AndroidManifest.xml文件中添加进上面Activity配置代码(红色局部):<manifestxmlns:android="://schemas.android/apk/res/android"package="cn.itcast.action"android:versionCode="1"android:versionName="1.0"><applicationandroid:icon="@drawable/icon"android:label="@string/app_name">..... <activityandroid:name=".NewActivity"android:label="新activity的页面标题"/></application>...</manifest>android:name属性值的前面加了一个点表示NewActivity是当前包下的类,如果类在应用的当前包下,可以省略点符号,如果类在应用的子包下必须加点,如:NewActivity类在包下可以这样写:<activityandroid:name=“.user.NewActivity“/>翻开新的Activity,不传递参数在一个Activity中可以使用系统提供的startActivity(Intentintent)方法翻开新的Activity,在翻开新的Activity前,你可以决定是否为新的Activity传递参数:第一种:翻开新的Activity,不传递参数publicclassMainActivityextendsActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){ ....... Buttonbutton=(Button)this.findViewById(R.id.button);button.setOnClickListener(newView.OnClickListener(){//点击该按钮会翻开一个新的Activity publicvoidonClick(Viewv){//新建一个显式意图,第一个参数为当前Activity类对象,第二个参数为你要翻开的Activity类 startActivity(newIntent(MainActivity.this,NewActivity.class)); }});}}翻开新的Activity,并传递假设干个参数给它第二种:翻开新的Activity,并传递假设干个参数给它:publicclassMainActivityextendsActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){ ....... button.setOnClickListener(newView.OnClickListener(){//点击该按钮会翻开一个新的Activity publicvoidonClick(Viewv){ Intentintent=newIntent(MainActivity.this,NewActivity.class)Bundlebundle=newBundle();//该类用作携带数据bundle.putString("name","传智播客");bundle.putInt("age",4);intent.putExtras(bundle);//附带上额外的数据startActivity(intent); }});}}在新的Activity中接收前面Activity传递过来的参数:publicclassNewActivityextendsActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){ ........ Bundlebundle=this.getIntent().getExtras(); Stringname=bundle.getString("name"); intage=bundle.getInt("age");}}Bundle类的作用Bundle类用作携带数据,它类似于Map,用于存放key-value名值对形式的值。相对于Map,它提供了各种常用类型的putXxx()/getXxx()方法,如:putString()/getString()和putInt()/getInt(),putXxx()用于往Bundle对象放入数据,getXxx()方法用于从Bundle对象里获取数据。Bundle的内部实际上是使用了HashMap<String,Object>类型的变量来存放putXxx()方法放入的值:publicfinalclassBundleimplementsParcelable,Cloneable{......
Map<String,Object>mMap;publicBundle(){mMap=newHashMap<String,Object>();......}publicvoidputString(Stringkey,Stringvalue){mMap.put(key,value);}publicStringgetString(Stringkey){
Objecto=mMap.get(key);return(String)o;
........//类型转换失败后会返回null,这里省略了类型转换失败后的处理代码}}在调用Bundle对象的getXxx()方法时,方法内部会从该变量中获取数据,然后对数据进行类型转换,转换成什么类型由方法的Xxx决定,getXxx()方法会把转换后的值返回。为Intent附加数据的两种写法第一种写法,用于批量添加数据到Intent:Intentintent=newIntent();Bundlebundle=newBundle();//该类用作携带数据bundle.putString("name","传智播客");intent.putExtras(bundle);//为意图追加额外的数据,意图原来已经具有的数据不会丧失,但key同名的数据会被替换第二种写法:这种写法的作用等价于上面的写法,只不过这种写法是把数据一个个地添加进Intent,这种写法使用起来比较方便,而且只需要编写少量的代码。Intentintent=newIntent();intent.putExtra("name","传智播客");Intent提供了各种常用类型重载后的putExtra()方法,如:putExtra(Stringname,Stringvalue)、putExtra(Stringname,longvalue),在putExtra()方法内部会判断当前Intent对象内部是否已经存在一个Bundle对象,如果不存在就会新建Bundle对象,以后调用putExtra()方法传入的值都会存放于该Bundle对象,下面是Intent的putExtra(Stringname,Stringvalue)方法代码片断:publicclassIntentimplementsParcelable{privateBundlemExtras;publicIntentputExtra(Stringname,Stringvalue){if(mExtras==null){mExtras=newBundle();}mExtras.putString(name,value);returnthis;}得到新翻开Activity关闭后返回的数据如果你想在Activity中得到新翻开Activity关闭后返回的数据,你需要使用系统提供的startActivityForResult(Intentintent,intrequestCode)方法翻开新的Activity,新的Activity关闭后会向前面的Activity传回数据,为了得到传回的数据,你必须在前面的Activity中重写onActivityResult(intrequestCode,intresultCode,Intentdata)方法:publicclassMainActivityextendsActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){ ....... Buttonbutton=(Button)this.findViewById(R.id.button);button.setOnClickListener(newView.OnClickListener(){//点击该按钮会翻开一个新的Activity publicvoidonClick(Viewv){ //第二个参数为请求码,可以根据业务需求自己编号 startActivityForResult(newIntent(MainActivity.this,NewActivity.class),1); }});}//第一个参数为请求码,即调用startActivityForResult()传递过去的值//第二个参数为结果码,结果码用于标识返回数据来自哪个新Activity@OverrideprotectedvoidonActivityResult(intrequestCode,intresultCode,Intentdata){ Stringresult=data.getExtras().getString(“result”));//得到新Activity关闭后返回的数据}}当新Activity关闭后,新Activity返回的数据通过Intent进行传递,android平台会调用前面Activity的onActivityResult()方法,把存放了返回数据的Intent作为第三个输入参数传入,在onActivityResult()方法中使用第三个输入参数可以取出新Activity返回的数据。请求码的作用使用startActivityForResult(Intentintent,intrequestCode)方法翻开新的Activity,我们需要为startActivityForResult()方法传入一个请求码(第二个参数)。请求码的值是根据业务需要由自已设定,用于标识请求来源。例如:一个Activity有两个按钮,点击这两个按钮都会翻开同一个Activity,不管是那个按钮翻开新Activity,当这个新Activity关闭后,系统都会调用前面Activity的onActivityResult(intrequestCode,intresultCode,Intentdata)方法。在onActivityResult()方法如果需要知道新Activity是由那个按钮翻开的,并且要做出相应的业务处理,这时可以这样做:@OverridepublicvoidonCreate(BundlesavedInstanceState){....button1.setOnClickListener(newView.OnClickListener(){ publicvoidonClick(Viewv){ startActivityForResult(newIntent(MainActivity.this,NewActivity.class),1); }});button2.setOnClickListener(newView.OnClickListener(){ publicvoidonClick(Viewv){ startActivityForResult(newIntent(MainActivity.this,NewActivity.class),2); }});@OverrideprotectedvoidonActivityResult(intrequestCode,intresultCode,Intentdata){switch(requestCode){case1://来自按钮1的请求,作相应业务处理case2: //来自按钮2的请求,作相应业务处理}}}结果码的作用在一个Activity中,可能会使用startActivityForResult()方法翻开多个不同的Activity处理不同的业务,当这些新Activity关闭后,系统都会调用前面Activity的onActivityResult(intrequestCode,intresultCode,Intentdata)方法。为了知道返回的数据来自于哪个新Activity,在onActivityResult()方法中可以这样做(ResultActivity和NewActivity为要翻开的新Activity):publicclassResultActivityextendsActivity{.....ResultActivity.this.setResult(1,intent);ResultActivity.this.finish
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 辰阳明德小学S版四年级语文下册教案(表格式)
- 博大精深的中华文化教学参考教案新人教必修
- 《萝卜回来了》教学设计
- 《物流运输实务》电子教案
- 旅游景区导游聘用合同范本
- 养猪场租赁合同:养殖产业转型
- 医疗美容医师聘用合同
- 健身房宿舍管理员招聘启事
- 咖啡馆冬季空调租赁合同范文
- 影剧院指示牌安装协议
- 2023届高考写作指导:漫画作文 课件24张
- 软件系统项目监理报告
- 社会学概论课件十四讲社会问题
- 2023年多媒体应用设计师真题题库总结
- YS/T 1022-2015偏钒酸铵
- GB/T 9574-2001橡胶和塑料软管及软管组合件试验压力、爆破压力与设计工作压力的比率
- 马工程《刑法学(下册)》教学课件 第19章 破坏社会主义市场经济秩序罪
- GB/T 1740-2007漆膜耐湿热测定法
- GB/T 1536-2021菜籽油
- 校园突发事件及危机应对
- 《必修上第六单元》教案【高中语文必修上册】
评论
0/150
提交评论