- 浏览: 21544931 次
- 性别:
- 来自: 杭州
最新评论
-
ZY199266:
配置文件还需要额外的配置ma
Android 客户端通过内置API(HttpClient) 访问 服务器(用Spring MVC 架构) 返回的json数据全过程 -
ZY199266:
我的一访问为什么是 /mavenwebdemo/WEB-I ...
Android 客户端通过内置API(HttpClient) 访问 服务器(用Spring MVC 架构) 返回的json数据全过程 -
lvgaga:
我又一个问题就是 如果像你的这种形式写。配置文件还需要额外的 ...
Android 客户端通过内置API(HttpClient) 访问 服务器(用Spring MVC 架构) 返回的json数据全过程 -
lvgaga:
我的一访问为什么是 /mavenwebdemo/WEB-I ...
Android 客户端通过内置API(HttpClient) 访问 服务器(用Spring MVC 架构) 返回的json数据全过程 -
y1210251848:
你的那个错误应该是项目所使用的目标框架不支持吧
log4net配置(web中使用log4net,把web.config放在单独的文件中)
Android中Shared Preferences、Files、Network、SQLite数据库编程总结及示例
前言Android中提供了4中数据存储方式。但是存储的这些数据都是私有的,要想在其他应用程序中使用这些数据。就需要使用ContentProvider(数据共享)。下面是对4种方式的介绍。
1. Shared Preferences 存储方式主要是针对系统配置信息的保存,比如给程序界面设置了音效,想在下一次启动前还能够保留上次设置的音效。此方法是用来存
储"key-value paires"格式的数据。是一个轻量级的键值存储机制,只能存储基本数据类型。
2. Files 存储其是通过FileInputStream 和FileOutputStream 来对文件的操作。就是把需要保存的东西通过文件的形式记录下来。当需要这写数据时,通过这个文件获取即可。
但是在Android中文件是私有的,一个应用程序无法读取其他应用程序文件。
3. SQLite 数据库 可以用来存储打了的数据,并且可以很容易对数据进行增,删,改,查等操作。且支持SQL语句。
4. NetWork 通过网络来存储和获取数据。即将数据存储到网络上去。
第一部分Shared Preferences 数据存储
Shared preferences 主要用来保存引用程序的一些属性设置。
getPreferences 此方法用来获取Preferences对象
SharedPreferences.Editor editor = uiState.edit(); 取得编辑对象
editor.put...() 此方法添加数据
commit() 保存数据
Activity.getPreferences 保存私有数据。即不能与其他模块共享数据。
注意: 用Shared Preferences 保存的数据无法直接在多个程序间共享。
下例为在推出程序时把音效的状态保存到Preferences中,当再次启动时将读取上次保存的数据。
public class MIDIPlayer{
public MediaPlayerplayerMusic= null;
private ContextmContext= null;
public MIDIPlayer(Context context){
mContext = context;
}
public void PlayMusic(){// 播放音乐
playerMusic = MediaPlayer.create(mContext, R.raw.start);//装载资源中的音乐
playerMusic.setLooping(true);//设置是否循环
try{
playerMusic.prepare();
}catch (IllegalStateException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
playerMusic.start();
}
public void FreeMusic(){// 停止并释放音乐
if (playerMusic != null){
playerMusic.stop();
playerMusic.release();
}
}
}
public class Activity01 extends Activity{
private MIDIPlayermMIDIPlayer= null;
private booleanmbMusic= false;
private TextViewmTextView= null;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTextView = (TextView) this.findViewById(R.id.TextView01);
mMIDIPlayer = new MIDIPlayer(this);
/* 装载数据 */
SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);// 取得活动的preferences对象.
mbMusic = settings.getBoolean("bmusic", false);// 取得值.
if (mbMusic){
mTextView.setText("当前音乐状态:开");
mbMusic = true;
mMIDIPlayer.PlayMusic();
}else{
mTextView.setText("当前音乐状态:关");
}
}
public boolean onKeyUp(int keyCode, KeyEvent event){
switch (keyCode){
case KeyEvent.KEYCODE_DPAD_UP:
mTextView.setText("当前音乐状态:开");
mbMusic = true;
mMIDIPlayer.PlayMusic();
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
mTextView.setText("当前音乐状态:关");
mbMusic = false;
mMIDIPlayer.FreeMusic();
break;
}
return true;
}
public boolean onKeyDown(int keyCode, KeyEvent event){
if (keyCode == KeyEvent.KEYCODE_BACK){
/* 这里我们在推出应用程序时保存数据 */
SharedPreferences uiState = getPreferences(0);// 取得活动的preferences对象.
SharedPreferences.Editor editor = uiState.edit();// 取得编辑对象
editor.putBoolean("bmusic", mbMusic);// 添加值
editor.commit();// 提交保存
if ( mbMusic ){
mMIDIPlayer.FreeMusic();
}
this.finish();
return true;
}
return super.onKeyDown(keyCode, event);
}
}
第二部分Files数据存储
public class MIDIPlayer{
public MediaPlayerplayerMusic= null;
private ContextmContext= null;
public MIDIPlayer(Context context){
mContext = context;
}
public void PlayMusic(){//播放音乐
playerMusic = MediaPlayer.create(mContext, R.raw.start);//装载资源中的音乐
playerMusic.setLooping(true);//设置是否循环
try{
playerMusic.prepare();
}catch (IllegalStateException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
playerMusic.start();
}
public void FreeMusic(){//停止并释放音乐
if (playerMusic != null){
playerMusic.stop();
playerMusic.release();
}
}
}
public class Activity01 extends Activity{
private MIDIPlayermMIDIPlayer= null;
private booleanmbMusic= false;
private TextViewmTextView= null;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTextView = (TextView) this.findViewById(R.id.TextView01);
mMIDIPlayer = new MIDIPlayer(this);
load();//通过load方法来获取文件数据
if (mbMusic){
mTextView.setText("当前音乐状态:开");
mbMusic = true;
mMIDIPlayer.PlayMusic();
}else{
mTextView.setText("当前音乐状态:关");
}
}
public boolean onKeyUp(int keyCode, KeyEvent event){
switch (keyCode){
case KeyEvent.KEYCODE_DPAD_UP:
mTextView.setText("当前音乐状态:开");
mbMusic = true;
mMIDIPlayer.PlayMusic();
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
mTextView.setText("当前音乐状态:关");
mbMusic = false;
mMIDIPlayer.FreeMusic();
break;
}
return true;
}
public boolean onKeyDown(int keyCode, KeyEvent event){
if (keyCode == KeyEvent.KEYCODE_BACK){
save();//通过save方法在退出应用程序时保存数据,当再次启动时通过load方法来读取这些数据
if ( mbMusic ){
mMIDIPlayer.FreeMusic();
}
this.finish();
return true;
}
return super.onKeyDown(keyCode, event);
}
void load(){//装载、读取数据
Properties properties = new Properties();//构建Properties对象
try{
FileInputStream stream = this.openFileInput("music.cfg");//利用输入流创建文件 "music.cfg"为文件名
properties.load(stream);//读取文件内容
}catch (FileNotFoundException e){
return;
}catch (IOException e){
return;
}
mbMusic = Boolean.valueOf(properties.get("bmusic").toString());//取得数据
}
boolean save(){//保存数据
Properties properties = new Properties();
properties.put("bmusic", String.valueOf(mbMusic));//将数据打包成Properties
try{
FileOutputStream stream = this.openFileOutput("music.cfg", Context.MODE_WORLD_WRITEABLE);//用文件来存储数据可以通过openFileOutput方法打开一个文件并存入数据
如果这个文件不存在就自动创建这个文件,可以deleteFile方法可以
删除指定文件
properties.store(stream, "");//将打包好的数据写入文件中
}catch (FileNotFoundException e){
return false;
}catch (IOException e){
return false;
}
return true;
}
}
如果在开发程序前,需要通过加载一个文件内容来初始化程序,就可以在编译程序之前,在res/raw/tempFile中建立一个static文件,就可以在程序中
通过Resources.openRawResource(R.raw.文件名)方法返回一个InputStream对象,直接读取文件内容。
第三部分 Network 数据存储
网络数据存储必须要联网。下例是在应用程序退出程序时,将数据发送到电子邮件中备份,所以需要在模拟器中配置电子邮件账户,
配置电子邮件账户步骤:启动模拟器,打开“菜单”,选择“电子邮件”项。在启动之后,填写好邮件地址和密码,选中“默认情况下从账户发送电子邮件” 程序将自动
配置电子邮件相关信息,最后点击完成。
public class Activity01 extends Activity{
private int miCount = 0;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
miCount=1000;
}
public boolean onKeyDown(int keyCode, KeyEvent event){
if (keyCode == KeyEvent.KEYCODE_BACK){
//退出应用程序时保存数据
Uri uri = Uri.parse("mailto:fengsheng.studio@hotmail.com");//发送邮件的地址
Intent it = new Intent(Intent.ACTION_SENDTO, uri); //创建Intent
it .putExtra(android.content.Intent.EXTRA_SUBJECT, "数据备份");//通过putExtra方法设置邮件的主题,内容,附件等
it .putExtra(android.content.Intent.EXTRA_TEXT, "本次计数:"+miCount);//设置邮件的内容
startActivity(it);//Android中是通过startActivity方法来调用要发送的邮件数据的Inten.
this.finish();
return true;
}
return super.onKeyDown(keyCode, event);
}
}
第四部分SQLite数据库,专门用于处理数据量较大的数据。SQLite他是一款轻型数据库。其特点:
1.轻量级
SQLite他是进程内的数据库引擎,因此不存在数据库的客户端和服务器。使用时只需带上它的一个动态库,就可用使用其全部功能,且动态库尺寸也很小。
2.独立性
SQLite数据库不依赖第三方软件,使用他不需要安装。
3.隔离性
SQLite数据库中所有的信息(如 表,视图,触发器)都包含在一个文件内,方便管理和维护。
4.跨平台
SQLite在很多系统上都可运行。
5.多语言接口
SQLite数据库支持多语言编程接口,如:C/C++,JAVA等。
6.安全性
SQLite数据库通过数据库级上的独占性和共享锁来实现独立事务处理。就是说多个进程在同一时间可以从同一数据库读取数据,但只有一个可以写入。在某个进程或线程
向数据库执行写入之前,必须获得独占锁定。在发出独占锁定后,其他的读或写操作将不会再发生。
SQLite数据库的基本操作包括:创建数据库,打开数据库,创建表,向表中添加数据,从表中删除数据,修改表中的数据,关闭数据库,删除指定表,删除数据库,和查询表中的
某条数据。下面有一例子。
public class Activity01 extends Activity{
private static intmiCount= 0;
private SQLiteDatabasemSQLiteDatabase= null;//数据库对象
private final static StringDATABASE_NAME= "Examples_06_05.db";//数据库名
private final static StringTABLE_NAME= "table1";//表名
/* 表中的字段 */
private final static StringTABLE_ID= "_id";
private final static StringTABLE_NUM= "num";
private final static StringTABLE_DATA= "data";
/* 创建表的sql语句 */
private final static StringCREATE_TABLE= "CREATE TABLE " + TABLE_NAME + " (" + TABLE_ID + " INTEGER PRIMARY KEY," + TABLE_NUM + " INTERGER,"+ TABLE_DATA + " TEXT)";
LinearLayoutm_LinearLayout= null;//线性布局
ListViewm_ListView= null;//用列表ListView视图-显示数据库中的数据
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
m_LinearLayout = new LinearLayout(this);
/* 设置布局LinearLayout的属性 */
m_LinearLayout.setOrientation(LinearLayout.VERTICAL);
m_LinearLayout.setBackgroundColor(android.graphics.Color.BLACK);
/* 创建ListView对象 */
m_ListView = new ListView(this);
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
m_ListView.setBackgroundColor(Color.BLACK);
/* 添加m_ListView到m_LinearLayout布局 */
m_LinearLayout.addView(m_ListView, param);
/* 设置显示m_LinearLayout布局 */
setContentView(m_LinearLayout);
// 创建或打开已经存在的数据库。在Android中创建和打开一个数据库都可以用openOrCreateDatebase方法来完成因它会去自动检测是否存在这个数据库,如果存
在则打开,如果不存在则创建一个数据库;创建成功则返回一个SQLiteDatabase对象
mSQLiteDatabase = this.openOrCreateDatabase(DATABASE_NAME, MODE_PRIVATE, null);
try{
mSQLiteDatabase.execSQL(CREATE_TABLE);//在数据库mSQLiteDatabase中创建一个表.利用SQL语句创建数据中的一个表。一个数据库中可以包含多个表,我们的
每一条数据保存在一个指定的表中,可以通过execSQL方法来完成。
}catch (Exception e){
UpdataAdapter();
}
}
public boolean onKeyUp(int keyCode, KeyEvent event){
switch (keyCode){
case KeyEvent.KEYCODE_DPAD_LEFT:
AddData();
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
DeleteData();
break;
case KeyEvent.KEYCODE_1:
UpData();
break;
case KeyEvent.KEYCODE_2:
DeleteTable();
break;
case KeyEvent.KEYCODE_3:
DeleteDataBase();
break;
}
return true;
}
public void DeleteDataBase(){//删除数据库可直接调用deleteDataBase方法
this.deleteDatabase(DATABASE_NAME);
this.finish();
}
public void DeleteTable(){//删除指定表此处使用了execSQLite方法
mSQLiteDatabase.execSQL("DROP TABLE " + TABLE_NAME);
this.finish();
}
public void UpData(){//修改表中数据
ContentValues cv = new ContentValues();
cv.put(TABLE_NUM, miCount);
cv.put(TABLE_DATA, "修改后的数据" + miCount);
mSQLiteDatabase.update(TABLE_NAME, cv, TABLE_NUM + "=" + Integer.toString(miCount - 1), null);//使用update方法来更新一天数据。此处修改了TABLE_NUM值为
miCount-1的数据。
UpdataAdapter();
}
public void AddData(){//向表中添加一条数据.使用insert方法添加数据,但使用此方法时要把数据打包到ContentValues中。ContentValues其实就是一个Map,Key值是字段
名称,Value值是字段的值。通过ContentValues的put方法可以把数据放到ContentValues对象中去。
ContentValues cv = new ContentValues();
cv.put(TABLE_NUM, miCount);
cv.put(TABLE_DATA, "测试数据库数据" + miCount);
mSQLiteDatabase.insert(TABLE_NAME, null, cv);//使用insert方法插入数据。也可使用execSQL方法插入代码如:
String INSERT_DATA = "INSERT INTO table1(_id,num,data) values(1,1,‘通过SQL语句插入’)";
mSQLiteDatabase.insert(INSETR_DATA);
miCount++;
UpdataAdapter();
}
public void DeleteData(){//从表中删除指定的一条数据
mSQLiteDatabase.execSQL("DELETE FROM " + TABLE_NAME + " WHERE _id=" + Integer.toString(miCount));//此处通过execSQLite方法来删除字段为miCount+1的数据。也可使用delete方法删除如:
mSQLiteDatabase.delete("Examples_06_05.db","WHERE _id"+0,null);此处删除了字段等于1的数据
miCount--;
if (miCount < 0){
miCount = 0;
}
UpdataAdapter();
}
public void UpdataAdapter(){//更新视图显示
// 获取数据库Phones的Cursor,Cursor对象指向的是每一条数据
Cursor cur = mSQLiteDatabase.query(TABLE_NAME, new String[] { TABLE_ID, TABLE_NUM, TABLE_DATA }, null, null, null, null, null);
miCount = cur.getCount();
if (cur != null && cur.getCount() >= 0){
ListAdapter adapter = new SimpleCursorAdapter(this,// ListAdapter是ListView和后台数据的桥梁
// 定义List中每一行的显示模板
android.R.layout.simple_list_item_2,// 表示每一行包含两个数据项
cur,// 数据库的Cursor对象
new String[] { TABLE_NUM, TABLE_DATA },// 从数据库的TABLE_NUM和TABLE_DATA两列中取数据
new int[] { android.R.id.text1, android.R.id.text2 });// 与NAME和NUMBER对应的Views
m_ListView.setAdapter(adapter);//将adapter添加到m_ListView中
}
}
public boolean onKeyDown(int keyCode, KeyEvent event){
if (keyCode == KeyEvent.KEYCODE_BACK){
mSQLiteDatabase.close();//使用SQLite数据库后要及时关闭,否则可能会抛出SQLiteException异常
this.finish();
return true;
}
return super.onKeyDown(keyCode, event);
}
}
上例中没有涉及到查询表中数据
在Android中查询数据是通过Cursor类来实现的,当我们使用SQLiteDatabase.query()方法时。得到的是一个Cursor对象,Cursor指向的是每一条数据。
Cursor类常用方法:
move 以当前位置为参考,将Cursor移动到指定位置,成功返回true,失败返回false
moveToPosition将Cursor移动到指定位置,成功true,失败返回false
moveToNext将Cursor向前移动一个位置,成功true,失败返回false
moveToLast将Cursor向后移动一个位置,成功true,失败返回false
moveToFirst将Cursor移动到第一行,成功true,失败返回false
isBeforeFirst返回Cursor是否指向第一项数据之前
isAfterLast返回Cursor是否指向最后一项数据
isClosed返回Cursor是否关闭
isFirst返回Cursor是否指向第一项数据
isLast返回Cursor是否指向最后一项数据
isNull返回指定位置的值是否为空
getCount返回总的数据项数
getInt返回当前行中指定索引的数据
下面为使用Cursor来查询数据库中的数据的代码。
Cursor cur = mSQLiteDatabase.rawQuery("SELECT*FORM table",null);
if (cur !=null){
if(cur.moveToFirst()){
do{
int numColumn = cur.getColumnIndex("num");
int num = cur.getInt(numColumn);
}while(cur.moveToNext());
}
}
SQLiteOpenHelper应用
为了能更好的管理和维护数据库,我们可以封装一个继承自SQLiteOpenHelper类的数据库操作类。
public class MyDataBaseAdapter{
private static final StringTAG= "MyDataBaseAdapter";// 用于打印log
public static final StringKEY_ID= "_id";// 表中一条数据的名称
public static final StringKEY_NUM= "num";// 表中一条数据的内容
public static final StringKEY_DATA= "data";// 表中一条数据的id
private static final StringDB_NAME= "Examples_06_06.db";// 数据库名称为data
private static final StringDB_TABLE= "table1";// 数据库表名
private static final intDB_VERSION= 1;// 数据库版本
private ContextmContext= null;// 本地Context对象
//创建一个表的SQL语句
private static final StringDB_CREATE= "CREATE TABLE " + DB_TABLE + " (" + KEY_ID + " INTEGER PRIMARY KEY," + KEY_NUM + " INTERGER,"+ KEY_DATA + " TEXT)";
private SQLiteDatabasemSQLiteDatabase= null;// 执行open()打开数据库时,保存返回的数据库对象
private DatabaseHelpermDatabaseHelper= null;// 由SQLiteOpenHelper继承过来
public MyDataBaseAdapter(Context context){//构造函数-取得Context
mContext = context;
}
public void open() throws SQLException{// 打开数据库,返回数据库对象
mDatabaseHelper = new DatabaseHelper(mContext);
mSQLiteDatabase = mDatabaseHelper.getWritableDatabase();
}
public void close(){// 关闭数据库
mDatabaseHelper.close();
}
public long insertData(int num, String data){//插入一条数据
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_NUM, num);
initialValues.put(KEY_DATA, data);
return mSQLiteDatabase.insert(DB_TABLE, KEY_ID, initialValues);
}
public boolean deleteData(long rowId){//插入一条数据
return mSQLiteDatabase.delete(DB_TABLE, KEY_ID + "=" + rowId, null) > 0;
}
public Cursor fetchAllData(){//通过Cursor查询所有数据
return mSQLiteDatabase.query(DB_TABLE, new String[] { KEY_ID, KEY_NUM, KEY_DATA }, null, null, null, null, null);
}
public Cursor fetchData(long rowId) throws SQLException{//查询指定数据
Cursor mCursor = mSQLiteDatabase.query(true, DB_TABLE, new String[] { KEY_ID, KEY_NUM, KEY_DATA }, KEY_ID + "=" + rowId, null, null, null, null, null);
if (mCursor != null){
mCursor.moveToFirst();
}
return mCursor;
}
public boolean updateData(long rowId, int num, String data){//更新一条数据
ContentValues args = new ContentValues();
args.put(KEY_NUM, num);
args.put(KEY_DATA, data);
return mSQLiteDatabase.update(DB_TABLE, args, KEY_ID + "=" + rowId, null) > 0;
}
/*
*此处封装了一个继承自SQLiteOpenHelper类的数据库操作类。SQLiteOpenHelper的构造方法中分别需要传入Context,数据库名称,CursorFactory(一般为null,否则为默认数据库
*,数据库的版本号(不能为负数),在SQLiteOpenHelper中当数据库第一次被创建时首先执行的是onCreate方法。
/
private static class DatabaseHelper extends SQLiteOpenHelper{
DatabaseHelper(Context context){//构造函数在此处并没有真正创建一个数据库,而是当调
用getWritableDatabase()或 getReadableDatabase()方法时,则创建一个数据库,并且返回一个SQLiteDatabase对象
super(context, DB_NAME, null, DB_VERSION);
}
public void onCreate(SQLiteDatabase db){//创建一个表
db.execSQL(DB_CREATE);// 数据库没有表时创建一个,此处利用SQL语句在数据库对象 db中创建了一个表
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){//升级数据库
db.execSQL("DROP TABLE IF EXISTS notes");
onCreate(db);
}
}
}
如果使用上面封装的MyDataBaseAdapter类如下:
public class Activity01 extends Activity{
private static intmiCount= 0;
LinearLayoutm_LinearLayout= null;
ListViewm_ListView= null;//ListView显示数据库中的数据
MyDataBaseAdapter m_MyDataBaseAdapter;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
m_LinearLayout = new LinearLayout(this);//创建LinearLayout布局对象
m_LinearLayout.setOrientation(LinearLayout.VERTICAL);//设置布局LinearLayout的属性
m_LinearLayout.setBackgroundColor(android.graphics.Color.BLACK);
m_ListView = new ListView(this);//创建ListView对象
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
m_ListView.setBackgroundColor(Color.BLACK);
m_LinearLayout.addView(m_ListView, param);//添加m_ListView到m_LinearLayout布局
setContentView(m_LinearLayout);//设置显示m_LinearLayout布局
m_MyDataBaseAdapter = new MyDataBaseAdapter(this);//构造MyDataBaseAdapter对象
m_MyDataBaseAdapter.open();//取得数据库对象
UpdataAdapter();
}
public boolean onKeyUp(int keyCode, KeyEvent event){
switch (keyCode){
case KeyEvent.KEYCODE_DPAD_LEFT:
AddData();
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
DeleteData();
break;
case KeyEvent.KEYCODE_1:
UpData();
break;
}
return true;
}
public void UpData(){//更新一条数据
m_MyDataBaseAdapter.updateData(miCount - 1, miCount, "修改后的数据" + miCount);
UpdataAdapter();
}
public void AddData(){//向表中添加一条数据
m_MyDataBaseAdapter.insertData(miCount, "测试数据库数据" + miCount);
miCount++;
UpdataAdapter();
}
public void DeleteData(){//从表中删除指定的一条数据
m_MyDataBaseAdapter.deleteData(miCount);//删除数据
miCount--;
if (miCount < 0){
miCount = 0;
}
UpdataAdapter();
}
public boolean onKeyDown(int keyCode, KeyEvent event){//按键事件处理
if (keyCode == KeyEvent.KEYCODE_BACK){
m_MyDataBaseAdapter.close();//退出时,不要忘记关闭
this.finish();
return true;
}
return super.onKeyDown(keyCode, event);
}
public void UpdataAdapter(){//更新视图显示
// 获取数据库Phones的Cursor
Cursor cur = m_MyDataBaseAdapter.fetchAllData();
miCount = cur.getCount();
if (cur != null && cur.getCount() >= 0){
ListAdapter adapter = new SimpleCursorAdapter(this,// ListAdapter是ListView和后台数据的桥梁
// 定义List中每一行的显示模板
android.R.layout.simple_list_item_2,// 表示每一行包含两个数据项
cur,// 数据库的Cursor对象
new String[] {MyDataBaseAdapter.KEY_NUM, MyDataBaseAdapter.KEY_DATA },// 从数据库的TABLE_NUM和TABLE_DATA两列中取数据
new int[] { android.R.id.text1, android.R.id.text2 });// 与NAME和NUMBER对应的Views
m_ListView.setAdapter(adapter);//将adapter添加到m_ListView中
}
}
}
第五部分ContentProvider
ContentProvider是所有应用程序之间数据存储和检索的一个桥梁,其作用为使得各个应用程序之间实现数据共享。
1、ContentResolver
所有的Content Provider都会实现一些共同的接口,包括数据的查询、添加、更改和删除。应用可用通过一个唯一的ContentResolver接口来使用具体的某个Content Provider.
可以通过getContentResolver()方法来得到ContentResolver对象,然后就可以用ContentResolver提供的方法来操作你需要的Content Provider了。
ContentResolver cr = getContentResolver();
对于每一种类型的ContentProvider只有一个实例(如音频、视频、图像、个人联系信息等常用Content Providers),但是这个实例可以与不同的程序或进程中的多个ContentResolver对象进行通信。
进程之间的互动是由ContentResolver和ContentProvider类处理的。
Content Provider把它的数据作为数据库模型上的单一数据表提供出来,在数据表中,每一行是一条记录,每一列代表某一特定类型的值。
2、URI
每个Content Providers都会对外提供一个公共的URI(包装成Uri对象)。如果应用程序有数据需要共享时,就需要使用Content Provider为这些数据定义一个URI,然后其他
应用程序就可以通过Content Providers 传入这个URI来对数据进程操作。
URI由三部分组成:"content://"、数据路径、标识ID(可选)。如下是系统的一些URI:
content://media/internal/images 这个URI将返回设备上存储的所有图片
content://contacts/people/5 联系人信息中ID为5的联系人记录
content://contacts/people/这个URI将返回设备上的所有联系人记录
上面第二个URI可改写为:
Uri person = ContentUris.withAppendedId(People.CONTENT_URI,5);//所有与其Content Provider互动的过程中都可以使用这个URI常量
每个ContentResolver都把URI作为其第一个参数,它决定了ContentResolver将与哪个Provider对话。
3、数据查询
可以通过ContentResolver.query()方法或者Activity.managedQuery()方法得当Cursor对象.
不同的是managedQuery包含了Cursor生命周期,当Activity被暂停后,如果要使用Cursor就必须通过Activity.startManagingCursor()方法来重新启动。但两者都需要传入
一个URI来确定当前要操作的数据。
Cursor cur = managedQuery(people ,null,null,null);//查询联系人信息中ID为5的联系人记录
要得到更详细内容可以
String[] projection = new String[] {People._ID, People._COUNT, People.NAME, People.NUMBER};
Uri contacts = People.CONTENT_URI;
Cursor managedCursor = managedQuery(contacts ,projection , null, null, People.NAME+"ASC");//第二个参数为返回指定列的数据,第三个返回所有行的数据
第四个参数可选参数,第五个参数是按名字的升序排序
一条查询返回的是一组数据的集合,列名,缺省排序,数据类型对每个Content Provider是特定的。但是每个Provider都有一个_id列,它为每条记录保存一个数字ID
值。每个Provider都可以把返回的记录数量作为_count列报告出来,这个值对所有的行来说是相同的。
读取查询的数据可通过Cursor对象的方法来操作,其对象用于在结果集中前向或后向列举数据,Cursor对象只能用来读取数据。其增加、修改、删除数据必须使用ContentResolver对象
private void getColumnData(Cursor cur){
if(cur.moveToFirst()){
String name;
String phoneNumber;
int nameColumn = cur.getColumnIndex(People.NAME);
int phoneColumn = cur.getColumnIndex(People.NUMBER);
String imagePath;
do{
name = cur.getString(nameColumn);
phoneNumber = cur.getString(phoneColumn);
}while(cur.moveToNext());
}
}
如果是通过ID来查询某一特定记录的,那么这个结果只有一个值,否则,它将包含多个值(如果没有匹配的值,将返回空)。我们可以读取记录的特定字段,但是必须知道
字段的类型,这是因为Cursor对象读每种数据类型都有不同的方法,例如:getString()、getInt()、getFloat()等方法。当然对于大多数类型,如果调用读字符串的函数,
Cursor对象将会返回一个代表这个数据的字符串。
Cursor可以通过列的索引得到列名,或者通过列名得到列索引。
4、修改数据
可通过ContentReolver.update()方法来修改数据。
private void updateRecord(int id,int num){//创建一个updateRecord方法来修改数据
Uri uri = ContentUris.withAppendedId(People.CONTENT_URI,id);
ContentValues values = new ContentValues();
values.put(People.NUMBER,num);
getContentResolver().update(uri,values,null,null);
}
5、添加数据
通过调用ContentResolver.insert()方法来增加一条记录,该方法接受一个要增加的目标URI,以及一个包含了新记录值的Map对象,调用后的返回值是新记录的URI(包括记录号)。
代码:
ContentValues values = new ContentValues();
values.put(People.NAME,"Abraham Lincoln");
values.put(People.STARRED,1);
Uri uri = getContentResolver().insert(People.CONTENT_URI,values);
下面为刚刚添加的记录加入新数据
Uri phoneUri = null;
Uri emailUri = null;
PhoneUri = Uri.withAppendedPath(uri,People.Phones.CONTENT_DIRECTORY);
values.clear();
values.put(People.Phones.TYPE, People.Phones.TYPE_MOBILE);
values.put(People.Phones.NUMBER, "1243442121");
getContentResolver().insert(phoneUri ,values);
emailUri = Uri.withAppendedPath(uri, People.ContactMethods.CONTENT_DIRECTORY);
values.clear();
values.put(People.Phones.KIND, People.Phones.KIND_EMALL);
values.put(People.Phones.DATA, "test@example.com");
values.put(People.ContentMethods.TYPE, People.ContactMethods.TYPE_HOME);
getContentResolver().insert(emailUri ,values);
如果一个查询返回如图像和声音的二进制数据,那么在数据表中可以被直接存储或者数据的表入口是指定一个Content的字符串:URI,通过这个URI可以得到数据。
通常小数量的数据如0K-50K常常在表中直接存储,通过Cursor.getBlob()函数读取,这个函数返回的是一个二进制数组。
如果数据表入口是一个Content:URI,就不要直接打开和读取文件(一个原因是权限问题),而是通过调用ContentResolver.openInputStream()函数来得到一个可以用来读取数据
的InputStream对象 代码如下:
ContentValues values = new ContentValues(3);
values.put(Media.DISPLAY_NAME, "road_trip_1");
values.put(Media.DESCRIPTION, "Day 1, trip to Los Angeles");
values.put(Media.MIME_TYPE, "image/jpeg");
Uri uri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, values);
try{
OutputStream outStream = getContentResolver().openOutputStream(uri);
sourceBitmap.compress(Bitmap.CompressFormat.JPEG, 50, outStream);
outStream.close();
}catch(Exception e){
}
6、删除数据
通过ContentResolver.delete()方法;
Uri uri = People.CONTENT_URI;
getContentResolver().delete(uri,null,null);
getContentResolver().delete(uri ,"NAME="+"'xxx'",null);//指定Where条件语句来删除
7、创建Content Provider
上面是使用Content Provider 下面我们将自己创建一个Content Provider
在创建的Content Provider 类中定义一个公共的、静态的常量来代表这个URI,该地址是唯一的.代码如下:
public static final Uri CONTENT_URI = Uri.parse("content://com.example.codelab.transporationprovider");
必须定义你要返回给客户端的数据列名。就像其他数据可一样,但要为其定义一个叫_id的列,它用来表示每条记录的唯一性。模式使用
"INTEGER PRIMARY KEY AUTOINCREMENT"自动更新。
如果你要处理的数据类型是一种比较新的类型,就必须先定义一个新的MIME类型,以供ContentProvider.geType(url)来返回。
MIME类型有两种形式:一种是指定的单个记录,另一个是多条记录
单个记录的MIME类型:
vnd.android.cursor.item/vnd.yourcompanyname.contenttype
比如一个请求列车信息的URI,如:content://com.example.transportationprovider/trains/122,可能会返回typevnd.android.cursor.item/vnd.example.rail这样一个MIME类型
多个记录的MIME类型
vnd.android.cursor.dir/vnd.yourcompanyname.contenttype
比如一个请求所有列车信息的URI,如:content://com.example.transportationprovider/trains,可能会返回vnd.android.cursor.dir/vnd/example.rail这样一个MIME类型
在AndroidManifest.xml中使用<provider>标签来设置Content Provider.
如果我们创建的Content Provider类名为MyContentProvider 这在AndroidManifest中需要添加如下代码:
<provider
android:name = "MyContentProvider"
android:authorities = "com.wissen.MyContentProvider"
/>
还有通过setReadPermission()和setWriterPermission()来设置其权限。当然也可在在上面代码中加入android:readPermission或者android:writePermission来控制权限
最后,要在其他应用程序中使用这个ContentProvider,这就需要将MyContentProvider加入项目中,也可以定义了静态字段的文件打包成jar文件,加入到要使用的工程中。通过
import导入。因为ContentProvider可能被不同的进程和线程调用,所以这些方法必须是线程安全的。
例:下例实现了ContentProvider的创建及使用
public class NotePad{//此类创建了一些字段数据,
public static final StringAUTHORITY= "com.google.provider.NotePad";//ContentProvider的uri的数据路径
private NotePad(){
}
public static final class Notes implements BaseColumns{// 定义基本字段,字段类继承自BaseColumns类
private Notes(){
}
public static final UriCONTENT_URI= Uri.parse("content://" + AUTHORITY + "/notes");//ContentProvider的uri
public static final StringCONTENT_TYPE= "vnd.android.cursor.dir/vnd.google.note";// 新的MIME类型-多个
public static final StringCONTENT_ITEM_TYPE= "vnd.android.cursor.item/vnd.google.note";// 新的MIME类型-单个
public static final StringDEFAULT_SORT_ORDER= "modified DESC";
//字段
public static final StringTITLE= "title";
public static final StringNOTE= "note";
public static final StringCREATEDDATE= "created";
public static final StringMODIFIEDDATE= "modified";
}
}
public class NotePadProvider extends ContentProvider{//创建自己的ContentProvider类NotePadProvider,包括了查询、添加、删除、更新等操作以及打开与创建数据库
private static final StringTAG= "NotePadProvider";
private static final StringDATABASE_NAME= "note_pad.db";// 数据库名
private static final intDATABASE_VERSION= 2;
private static final StringNOTES_TABLE_NAME= "notes";// 表名
private static HashMap<String, String>sNotesProjectionMap;
private static final intNOTES= 1;
private static final intNOTE_ID= 2;
private static final UriMatchersUriMatcher;
private DatabaseHelpermOpenHelper;
//创建表SQL语句
private static final StringCREATE_TABLE="CREATE TABLE "
+ NOTES_TABLE_NAME
+ " (" + Notes._ID
+ " INTEGER PRIMARY KEY,"
+ Notes.TITLE
+ " TEXT,"
+ Notes.NOTE
+ " TEXT,"
+ Notes.CREATEDDATE
+ " INTEGER,"
+ Notes.MODIFIEDDATE
+ " INTEGER" + ");";
static{
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);
sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);
sNotesProjectionMap = new HashMap<String, String>();
sNotesProjectionMap.put(Notes._ID, Notes._ID);
sNotesProjectionMap.put(Notes.TITLE, Notes.TITLE);
sNotesProjectionMap.put(Notes.NOTE, Notes.NOTE);
sNotesProjectionMap.put(Notes.CREATEDDATE, Notes.CREATEDDATE);
sNotesProjectionMap.put(Notes.MODIFIEDDATE, Notes.MODIFIEDDATE);
}
private static class DatabaseHelper extends SQLiteOpenHelper{
DatabaseHelper(Context context){//构造函数-创建数据库
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public void onCreate(SQLiteDatabase db){//创建表
db.execSQL(CREATE_TABLE);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){//更新数据库
db.execSQL("DROP TABLE IF EXISTS notes");
onCreate(db);
}
}
public boolean onCreate(){
mOpenHelper = new DatabaseHelper(getContext());
return true;
}
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder){//查询操作
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
switch (sUriMatcher.match(uri)){
case NOTES:
qb.setTables(NOTES_TABLE_NAME);
qb.setProjectionMap(sNotesProjectionMap);
break;
case NOTE_ID:
qb.setTables(NOTES_TABLE_NAME);
qb.setProjectionMap(sNotesProjectionMap);
qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1));
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
String orderBy;
if (TextUtils.isEmpty(sortOrder)){
orderBy = NotePad.Notes.DEFAULT_SORT_ORDER;
}else{
orderBy = sortOrder;
}
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
public String getType(Uri uri){// 如果有自定义类型,必须实现该方法
switch (sUriMatcher.match(uri)){
case NOTES:
return Notes.CONTENT_TYPE;
case NOTE_ID:
return Notes.CONTENT_ITEM_TYPE;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
}
public Uri insert(Uri uri, ContentValues initialValues){//插入数据库
if (sUriMatcher.match(uri) != NOTES){
throw new IllegalArgumentException("Unknown URI " + uri);
}
ContentValues values;
if (initialValues != null){
values = new ContentValues(initialValues);
}else{
values = new ContentValues();
}
Long now = Long.valueOf(System.currentTimeMillis());
if (values.containsKey(NotePad.Notes.CREATEDDATE) == false){
values.put(NotePad.Notes.CREATEDDATE, now);
}
if (values.containsKey(NotePad.Notes.MODIFIEDDATE) == false){
values.put(NotePad.Notes.MODIFIEDDATE, now);
}
if (values.containsKey(NotePad.Notes.TITLE) == false){
Resources r = Resources.getSystem();
values.put(NotePad.Notes.TITLE, r.getString(android.R.string.untitled));
}
if (values.containsKey(NotePad.Notes.NOTE) == false){
values.put(NotePad.Notes.NOTE, "");
}
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
long rowId = db.insert(NOTES_TABLE_NAME, Notes.NOTE, values);
if (rowId > 0){
Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, rowId);
getContext().getContentResolver().notifyChange(noteUri, null);
return noteUri;
}
throw new SQLException("Failed to insert row into " + uri);
}
public int delete(Uri uri, String where, String[] whereArgs){//删除数据
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count;
switch (sUriMatcher.match(uri)){
case NOTES:
count = db.delete(NOTES_TABLE_NAME, where, whereArgs);
break;
case NOTE_ID:
String noteId = uri.getPathSegments().get(1);
count = db.delete(NOTES_TABLE_NAME, Notes._ID + "=" + noteId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
public int update(Uri uri, ContentValues values, String where, String[] whereArgs){//更新数据
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count;
switch (sUriMatcher.match(uri)){
case NOTES:
count = db.update(NOTES_TABLE_NAME, values, where, whereArgs);
break;
case NOTE_ID:
String noteId = uri.getPathSegments().get(1);
count = db.update(NOTES_TABLE_NAME, values, Notes._ID + "=" + noteId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
}
public class Activity01 extends Activity{//要使用自己创建出来的NotePadProvider类,首先向其中插入两条数据,然后用Toast来显示数据库中的所以数据
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/* 插入数据 */
ContentValues values = new ContentValues();
values.put(NotePad.Notes.TITLE, "title1");
values.put(NotePad.Notes.NOTE, "NOTENOTE1");
getContentResolver().insert(NotePad.Notes.CONTENT_URI, values);
values.clear();
values.put(NotePad.Notes.TITLE, "title2");
values.put(NotePad.Notes.NOTE, "NOTENOTE2");
getContentResolver().insert(NotePad.Notes.CONTENT_URI, values);
/* 显示 */
displayNote();
}
private void displayNote(){
String columns[] = new String[] { NotePad.Notes._ID,
NotePad.Notes.TITLE,
NotePad.Notes.NOTE,
NotePad.Notes.CREATEDDATE,
NotePad.Notes.MODIFIEDDATE };
Uri myUri = NotePad.Notes.CONTENT_URI;
Cursor cur = managedQuery(myUri, columns, null, null, null);
if (cur.moveToFirst()){
String id = null;
String title = null;
do{
id = cur.getString(cur.getColumnIndex(NotePad.Notes._ID));
title = cur.getString(cur.getColumnIndex(NotePad.Notes.TITLE));
Toast toast=Toast.makeText(this, "TITLE:"+id + "NOTE:" + title, Toast.LENGTH_LONG);
toast.setGravity(Gravity.TOP|Gravity.CENTER, 0, 40);
toast.show();
}
while (cur.moveToNext());
}
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yarin.android.Examples_06_07"
android:versionCode="1"
android:versionName="1.0">
<application
android:icon="@drawable/icon"
android:label="@string/app_name">
<provider //声明我们所使用的ContentProvider
android:name="NotePadProvider"
android:authorities="com.google.provider.NotePad"/>
<activity
android:name=".Activity01"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<data android:mimeType="vnd.android.cursor.dir/vnd.google.note"/>
</intent-filter>
<intent-filter>
<data android:mimeType="vnd.android.cursor.item/vnd.google.note"/>
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="5"/>
</manifest>
相关推荐
Android 使用Shared Preferences进行数据存储-样例,演示如何使用 Shared Preferences 获得数据和保存数据、如何使用getPreferences方法创建文件的模式,以及如何使用getPreferences模拟用户参数设置、查看 ...
一款绿色的SQLite文件查看编辑器,支持SQL语句,直接解压后运行文件夹里面的SQLiteDatabaseBrowserPortable.exe即可运行,打开文件时文件类型选择所有类型,内附简单的使用方法,配合i4等苹果手机助手可以方便得将...
FastSave is An Android library for fast and easy access to Android Shared preferences. It allows you to save any type or list in the sharedpreferences and retrieve it in convenient way. Installation ...
Android Studio编写的Android存储示例。其中包括:使用自带的SharedPreferences存取;存储数据到内存;存储数据到SD卡;存储数据到SQLite数据库。
一个用于调试android数据库和shared preferences的库
Shared Preferences是Android平台上的一个轻量级的数据存储类,用于保存和读取应用程序的一些常用配置和数据,比如用户设置的参数、游戏分数、应用程序状态等。Shared Preferences类似于Windows中的INI文件,它允许...
Android Shared Preferences Helper Android Library to handle SharedPreferences boilerplate code and other tools Download dependencies { compile 'com.github.seanzor:shared-preferences-helper:1.1.0' }...
关于android的数据存储-SQLite-ContentProvider-preferences
NULL 博文链接:https://byandby.iteye.com/blog/833292
利用SharedPreferences 在2个不同的Activity传递数据 可以用做保存帐号的登录信息
android-secure-preferences About This project uses the Encryption class from: http://www.java2s.com/Code/Android/Security/AESEncryption.htm Gives an implementation of SharedPreferences, which encrypts...
Android数据存取之Preferences 这种方式应该是用起来最简单的Android读写外部数据的方法了。他的用法基本上和J2SE(java.util.prefs.Preferences)中的用法一样,以一种简单、 透明的方式来保存一些用户个性化设置的...
Android-Shared-Preferences-example-application Android 共享首选项示例应用程序
数据存储:介绍如何在安卓应用程序中进行数据存储,包括Shared Preferences、SQLite数据库、文件存储等方式。 网络通信:介绍如何在安卓应用程序中进行网络通信,包括HTTP请求、WebSocket、Retrofit等网络库的使用...
Use a single object : Preferences in your kotlin shared projects Compatible with kotlin android and kotlin native for iphone class MyPresenter { val preferences = Preferences() fun start(){ ...
在Android中,实现数据持久化有五种方式:Preferences,文件File,I/O操作、SQLite数据库,ContentProvider组件。 下面逐个做一简单的介绍: 一、Preferences的介绍: Preferences是一种轻量级的数据存储机制,他将...
6.5 Android数据库编程 6.5.1 SQLite简介 6.5.2 SQLite编程详解 6.5.3 SQLiteOpenHelper应用 6.6 数据共享(ContentProviders) 6.7 小结 第7 章多媒体开发 7.1 多媒体开发详解 7.1.1 Open Core 7.1.2 MediaPlayer ...
Android_数据存储 Android三种存储方式 Preferences机制 SQLite数据库存储 content provider
入门首先,将streaming_shared_preferences添加到您的pubspec.yaml中。 如果您已经在使用shared_preferences ,则应将其替换为streaming_shared_preferences 。 dependencies : streaming_shared_preferences : ^...
分别使用getPreferences()和getSharedPreferences()建立xml文件,UI上输入数据类型、键、值之后...可以使用adb查看data/data/<package-name>/shared_prefs/路径下生成的xml,也可以通过输入键名点击Read按钮进行查看