版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
数据存储CONTENTS目录02
文
件
存
储01
SharedPreferences03
SQLite04
ContentProvider05
综合实例无论是桌面应用程序还是Android手机应用程序,都会涉及数据的存储。本章将详细介绍在Android中存储数据的相关知识。在Android中应用程序存储的数据(包括文件)都属于应用程序私有,但同时也提供了ContentProviders(数据共享),方便应用程序将私有的数据分享给其他程序使用。其中数据存储方式共分为5种,分别为:
SharedPreferences。
内部存储(InternalStorage)。
外部存储(ExternalStorage)。
SQLite数据库存储。
网络存储。其中,网络存储在本质上是对网络资源的获取和访问,其相关内容会在网络编程章节中进行介绍,本章主要介绍前4种,其中内部存储和外部存储统称为文件存储。此外,Android系统框架提供了ContentProvider来实现各种应用程序间持久化数据的共享。SharedPreferences017.1.1SharedPreferences简介SharedPreferences主要用于存储系统的配置信息,类似于Windows下常用的.ini文件,例如上次登录的用户名、上次最后设置的信息等,通过保存上一次用户所做的修改或者自定义参数设定,当再次启动程序后依然保持原有设置。它是用键值对的方式存储的,方便管理写入和读取。使用SharedPreferences的步骤如下:
获取Preferences。每个Activity默认都有一个SharedPreferences对象,获取SharedPreferences对象的方法有两种:SharedPreferencesgetSharedPreferences(Stringname,intmode)。使用该方法获取name指定的SharedPreferences对象,并获取对该SharedPreferences对象的读写控制权。当应用程序中可能使用到多个SharedPreferences时使用该方法。SharedPreferencesgetPreferences(intmode)。当应用程序中仅需要一个SharedPreferences对象时,使用该方法获取当前Activity对应的SharedPreferences,而不需要指定SharedPreferences的名字。其中,参数mode有4种取值,分别是:
MODE_PRIVATE默认方式,只能被创建的应用程序或者与创建的应用程序具有相同用户ID的应用程序访问。
MODE_WORLD_READABLE允许其他应用程序对该SharedPreferences文件进行读操作。
MODE_WORLD_WRITEABLE允许其他应用程序对该SharedPreferences文件进行写操作。
MODE_MULTI_PROCESS在多进程应用程序中,当多个进程都对同一个SharedPreferences进行访问时,该文件的每次修改都会被重新核对。
调用edit()方法获取SharedPreferences.Editor,SharedPreferences通过该接口对其内容进行更新。
通过SharedPreferences.Editor接口提供的put方法对SharedPreferences进行更新。例如使用putBoolean(Stringkey,booleanvalue)、putFloat(Stringkey,floatvalue)等方法将相应数据类型的数据与其key对应起来。
调用SharedPreferences.Editor的commit()方法将更新提交到SharedPreferences中。7.1.2使用SharedPreferences
实例SharedPreferencesDemo演示了SharedPreferences对象的使用方法。该实例的运行效果如图7.1所示。当用户在该实例运行时,在文本框中输入电话号码和所在城市,例beijing,单击回退按钮退出应用程序时,该应用程序将相关信息写入其对应的SharedPreferences中。当用户再次启动该应用程序时,之前填写到文本框内的信息会被从SharedPreferences中读取并显示出来,以方便用户修改。图7.1
SharedPreferencesDemo界面实例SharedPreferencesDemo中的布局文件main.xml中放置了三个TextView和两个EditText,其中两个EditText按照TextView的要求输入电话号码和城市。其代码如下:<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="vertical"><TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:text="使用SharedPreferences存储程序信息"/> <TextView android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="您的电话号码:"/> <EditText android:id="@+id/phone_text" android:layout_width="fill_parent"android:layout_height="wrap_content"android:hint="输入电话号码"/> <TextView android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="您所在的城市"/> <EditText android:id="@+id/city_text" android:layout_width="fill_parent"android:layout_height="wrap_content"android:hint="输入城市名称"/></LinearLayout>实例SharedPreferencesDemo中AndroidManifest.xml的代码如下:<?xmlversion="1.0"encoding="utf-8"?><manifestxmlns:android="/apk/res/android"package="introduction.android.SharedPreferencesDemo"android:versionCode="1"android:versionName="1.0"><uses-sdkandroid:minSdkVersion="14"/><applicationandroid:icon="@drawable/ic_launcher"android:label="@string/app_name"><activityandroid:name=".SharedPreferencesDemo"android:label="@string/app_name"><intent-filter><actionandroid:name="ent.action.MAIN"/><categoryandroid:name="ent.category.LAUNCHER"/></intent-filter></activity></application></manifest>实例SharedPreferencesDemo中SharedPreferencesDemo.java的代码如下:packageintroduction.android.SharedPreferencesDemo;importjavax.security.auth.PrivateCredentialPermission;importintroduction.android.SharedPreferencesDemo.R;importandroid.app.Activity;importandroid.content.SharedPreferences;importandroid.os.Bundle;importandroid.widget.EditText;publicclassSharedPreferencesDemoextendsActivity{privateEditTextphoneText,cityText;privateStringphone,city;publicstaticfinalStringSET_INFO="SET_Info";publicstaticfinalStringPHONE="PHONE";publicstaticfinalStringCITY="CITY";@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);phoneText=(EditText)findViewById(R.id.phone_text);cityText=(EditText)findViewById(R.id.city_text);/*获取SharedPreferences对象*/SharedPreferencessetinfo=getPreferences(Activity.MODE_PRIVATE);/*取出保存的电话号码和地址信息*/phone=setinfo.getString(PHONE,"");city=setinfo.getString(CITY,"");/*将取出的信息分别放在对应的EditText中*/phoneText.setText(phone);cityText.setText(city);}@OverrideprotectedvoidonStop(){ SharedPreferencessetinfo=getPreferences(Activity.MODE_PRIVATE);setinfo.edit().putString(PHONE,phoneText.getText().toString()).putString(CITY,cityText.getText().toString()).commit();super.onStop();}}该Activity在启动时通过onCreate()方法从其SharedPreferences中获取相应数据,在onStop()方法中将相应数据写入SharedPreferences中,其中:SharedPreferencessetinfo=getPreferences(Activity.MODE_PRIVATE);用于获取当前Activity默认的SharedPreferences对象,该对象没有名字。当然,也可以通过getSharedPreferences(Stringname,intmode)方法来创建并获取一个带有名字的SharedPreferences。当该SharedPreferences被创建后,可以在应用程序的包路径下,即data/data/<yourpackagename>/shared_prefs文件夹下找到该文件。文
件
存
储027.2.1文件存储方式简介Android的文件存储方式分为两种:内部存储和外部存储。1.内部存储内部存储是指将应用程序的数据以文件方式存储到设备内存中。以内部存储方式存储的文件属于其所创建的应用程序私有,其他应用程序无权进行操作。当创建的应用程序被卸载时,其内部存储的文件也随之被删除。当内部存储器的存储空间不足时,缓存文件可能会被删除以释放空间,因此,缓存文件是不可靠的。当使用缓存文件时,自己应该维护好缓存文件,并且将缓存文件限制在特定大小之内。使用文件存储信息时,使用openFileOutput和openFileInput进行文件的读写,这跟Java中的I/O程序很类似。创建并写内部存储文件的步骤如下:
通过Context.openFileOutput(Stringname,intmode)方法打开文件并设定读写方式,返回FileOutputStream。其中,参数mode取值为:
MODE_PRIVATE,默认访问方式,文件仅能被创建应用程序访问。
MODE_APPEND,若文件已经存在,则在文件末尾继续写入数据,而不抹掉文件原有内容。
MODE_WORLD_READABLE,允许该文件被其他应用程序执行读取内容操作。
MODE_WORLD_WRITEABLE,允许该文件被其他应用程序执行写操作。
调用FileOutputStream.write()方法写入数据。
调用FileOutputStream.close()方法关闭输出流,完成写操作。内部存储文件的写文件示例代码如下:StringFILENAME="hello_file";
Stringstring="helloworld!";
FileOutputStreamfos=openFileOutput(FILENAME,Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();2.外部存储外部存储是指将文件存储到一些外部存储设备上,例如SD卡或者设备内嵌的存储卡,属于永久性的存储方式。外部存储的文件不被某个应用程序所特有,可以被其他应用程序共享,当将该外部存储设备连接到计算机上时,这些文件可以被浏览、修改和删除。因此,这种存储方式不具有安全性。由于外部存储器可能处于被移除、连接到计算机、丢失、只读或者其他各种状态,因此在使用外部存储之前,必须使用Environment.getExternalStorageState()方法来确认外部存储器是否可用。验证外部存储器是否可读写的代码如下:booleanmExternalStorageAvailable=false;
booleanmExternalStorageWriteable=false;
Stringstate=Environment.getExternalStorageState();
if(Environment.MEDIA_MOUNTED.equals(state)){
//外部存储器可读写
mExternalStorageAvailable=mExternalStorageWriteable=true;
}elseif(Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)){
//外部存储器可读不可写
mExternalStorageAvailable=true;
mExternalStorageWriteable=false;
}else{
//外部存储器不可读写,处于其他状态
mExternalStorageAvailable=mExternalStorageWriteable=false;
}此外,在程序开发过程中还可以使用缓存文件(Cache),内部存储和外部存储都可以用于保存缓存文件。当存储器的存储空间不足时,缓存文件可能会被删除以释放空间。因此,缓存文件是不可靠的。当使用缓存文件时,应该自己维护好缓存文件,并且将缓存文件限制在特定大小之内。7.2.2使用文件存储功能
实例FileDemo演示了使用文件存储的功能,其运行效果如图7.2所示。该实例将文本框中输入的内容存储到名为text的文件中。当该应用程序再次启动时,可以从text文件写入的内容中读取并显示出来。本实例使用内部存储方式,读者可以在data/data/<yourpackagename>/files目录下找到名为text的文件。图7.2FileDemo界面实例FileDemo的布局文件main.xml中放置了两个TextView、一个EditText和两个Button,其代码如下:<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="vertical"><TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:text="使用文件存储程序信息"/> <TextView android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="输入您存储的信息"/> <EditText android:id="@+id/phone_text" android:layout_width="fill_parent"android:layout_height="wrap_content"android:hint="输入保存的信息"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/SaveButton" android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="保存信息"/> <Button android:id="@+id/LoadButton" android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="读取信息"/> </LinearLayout></LinearLayout>实例FileDemo中AndroidManifest.xml文件的代码如下:<?xmlversion="1.0"encoding="utf-8"?><manifestxmlns:android="/apk/res/android"package="introduction.android.fileDemo"android:versionCode="1"android:versionName="1.0"><uses-sdkandroid:minSdkVersion="34"android:targetSdkVersion=”36”/><applicationandroid:icon="@drawable/ic_launcher"android:label="@string/app_name"><activityandroid:name="introduction.android.fileDemo.FileDemo"android:label="@string/app_name"><intent-filter><actionandroid:name="ent.action.MAIN"/><categoryandroid:name="ent.category.LAUNCHER"/></intent-filter></activity></application></manifest>实例FileDemo中FileDemo.java的代码如下:publicclassFileDemoextendsActivity{privateEditTextSaveText;privateButtonSaveButton,LoadButton;@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);SaveText=(EditText)findViewById(R.id.phone_text);SaveButton=(Button)findViewById(R.id.SaveButton);LoadButton=(Button)findViewById(R.id.LoadButton);SaveButton.setOnClickListener(newButtonListener());LoadButton.setOnClickListener(newButtonListener());}privateclassButtonListenerimplementsOnClickListener{ @Override publicvoidonClick(Viewv){ switch(v.getId()){ /*保存数据*/ caseR.id.SaveButton: Stringsaveinfo=SaveText.getText().toString().trim(); FileOutputStreamfos; try{ fos=openFileOutput("text",MODE_APPEND); fos.write(saveinfo.getBytes()); fos.close(); }catch(Exceptione){ e.printStackTrace(); } Toast.makeText(FileDemo.this,"数据保存成功",Toast.LENGTH_LONG).show(); break; /*读取数据*/ caseR.id.LoadButton: Stringget=""; try{ FileInputStreamfis=openFileInput("text"); byte[]buffer=newbyte[fis.available()]; fis.read(buffer); get=newString(buffer); }catch(Exceptione){ e.printStackTrace(); } Toast.makeText(FileDemo.this,"保存的数据是:"+get,Toast.LENGTH_LONG).show(); break; default: break; } } }}SQLite037.3.1SQLite数据库简介前面我们介绍了用SharedPreferences和文件存储信息的方法,但是当频繁大量地使用数据存储时,就要用到数据库来管理信息数据。在Android中,我们使用SQLite数据库,在应用中也常常会用到SQLite来存储、管理、维护数据,本节将详细介绍SQLite的使用方法。Android通过SQLite数据库引擎来实现结构化数据存储。Android系统提供对SQLite数据库的完全支持,在数据库应用程序中,任何类都可以通过名字对已创建的数据库进行访问,但是在应用程序之外不可以。SQLite是一个轻量级数据库,第一个版本诞生在2000年5月,其遵守ACID的关联式数据库管理系统,最初就是为嵌入式设计的,其占用资源非常少,在内存中只需要占用几百千字节(KB)的存储空间,这也是Android采用SQLite数据库的重要原因之一。同时,SQLite还支持事务处理功能,根据相关资料可知,SQLite的处理速度比MySQL、PostgreSQL等著名的开源数据库管理系统更快。另外,SQLite数据库不像其他的数据库(如Oracle),它没有服务器进程,SQLite通过文件保存数据库,该文件是跨平台的,可以自由复制。一个文件就是一个数据库,数据库名称即文件名;数据库里面可以包含多个表格,在每个表格中可以添加多条记录,但记录没有名称;记录可以由多个字段组成,每个字段都要有相对应的值,每个值都必须指定类型。基于SQLite自身的先天优势,其在嵌入式领域中得到了广泛应用。SQLite支持SQL语言,由SQL编译器、内核、后端以及附件组成。SQLite通过利用虚拟机和虚拟数据库引擎(VDBE),使调试、修改和扩展SQLite的内核变得更加方便。Android在运行时(run-time)集成了SQLite,所以每个Android应用程序都可以使用SQLite数据库,在Android开发中使用SQLite相当简单。但是,由于JDBC会消耗太多的系统资源,所以JDBC对于手机这种内存受限的设备来说并不合适。因此,Android提供了一些新的API来使用SQLite数据库,在Android开发中,我们需要学习使用这些API。另外需要了解的是,数据库存储在data/<项目文件夹>/databases/目录下。创建SQLite数据库Android系统推荐的创建SQLite数据库的方法是创建实现SQLiteOpenHelper接口的子类,并且重写onCreate()方法,在该方法中执行用于创建SQLite数据库的命令。所创建的数据库被放置在/data/data/<yourpackagename>/database目录下,例如:publicclassDictionaryOpenHelperextendsSQLiteOpenHelper{
privatestaticfinalintDATABASE_VERSION=2;
privatestaticfinalStringDICTIONARY_TABLE_NAME="dictionary";
//创建数据库的SQL语句privatestaticfinalStringDICTIONARY_TABLE_CREATE=
"CREATETABLE"+DICTIONARY_TABLE_NAME+"("+
KEY_WORD+"TEXT,"+
KEY_DEFINITION+"TEXT);";
DictionaryOpenHelper(Contextcontext){
super(context,DATABASE_NAME,null,DATABASE_VERSION);
}
@Override
publicvoidonCreate(SQLiteDatabasedb){
db.execSQL(DICTIONARY_TABLE_CREATE);
//执行SQL语句
}
}获取数据库对象通过实现SQLiteOpenHelper接口的类的对象,调用getWritableDatabase()和getReadableDatabase()方法,可以返回所创建数据库的SQLiteDatabase对象。对数据库进行操作SQLiteDatabase对象提供了对数据库进行操作的一系列方法,例如query、insert、delete、update等,进而对SQLite数据库进行读写等操作。操作返回对象对数据库的查询操作会返回一个Cursor对象,通过该对象可以从返回的结果中读取出行、列信息。7.3.2SQLite数据库操作Android提供了创建和使用SQLite数据库的API。AndroidSDK提供了一系列对SQLite数据库进行操作的类和接口,这里我们简单介绍一下。
SQLiteDatabase类。SQLiteDatabase是一个数据库访问类,此类封装了一系列数据库操作的API,使其可以对数据进行CRUD操作,即添加、查询、更新、删除等。一些常用的操作数据库的方法如表7.1所示。表7.1
SQLiteDatabase常用方法方法名称方法描述openOrCreateDatabase(Stringpath,SQLiteDatabase.CursorFactoryfactory)打开或创建数据库insert(Stringtable,StringnullColumnHack,ContentValuesvalues)添加一条记录delete(Stringtable,StringwhereClause,String[]whereArgs)删除一条记录query(Stringtable,String[]columns,Stringselection,String[]selectionArgs,StringgroupBy,Stringhaving,StringorderBy)查询一条记录update(Stringtable,ContentValuesvalues,StringwhereClause,String[]whereArgs)修改记录execSQL(Stringsql)执行一条SQL语句close()关闭数据库
SQLiteOpenHelper类。SQLiteOpenHelper是一个抽象类,用来创建和版本更新。SQLiteOpenHelper的子类通过getReadableDatabase()和getWritableDatabase()方法来获取SQLiteDatabase实例对象,并保证以同步方式访问。通常情况下,getReadableDatabase()和getWritableDatabase()都是创建或者打开一个可写数据库,并返回相同的对象。只有在某些情况下,例如磁盘空间满了,或者数据库只能以只读方式打开的时候,getReadableDatabase()方法才会以查询方式打开数据库。其一般的用法是定义一个类继承之,并实现其抽象方法来创建和更新数据库,其常见的方法如表7.2所示。表7.2
SQLiteOpenHelper常用方法方法名称方法描述SQLiteOpenHelper(Contextcontext,Stringname,CursorFactoryfactory,intversion)构造方法,一般是要传递一个要创建的数据库名称onCreate(SQLiteDatabasedb)创建数据库时调用onUpdate(SQLiteDatabasedb,intoldVersion,intnewVersion)版本更新时调用getReadableDatabase()创建或打开一个只读数据库getWritableDatabase()创建或打开一个读写数据库
Cursor接口。Cursor是一个游标接口,在数据库中使用时作为返回值,相当于结果集ResultSet。它提供了遍历查询结果的方法。Cursor游标的一些常用方法如表7.3所示。表7.3
Cursor游标常用方法方法名称方法描述close()关闭游标,释放资源copyStringToBuffer(intcolumnIndex,CharArrayBufferbuffer)在缓冲区中检索请求的列的文本,并将其存储getColumnCount()返回所有列的总数getColumnIndex(StringcolumnName)返回指定列的名称,如果不存在,就返回-1getColumnIndexOrThrow(StringcolumnName)从零开始返回指定列的名称,如果不存在,将抛出异常getColumnName(intcolumnIndex)从给定的索引返回列名getColumnNames()返回一个字符串数组的列名getCount()返回Cursor中的行数moveToFirst()移动光标到第一行moveToLast()移动光标到最后一行moveToNext()移动光标到下一行moveToPosition(intposition)移动光标到一个绝对的位置moveToPrevious()移动光标到上一行这些方法的使用可以通过创建数据库、创建表和执行SQL语句的过程一一进行介绍。
打开或创建数据库。openOrCreateDatabase()方法会自动检测要打开的数据库是否存在,如果存在就打开,否则创建一个数据库。若该方法运行成功,则返回一个SQLiteDatabase对象,否则抛出异常FileNotFoundException。下面为创建名为“sie.db”的数据库的代码:SQLiteDatabasedatabase=SQLiteDatabase.openOrCreateDatabase("/data/data/sie.db",null);
创建数据表。使用SQLiteDatabase的execSQL()方法执行SQL语句,便能创建一个表。下面创建一个表,其中有三个属性:_id为主键并自动增加,name为姓名,number为编号,相关代码如下:Stringtable="createtablesietexttable(_idintegerprimarykeyautoincrement,nametext,numbertext)";database.execSQL(table);
插入数据。使用SQLiteDatabase的insert(Stringtable,StringnullColumnHack,ContentValuesvalues)方法,第一个参数是表名称,第二个参数是空列的默认值,第三个参数是ContentValues封装的列的名称和对应的列值,代码如下:ContentValuesvalues=newContentValues(); values.put("name","sietext01"); values.put("number","001"); database.insert("table",null,values);
删除数据。使用SQLiteDatabase的delete(Stringtable,StringwhereClause,String[]whereArgs)方法,第一个参数是表的名称,第二个参数是删除条件,第三个参数是条件值数组。
修改数据。使用SQLiteDatabase的update(Stringtable,ContentValuesvalues,StringwhereClause,String[]whereArgs)方法,第一个参数是表名称,第二个参数是更新行和列的ContentValues类型的键值对,第三个参数是更新条件,第四个参数是更新的条件数组。此外,上述三种能够引起数据库数据改变的操作,都可以通过SQLiteDatabase的execSQL()方法来完成。
查询数据。在Android中通过Cursor类来实现,使用SQLiteDatabase.query()方法会得到一个Cursor对象,Cursor用于指向查询结果中的记录。下面使用Cursor查询数据库中的数据,代码如下:Cursorcursor=database.query("table",null,null,null,null,null,null); /*判断游标是否为空*/ if(cursor.moveToFirst()){ for(inti=0;i<cursor.getCount();i++){ cursor.moveToNext(); //获得ID intid=cursor.getInt(0); //获得用户名
Stringname=cursor.getString(1); //获得编号
Stringnumber=cursor.getString(2); } }SQLiteOpenHelper类是SQLiteDataBase的帮助类,这个类主要用于打开或者创建数据库,并返回数据库对象,同时对数据库的版本进行管理。并且它是一个抽象类,需要继承它并实现里面的两个抽象方法:
onCreate(SQLiteDatabase)。在数据库第一次生成的时候会调用这个方法,一般在这个方法中生成数据库表。
onUpgrade(SQLiteDatabase,int,int)。当数据库需要升级的时候,系统会主动调用这个方法。一般在这个方法中删除原有数据表,并建立新的数据表。7.3.3SQLite数据库操作实例实例MyDbDemo演示了使用SQLiteOpenHelper和SQLiteDatabase对数据库进行操作的过程,其运行效果如图7.3所示。图7.3
MyDbDemo界面实例MyDbDemo使用SQLiteOpenHelper对象建立了数据库文件“mydb”,通过SQLiteDatabase对象对该数据库进行数据的查询、插入、修改和删除操作,并显示到ListView组件中。实例MyDbDemo的运行界面实际上由两个XML文件组成,分别是main.xml和listview.xml。其中main.xml文件的代码如下:<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="vertical"><LinearLayoutandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:addStatesFromChildren="true"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="姓名"android:textColor="?android:attr/textColorSecondary"/><EditTextandroid:id="@+id/et_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:singleLine="true"/></LinearLayout><LinearLayoutandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:addStatesFromChildren="true"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="年龄"android:textColor="?android:attr/textColorSecondary"/><EditTextandroid:id="@+id/et_age"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:singleLine="true"/></LinearLayout><LinearLayoutandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:addStatesFromChildren="true"android:gravity="center"><Buttonandroid:id="@+id/bt_add"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="添加"android:onClick="addbutton"></Button><Buttonandroid:id="@+id/bt_modify"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="修改"android:onClick="updatebutton"></Button><Buttonandroid:id="@+id/bt_del"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="删除"android:onClick="updatebutton"></Button><Buttonandroid:id="@+id/bt_query"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="查询"android:onClick="querybutton"></Button></LinearLayout><ListViewandroid:id="@+id/listView"android:layout_width="fill_parent"android:layout_height="wrap_content"android:padding="5dip"></ListView></LinearLayout>由代码可见,main.xml实际上实现的是如图7.4所示的效果。该布局中放置了两个TextView、两个EditText和4个按钮,在按钮的下面是一个ListView组件,但是该ListView没有对显示效果进行任何的限制。图7.4
main.xml界面实例MyDbDemo中listview.xml文件的代码如下:<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="/apk/res/android"android:id="@+id/linear"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="5dip"><TextViewandroid:id="@+id/tvID"android:layout_width="80dp"android:layout_height="wrap_content"/><TextViewandroid:id="@+id/tvName"android:layout_width="80dp"android:layout_height="wrap_content"/><TextViewandroid:id="@+id/tvAge"android:layout_width="80dp"android:layout_height="wrap_content"/></LinearLayout>可见listview.xml布局中横向放置了三个TextView用于显示数据。该实例实际的运行效果是使用listview.xml中的数据格式替换main.xml中ListView组件的数据格式后实现的。该效果通过LayoutInflater类的对象进行实现。实例MyDbDemo中AndroidManifest.xml文件的代码如下:<?xmlversion="1.0"encoding="utf-8"?><manifestxmlns:android="/apk/res/android"xmlns:tools="/tools"><applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:fullBackupContent="@xml/backup_rules"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.MyDbDemo"tools:targetApi="36"><activityandroid:exported="true"android:label="@string/app_name"android:name=".MyDbDemoActivity"><intent-filter><actionandroid:name="ent.action.MAIN"/><categoryandroid:name="ent.category.LAUNCHER"/></intent-filter></activity><providerandroid:name=".FriendsProvider"android:authorities="vider"android:exported="true"/></application></manifest>实例MyDbDemo中SQLiteOpenHelper的子类DbHelper的实现代码如下:packageroduction.mydbdemo;importandroid.content.ContentValues;importandroid.content.Context;importandroid.database.Cursor;importandroid.database.sqlite.SQLiteDatabase;importandroid.database.sqlite.SQLiteDatabase.CursorFactory;importandroid.database.sqlite.SQLiteOpenHelper;importandroid.text.TextUtils;importjava.util.ArrayList;importjava.util.Collections;publicclassDbHelperextendsSQLiteOpenHelper{privatestaticfinalStringTB_FRIENDS="friends";publicstaticfinalStringCOL_ID="_id";privatestaticfinalStringCOL_NAME="name";privatestaticfinalStringCOL_AGE="age";privatestaticfinalStringTAG="DbHelper";privatestaticfinalStringWHERE_ID_CLAUSE="_id=?"; publicstaticfinalStringTB_NAME="friends"; publicDbHelper(Contextcontext,Stringname,CursorFactoryfactory, intversion){ super(context,"friends.db",null,1); //TODOAuto-generatedconstructorstub }//regionCRUD操作publiclonginsertFriend(Stringname,intage){SQLiteDatabasedb=getWritableDatabase();ContentValuesvalues=newContentValues();values.put("name",name);values.put("age",age);returndb.insert(TB_NAME,null,values);}publicintupdateFriend(longid,StringnewName,intnewAge){SQLiteDatabasedb=getWritableDatabase();ContentValuesvalues=newContentValues();values.put("name",newName);values.put("age",newAge);returndb.update(TB_NAME,values,WHERE_ID_CLAUSE,newString[]{String.valueOf(id)});}publicintdeleteFriend(longid){SQLiteDatabasedb=getWritableDatabase();returndb.delete(TB_NAME,WHERE_ID_CLAUSE,newString[]{String.valueOf(id)});}publicCursorgetAllFriends(){returngetReadableDatabase().query(TB_NAME,newString[]{"_id","name","age"},null,null,null,null,"nameCOLLATENOCASEASC");}//endregionprivateStringmakePlaceholders(intlen){returnTextUtils.join(",",Collections.nCopies(len,"?"));}privateString[]toStringArray(long[]input){String[]output=newString[input.length];for(inti=0;i<input.length;i++){output[i]=Long.toString(input[i]);}returnoutput;}@Override publicvoidonCreate(SQLiteDatabasedb){ //TODOAuto-generatedmethodstub db.execSQL("CREATETABLE"+TB_FRIENDS+"("+COL_ID+"INTEGERPRIMARYKEYAUTOINCREMENT,"+COL_NAME+"TEXTNOTNULL,"+COL_AGE+"INTEGERNOTNULLDEFAULT0);");} @Override publicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){ //TODOAuto-generatedmethodstub //更安全的数据库升级方案try(Cursorc=db.rawQuery("SELECT*FROM"+TB_NAME,null)){ArrayList<ContentValues>data=newArrayList<>();while(c.moveToNext()){ContentValuescv=newContentValues();cv.put("name",c.getString(c.getColumnIndexOrThrow("name")));cv.put("age",c.getInt(c.getColumnIndexOrThrow("age")));data.add(cv);}db.execSQL("CREATETEMPORARYTABLEfriends_backupASSELECT*FROM"+TB_FRIENDS);db.execSQL("DROPTABLE"+TB_FRIENDS);onCreate(db);db.execSQL("INSERTINTO"+TB_FRIENDS+"SELECT*FROMfriends_backup");db.execSQL("DROPTABLEfriends_backup");onCreate(db);for(ContentValuescv:data){db.insert(TB_NAME,null,cv);}} onCreate(db); }}子类DbHelper重写了父类SQLiteOpenHelper的两个抽象方法onCreate()和onUpgrade()。在onCreate()方法中创建了一个名为friends的数据表,
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 《适老微高压富氧舱》团体标准解读
- 浙江省湖州市南浔区2025-2026学年三年级上学期期末语文试题(文字版含答案)
- 2026年自然资源综合岗事业单位招聘考试笔试试题(含答案)
- 2026年烟草物流管理外勤专员烟草公司招聘考试笔试试题(含答案)
- 洁丽雅毛巾网络营销策划书
- 人教版九年级上册《生物》期末考试带答案
- 2026年化学性烧伤急救个案分享
- 2026 年梗阻性黄疸胆道支架置入护理个案
- 2026年秋季初中道德与法治开学第一课 新学期学习规划教案
- 瓜果产地批发采购合作协议范本三篇
- DB31T 1703-2026宠物友好型商业场所安全运行管理指南
- 2025年广西卫生职业技术学院教职人员招聘笔试真题(含完整答案解析)
- 2026湖北恩施州恩施市面向市外教师选调65人考前冲刺密卷及参考答案详解(培优B卷)
- 关于项目工期的确认函7篇范本
- 2026年医师定期考核试题题库中医入门试题及答案
- 2026小红书有感运动IP方案
- 天然气管线保护施工方案
- 2025届中工国际工程股份有限公司校园招聘笔试历年参考题库附带答案详解
- 《数据资产全过程管理业务流程操作指引(试行)》
- GB/Z 114.1-2026纳米制造技术规范纳米储能第1部分:空白详细规范电化学电容器用纳米多孔活性炭
- (2025年)注册安全工程师考试建筑施工(初级)安全生产实务试卷与参考答案
评论
0/150
提交评论