- 浏览: 44102 次
文章分类
- 全部博客 (35)
- java (35)
- zk安装 (1)
- 从零开始认识 JasperReport + IReport (JasperReport部分) (1)
- Javadoc查看、搜索、比较利器——GroovyHelp 3.1.5 GA发布 (1)
- 设计模式-Simple Factory 模式 (1)
- biaodashi (1)
- 格局定乾坤 (1)
- 一个spatialReference引发的血案 (1)
- 创造亿万富翁的神奇公式 (1)
- 打印机 (2)
- js 调用flex 方法 (1)
- tomcat部署 (1)
- 2010 -> 2011 (1)
- Android颜色选择器 (1)
- 《软件开发的边界-管理成功的项目》 (1)
- 毕业了 (1)
- MapXtreme2004开发的Web程序的部署 (1)
- 一个比较有用的XML文件操作类 C#代码 可以继续扩展 (1)
- J2EE中 实体BEAN和会话BEAN的区别 (1)
- iOS开发之Objective-C与JavaScript的交互 (1)
- iOS开发之多媒体播放 (1)
- 单链表逆序 (1)
- ORA-01114错误原因及解决方法(临时表空间坏掉、或者满了) (1)
- hibernate使用sql查询text类型的字段出错 (1)
- 腾讯微博java(android) sdk 标签相关api详细介绍 (1)
- Android开发之数据保存技术(一) (1)
- 瞎混了好久,今天开博 (1)
- MySQL安装详解(V5.5 For Windows) (1)
- Execution in the Kingdom of Nouns (1)
- EJB 2.0 VS EJB3.0 (1)
- 一个简单的Unix脚本(文件拷贝打包) (1)
- php session_cache_limiter详解 (1)
- llvm-clang (1)
- jdbc学习笔记-----jdbc性能优化 (1)
- java教程:解析java的多线程机制(二) (1)
最新评论
<h1>Android开发之数据保存技术(一)</h1>
/*
* Android开发之数据保存技术(一)
* 北京Android俱乐部群:167839253
* Created on: 2011-8-17
* Author: blueeagle
* Email: liujiaxiang@gmail.com
*/
本文主要讲解Android开发的数据保存技术。Android的数据保存技术主要有preference,本地文件,SQLite轻量级数据库,和Content Provider。本文只要讲SQLite和Conent Provider。preference和本地文件,将放在后面讨论。
<h2>SQLite</h2>
Android通过SQLite库提供了完善的关系数据库功能,而没有强加任何额外的限制。通过使用SQLite,可以为每一个应用程序创建独立的关系数据库。
所有的Android数据库都存储在/data/data/<package_name>/databases文件夹下。默认条件下,所有的数据库都是私有的,并且只能被创建它们的应用程序访问。要跨应用程序共享数据库,可以使用内容提供器。
SQLite是一个关系数据管理系统。它被普遍认为是:开源,兼容标准,轻量级,Single-tier。
可以用一个例子来演示SQLite。该例子将记录存储在一个数据库中,然后显示出来。
新建一个HelloSQLite的程序。
需要在某个地方放置该数据库中描述的一些常量,所以要创建一个Constants接口。
代码如下:
/*
* Android开发之数据保存技术(一)
* Constants.java
* Created on: 2011-8-15
* Author: blueeagle
* Email: liujiaxiang@gmail.com
*/
<textarea readonly name="code" class="java">package com.blueeagle;
import android.provider.BaseColumns;
public interface Constants extends BaseColumns {
/** Called when the activity is first created. */
public static final String TABLE_NAME = "HelloSQLite";
public static final String TIME = "time";
public static final String TITLE = "title";
}
</textarea><br>
每个事件都将作为HeloSQLite表中的一行进行存储。每行都包含一个_id、time和title列。_id是主键,在扩展的BaseColums接口中声明。time和title分别作为时间和事件标记。
使用SQliteOpenHelper。接下来,创建一个名为SQLiteData的帮助器来表示数据库本身。这个类扩展自Android的SQLiteOpenHelper类,它负责管理数据库的创建和版本。需要做的就是提供一个构造方法并且覆写两个方法。
代码如下:
<textarea readonly name="code" class="java">/*
* Android开发之数据保存技术(一)
* MySQLite.java
* Created on: 2011-8-16
* Author: blueeagle
* Email: liujiaxiang@gmail.com
*/
package com.blueeagle;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import static com.blueeagle.Constants.TABLE_NAME;
import static com.blueeagle.Constants.TIME;
import static com.blueeagle.Constants.TITLE;
import static android.provider.BaseColumns._ID;
public class MySQLite extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "MySQLite.db";
private static final int DATABASE_VERSION = 1;
public MySQLite(Context context, String name, CursorFactory factory,
int version) {
super(context, DATABASE_NAME, factory, DATABASE_VERSION);
// TODO Auto-generated constructor stub
}
@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL("CREATE TABLE "+ TABLE_NAME+"("+_ID+"INTEGER PRIMARY KEY AUTOINCREMENT,"+TIME+"INTEGER,"+TITLE+"TEXT NOT NULL);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
db.execSQL("DROP TABLE IF EXISTS" + TABLE_NAME);
onCreate(db);
}
}
</textarea><br>
首次访问数据库时,SQLiteOpenHelper将注意到该数据库不存在,并调用onCreate()方法来创建它。
定义Activity主程序。
在HelloSQLite程序中做的第一次尝试是使用本地的SQLite数据库来存储事件,并将这些事件显示为TextView中的一个字符串。
布局xml文件如下:
<textarea readonly name="code" class="html">main.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/myText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</ScrollView>
</textarea><br>
这段代码使用一个ScrollView,以防太多的时间沾满了屏幕。
对于HelloSQLite.java的实现如下所示:相关代码有注释说明。
<textarea readonly name="code" class="java">package com.blueeagle;
/*
* Android开发之数据保存技术(一)
* HelloSQLite.java
* Created on: 2011-8-16
* Author: blueeagle
* Email: liujiaxiang@gmail.com
*/
import android.app.Activity;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.widget.TextView;
import static com.blueeagle.Constants.TABLE_NAME;
import static com.blueeagle.Constants.TIME;
import static com.blueeagle.Constants.TITLE;
import static android.provider.BaseColumns._ID;
public class HelloSQLite extends Activity {
/** Called when the activity is first created. */
private MySQLite mySqlite;
private static String[] FROM={_ID,TIME,TITLE};
private static String ORDER_BY = TIME+" DESC";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mySqlite = new MySQLite(this);
try{
addItem("Hello,Android!");
Cursor cursor = getItems();
showItems(cursor);
}
finally{
mySqlite.close();
}
}
//显示查询结果
private void showItems(Cursor cursor) {
// TODO Auto-generated method stub
StringBuilder builder = new StringBuilder("Saved items:\n");
while(cursor.moveToNext()){
long id = cursor.getLong(0);
long time = cursor.getLong(1);
String title = cursor.getColumnName(2);
builder.append(id).append(": ");
builder.append(time).append(": ");
builder.append(title).append("\n");
}
TextView myTextView = (TextView)findViewById(R.id.myText);
myTextView.setText(builder);
}
//此函数接受一个Cursor作为输入并格式化,以便用户能够理解输出的内容
//查询条目方法
private Cursor getItems() {
// TODO Auto-generated method stub
SQLiteDatabase db = mySqlite.getReadableDatabase();
Cursor cursor = db.query(TABLE_NAME, FROM, null, null, null, null, ORDER_BY);
startManagingCursor(cursor);
return cursor;
}
//因为查询不用修改数据库,因此利用只读句柄,然后调用查询的query方法来执行SQL语句,FROM是
//想要使用的列构成的数组,ORDER_BY告诉SQLite按照从新到旧的顺序返回查询结果。
//添加条目方法
private void addItem(String string) {
// TODO Auto-generated method stub
SQLiteDatabase db = mySqlite.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(TIME, System.currentTimeMillis());
values.put(TITLE, string);
db.insert(TABLE_NAME, null, values);
}
//因为要修改数据库,所以调用getWritableDatabase()方法来获取数据库的一个写句柄,当然也可以获取
//到读句柄。
}
</textarea><br>
完成上述文件-》运行,即可看到结果显示出来。这样就完成了第一个Android数据库程序。
当然,这里面需要注意的问题:
1. 新建数据库的问题
新建数据库的时候,会遇到我们用:
db.execSQL("CREATE TABLE "+ TABLE_NAME+"("+_ID+"INTEGER PRIMARY KEY AUTOINCREMENT,"+TIME+"INTEGER,"+TITLE+"TEXT NOT NULL);");
这样一条语句。有时候SQL语句书写错误,比如少一个空格就会引起程序异常退出。这个时候建议在db.execSQL()函数中填写一个字符串变量,然后把自己写的SQL语句赋给字符串变量,在做赋值操作的时候,先打印出来看看,是不是少空格,多+号什么的小错误。
2. 版本号的问题
关于构造函数中的版本号,是有明确的说明的。
<p align="left"> int version) {
super(context, DATABASE_NAME, factory,
DATABASE_VERSION);
这个版本号version当你有新版本的时候,则做更新操作,新版本的版本号将要比老版本高,如果此时修改版本号,不是向高修改,而是向低修改的话,程序就会发生异常了。
3. 数据库文件的问题
对于onCreate()方法,在程序运行的时候,只运行一次,运行的这一次就是去创建数据库。将数据库的文件存储在SD卡中。路径是data/data/包名/databases里。可以在Eclipse里通过DDMS里的File Explorer来查看。当数据库文件存在了以后,则不会再次运行。
完成了上述例子,就算完成了一个数据库的应用。但是如果列表中有数千个或者上百万个事件。程序将运行的非常慢。甚至于耗尽内存。解决办法就是数据绑定。
有了数据绑定,只需要几行代码,就可以将数据连接到视图,从而实现需求。为了演示,我们修改上面的实例。
将主程序HelloSQLite.java继承ListActivity而不是Activity。
将代码修改为如下所示:
<textarea readonly name="code" class="java">package com.blueeagle;
/*
* Android开发之数据保存技术
* HelloSQLite.java
* Created on: 2011-8-16
* Author: blueeagle
* Email: liujiaxiang@gmail.com
*/
import android.app.ListActivity;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.widget.SimpleCursorAdapter;
import static com.blueeagle.Constants.TABLE_NAME;
import static com.blueeagle.Constants.TIME;
import static com.blueeagle.Constants.TITLE;
import static android.provider.BaseColumns._ID;
public class HelloSQLite extends ListActivity {
/** Called when the activity is first created. */
private MySQLite mySqlite;
private static String[] FROM={_ID,TIME,TITLE};
private static String ORDER_BY = TIME+" DESC";
//@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mySqlite = new MySQLite(this);
try{
addItem("Hello,Android!");
Cursor cursor = getItems();
showItems(cursor);
}
finally{
mySqlite.close();
}
}
private static int[] TO = {R.id.rowid,R.id.time,R.id.title};
private void showItems(Cursor cursor) {
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,R.layout.item,cursor,FROM,TO);
//这里有必要说明一下SimpleCursorAdapter构造函数的5个参数。1.对应于当前Activity的引用,2.一个资源,它定义一个列表条目的视图,
//3.数据集光标,4.一组列名称,数据来源于这些列。5.视图列表,这是数据的目的地。
setListAdapter(adapter);
}
private Cursor getItems() {
SQLiteDatabase db = mySqlite.getReadableDatabase();
Cursor cursor = db.query(TABLE_NAME, FROM, null, null, null, null, ORDER_BY);
startManagingCursor(cursor);
return cursor;
}
private void addItem(String string) {
// TODO Auto-generated method stub
SQLiteDatabase db = mySqlite.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(TIME, System.currentTimeMillis());
values.put(TITLE, string);
db.insert(TABLE_NAME, null, values);
}
}
</textarea><br>
将main.xml修改成如下形式:
<textarea readonly name="code" class="html"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ListView
android:id="@android:id/list"
android:layout_height="wrap_content"
android:layout_width="wrap_content">
</ListView>
<TextView
android:id="@android:id/empty"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="empty!">
</TextView>
</LinearLayout>
</textarea><br>
增加item.xml为如下:
<textarea readonly name="code" class="html"><?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10sp"
>
<TextView
android:id="@+id/rowid"
android:layout_height="wrap_content"
android:layout_width="wrap_content">
</TextView>
<TextView
android:id="@+id/rowidcolon"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text=":"
android:layout_toRightOf="@id/rowid">
</TextView>
<TextView
android:id="@+id/time"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_toRightOf="@id/rowidcolon">
</TextView>
<TextView
android:id="@+id/timecolon"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text=":"
android:layout_toRightOf="@id/time">
</TextView>
<TextView
android:id="@+id/title"
android:layout_height="fill_parent"
android:layout_width="wrap_content"
android:textStyle="italic"
android:ellipsize="end"
android:singleLine="true"
android:layout_toRightOf="@id/timecolon">
</TextView>
</RelativeLayout>
</textarea><br>
运行结果如图所示。
<img src="http://hi.csdn.net/attachment/201108/17/0_1313565594vM3N.gif" alt="">
当然,这只是一个DEMO,用来展示如何使用SQLite,这个DEMO存在一些问题。其他应用程序都不能向事件数据库添加内容,甚至于无法看这些事件。那么针对这一点,引出了Android里的内容提供器,即ContentProvider。
<h2>内容提供器</h2>
在Android安全模型中,一个应用程序编写的文件无法被其他任何应用程序所读写。每个应用程序都有自己的Linux用户ID和数据目录,以及其受保护的内存空间。Android程序可以通过下面两种方式进行彼此间的通信。
第一种是IPC(Inter-Process Communication,进程间通信):一个进程使用AIDL(Android Interface Definition Language,接口定义语言)和IBinder接口声明一个任意的API。调用该API时,将在进程间安全且有效地队参数进行编组。这项先进技术用于对后台Service线程进行远程过程调用。
第二种就是ContentProvider:进程在系统中将他们本身注册为某些数据类型的提供者。请求该信息时,Android就会通过一个固定的API调用这些进程,以它们认为合适的方式查询或者修改内容。
ContentProvider管理的任何信息部分都通过一个URI来寻址,这个URI类似于以下形式:content://authority/path/id
其中content://是标准要求的前缀。authority是提供者的名称,建议使用完全限定包名称,避免出现名称冲突。Path是提供者内部的一个虚拟目录,用于标识被请求的数据类型。Id是被请求的特定记录的主键,要请求获得具有特定类型的所有记录,可以省略此参数以及后面的斜杠。
Android已经内置提供了几个提供者,包括:
content://browser;
content://contacts;
content://media;
content://settings。
下面我们就来演示如何使用内容提供器。
将HelloSQLite程序改为使用内容提供器的。对于HelloSQLite的提供者,下面都是有效的URI:
content://com.blueeagle.HelloSQLite/3 ——表示取id为3的数据
content://com.blueeagle.HelloSQLite/ ——表示取所有数据
首先需要向Contants.java添加两个常量:
public static final Uri CONTENT_URI = Uri.parse("content://"+AUTHORITY+"/"+TABLE_NAME);
接下来可以对HelloSQLite类做一些修改:
代码如下:
<textarea readonly name="code" class="java">package com.blueeagle;
/*
* Android开发之数据保存技术(一)
* HelloSQLite.java
* Created on: 2011-8-16
* Author: blueeagle
* Email: liujiaxiang@gmail.com
*/
import android.app.ListActivity;
import android.content.ContentValues;
import android.database.Cursor;
import android.os.Bundle;
import android.widget.SimpleCursorAdapter;
import static com.blueeagle.Constants.TIME;
import static com.blueeagle.Constants.TITLE;
import static com.blueeagle.Constants.CONTENT_URI;
import static android.provider.BaseColumns._ID;
public class HelloSQLite extends ListActivity {
/** Called when the activity is first created. */
//private MySQLite mySqlite;
private static String[] FROM = {_ID,TIME,TITLE};
private static String ORDER_BY = TIME+" DESC";
//@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
addItem("Hello,Android!");
Cursor cursor = getItems();
showItems(cursor);
}
private static int[] TO = {R.id.rowid,R.id.time,R.id.title};
//显示查询结果
private void showItems(Cursor cursor) {
// TODO Auto-generated method stub
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,R.layout.item,cursor,FROM,TO);
setListAdapter(adapter);
}
//使用ContentProvider时,geiItems方法也化简了
private Cursor getItems() {
return managedQuery(CONTENT_URI,FROM,null,null,ORDER_BY);
}
//此处使用Activity.managedQuery()方法,将内容URI,感兴趣的列表和应该使用的排序顺序传递给该方法。
private void addItem(String string) {
ContentValues values = new ContentValues();
values.put(TIME, System.currentTimeMillis());
values.put(TITLE, string);
getContentResolver().insert(CONTENT_URI, values);
}
//没有了对getWriteableDatabase()的调用,对insertOrThrow的调用替换成了getContentResolver().insert(CONTENT_URI, values)
//我们使用了一个URI而不是用数据库句柄。
}
</textarea><br>
下面就是实现ContentProvider
ContentProvider是一个类似于Activity的高级对象,需要向系统进行声明。因此,实现ContentProvider的第一步是将其添加到AndroidManifest.xml文件中的<activity>标签之前。
其中android:name是类名,android:authorities是在内容URI中使用的字符串。接下来创建我们自己的ContentProvider类,为继承类。ContentProvider创建后就会被调用:public boolean onCreate()ContentProvider类中有6个继承而来的方法,需要实现:
具体来说需要实现ContentProvider 类中的6个抽象方法。 <br>
Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):将查询的数据以Cursor 对象的形式返回。
<br>
Uri insert(Uri uri, ContentValues values):向 Content Provider中插入新数据记录,ContentValues 为数据记录的列名和列值映射。
<br>
int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):更新Content Provider中已存在的数据记录。
int delete(Uri uri, String selection, String[] selectionArgs):从Content Provider中删除数据记录。
String getType(Uri uri):返回Content Provider中的数据( MIME )类型。
boolean onCreate():当 Content Provider 启动时被调用。
定义一个 URI 类型的静态常量,命名为CONTENT_URI。 必须为该常量对象定义一个唯一的URI字符串,一般的做法是将 ContentProvider子类的全称类名作为URI字符串。
定义每个字段的列名,如果采用的数据库存储系统为SQLite 数据库,数据表列名可以采用数据库中表的列名。不管数据表中有没有其他的唯一标识一个记录的字段,都应该定义一个"_id"字段 来唯一标识一个记录。模式使用 "INTEGER PRIMARY KEY AUTOINCREMENT" 自动更新 一般将这些列名字符串定义为静态常量, 如"_id"字段名定义为一个名为"_ID" 值为 "_id" 的静态字符串对象。
创建好的一个Content Provider必须在AndroidManifest.xml中声明。
<p align="left"> <provider android:name=".ItemsProvider"
android:authorities="com.blueeagle" />
其中name属性为ContentProvider 子类的全称类名,authorities 属性唯一标识了一个ContentProvider。还可以通过 setReadPermission() 和 setWritePermission() 来设置其操作权限。当然也可以再上面的 xml中加入 android:readPermission 或者 android: writePermission属性来控制其权限。
<br>注意:因为ContentProvider可能被不同的进程和线程调用,所以这些方法必须是线程安全的。
然后需要使用UriMatcher,用于匹配Uri。<br>
用法如下:<br>
首先把需要匹配Uri路径全部给注册上:
对于Uri:
什么是URI?将其分为A,B,C,D 4个部分:
A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;"content://"
B:URI的标识,它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的 类名。这个标识在 元素的 authorities属性中说明:一般是定义该ContentProvider的包.类的名称 ;"content://hx.android.text.myprovider"
C:路径,不知道是不是路径,通俗的讲就是你要操作的数据库中表的名字,或者你也可以自己定义,记得在使用的时候保持一致就ok了;"content://hx.android.text.myprovider/tablename"
D:如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部; "content://hx.android.text.myprovider/tablename/#" #表示数据id
注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,例如匹配content://com.blueeagle路径,返回的匹配码为1。
//常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码<br>
UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//添加需要匹配的uri,如果匹配就会返回匹配码<br>
//如果match()方法匹配content://com.blueeagle路径,返回匹配码为1<br>
sUriMatcher.addURI(“content://com.blueeagle”, “HelloSQLite”, 1);
//如果match()方法匹配content://com.blueeagle/ ***路径,返回匹配码为2<br>
//#号为通配符<br>
sUriMatcher.addURI(“content://com.blueeagle”, “HelloSQLite/#”, 2);
switch(sUriMatcher.match(Uri.parse("content://com.blueeagle /***"))) {<br>
case 1 break;<br>
case 2 break;<br>
default:<br>
//不匹配 break;<br>
}
自定义的contentprovider如下:
ItemsProvider.java
<textarea readonly name="code" class="java">package com.blueeagle;
/*
* Android开发之数据保存技术(一)
* ItemsProvider.java
* Created on: 2011-8-16
* Author: blueeagle
* Email: liujiaxiang@gmail.com
*/
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.text.TextUtils;
import static com.blueeagle.Constants.CONTENT_URI;
import static com.blueeagle.Constants.TABLE_NAME;
import static com.blueeagle.Constants.AUTHORITY;
import static android.provider.BaseColumns._ID;
public class ItemsProvider extends ContentProvider {
private static final int ITEMS = 1;
private static final int ITEMS_ID = 2;
/** The MIME type of a directory of items */
private static final String CONTENT_TYPE
= "vnd.android.cursor.dir/vnd.com.blueeagle";
/** The MIME type of a single item */
private static final String CONTENT_ITEM_TYPE
= "vnd.android.cursor.item/vnd.com.blueeagle";
private MySQLite myDataBase ;
private UriMatcher myUriMatcher;
@Override
public boolean onCreate() {
myUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
myUriMatcher.addURI(AUTHORITY, "HelloSQLite", ITEMS);
myUriMatcher.addURI(AUTHORITY, "HelloSQLite/#", ITEMS_ID);
myDataBase = new MySQLite(getContext());
return true;
}
@Override
public int delete(Uri uri, String selection,
// TODO Auto-generated method stub
String[] selectionArgs) {
SQLiteDatabase db = myDataBase.getWritableDatabase();
int count;
switch (myUriMatcher.match(uri)) {
case ITEMS:
count = db.delete(TABLE_NAME, selection, selectionArgs);
break;
case ITEMS_ID:
long id = Long.parseLong(uri.getPathSegments().get(1));
count = db.delete(TABLE_NAME, appendRowId(selection, id),
selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
// Notify any watchers of the change
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
switch (myUriMatcher.match(uri)) {
case ITEMS:
return CONTENT_TYPE;
case ITEMS_ID:
return CONTENT_ITEM_TYPE;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
SQLiteDatabase db = myDataBase.getWritableDatabase();
// Validate the requested uri
if (myUriMatcher.match(uri) != ITEMS) {
throw new IllegalArgumentException("Unknown URI " + uri);
}
// Insert into database
long id = db.insertOrThrow(TABLE_NAME, null, values);
// Notify any watchers of the change
Uri newUri = ContentUris.withAppendedId(CONTENT_URI, id);
getContext().getContentResolver().notifyChange(newUri, null);
return newUri;
}
@Override
public Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String orderBy) {
// TODO Auto-generated method stub
if (myUriMatcher.match(uri) == ITEMS_ID) {
long id = Long.parseLong(uri.getPathSegments().get(1));
selection = appendRowId(selection, id);
}
// Get the database and run the query
SQLiteDatabase db = myDataBase.getReadableDatabase();
Cursor cursor = db.query(TABLE_NAME, projection, selection,
selectionArgs, null, null, orderBy);
// Tell the cursor what uri to watch, so it knows when its
// source data changes
cursor.setNotificationUri(getContext().getContentResolver(),
uri);
return cursor;
}
private String appendRowId(String selection, long id) {
// TODO Auto-generated method stub
return _ID + "=" + id
+ (!TextUtils.isEmpty(selection)
? " AND (" + selection + ')'
: "");
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
SQLiteDatabase db = myDataBase.getWritableDatabase();
int count;
switch (myUriMatcher.match(uri)) {
case ITEMS:
count = db.update(TABLE_NAME, values, selection,
selectionArgs);
break;
case ITEMS_ID:
long id = Long.parseLong(uri.getPathSegments().get(1));
count = db.update(TABLE_NAME, values, appendRowId(
selection, id), selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
// Notify any watchers of the change
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
}
</textarea><br>
总结一下,创建一个新的内容提供器。
1.通过扩展抽象类ContentProvider可以创建新的内容提供器。重写onCreate方法来打开或者初始化将要使用这个新的提供器来提供底层数据源。
2.还应该提供那些用来返回指向这个提供器的完整的URI的公共静态CONTENT_URI变量。提供器之间的内容URI应该是唯一的,所以最好的做法是使URI路径以包名为基础。
定义一个内容提供器URI一般的形式为:
content://com.pakagename/datapath
例如:content://com.blueeagle/items
或者:content://com.blueeagle./items/3
内容URI可以表示为这两种形式中的任意一种形式。前面的一种URI表示对那种类型中所有的值的请求,后面附加一个/3的表示对一条记录的请求(这里请求的是记录3)。这两种形式来访问提供器都是可行的。
完成这项工作最简单的方式是使用一个UriMatcher。当通过内容解析器来访问内容提供器的时候,可以配置UriMathcer来解析URI以确定它们的形式。就像前文说的那样。
发表评论
-
java教程:解析java的多线程机制(二)
2012-02-08 15:27 1013<div>四、线程间的同步 <div ... -
jdbc学习笔记-----jdbc性能优化
2012-02-08 15:07 999<div>这里说的是如何正确使用jdbc编 ... -
llvm-clang
2012-02-07 17:14 1069clang ... -
php session_cache_limiter详解
2012-02-07 15:18 2761<span style="backgr ... -
一个简单的Unix脚本(文件拷贝打包)
2012-02-04 17:09 952题目要求: 实现备份脚本,将目录: /sbin ... -
EJB 2.0 VS EJB3.0
2012-02-04 16:39 892SUMMARY: Removal of home in ... -
Execution in the Kingdom of Nouns
2012-02-03 16:39 1887<h3>Execution in the ... -
MySQL安装详解(V5.5 For Windows)
2012-02-01 09:39 818<p>MySQL安装详解(V5.5 For ... -
瞎混了好久,今天开博
2012-01-31 14:13 793<p>作为一名“无证”程序员,自己瞎混了这 ... -
腾讯微博java(android) sdk 标签相关api详细介绍
2012-01-11 13:53 1133<span style="font-f ... -
hibernate使用sql查询text类型的字段出错
2011-12-28 16:28 1459晚上查了一下,做个记录 hibernate默认不支持t ... -
ORA-01114错误原因及解决方法(临时表空间坏掉、或者满了)
2011-12-28 14:23 1795<span style="font-f ... -
单链表逆序
2011-12-21 11:24 1391实现一: #include "stdafx. ... -
iOS开发之多媒体播放
2011-12-19 15:49 1007iOS sdk中提供了很多方便的方法来播放多媒体。本 ... -
iOS开发之Objective-C与JavaScript的交互
2011-12-19 14:48 1120UIWebView是iOS最常用的SDK之一,它有一个 ... -
J2EE中 实体BEAN和会话BEAN的区别
2011-12-15 10:14 929<span style="" ... -
一个比较有用的XML文件操作类 C#代码 可以继续扩展
2011-12-15 09:49 903CXml</span>{</spa ... -
MapXtreme2004开发的Web程序的部署
2011-12-14 16:39 860</span></font>& ... -
毕业了
2011-12-14 11:39 691今天终于顺利的通过了硕士毕业答辩。<br> ... -
《软件开发的边界-管理成功的项目》
2011-12-13 10:04 758本书是Rational Software的资深项目经理 ...
相关推荐
数据储存与文件操作、对话框、通知、菜单、 LoaderManager异步加载、多线程(AsyncTask与Handler)、 百度地图等十五个模块,一共102集。 本网盘分享章节编号是按照视频更新的先后顺序编号的,具体学习可参考如下...
总之,Android软件开发中的数据管理是一个涉及多种技术和策略的复杂主题。熟练掌握数据的新建、储存、读取和删除,是构建高效、稳定应用的基础。通过学习雨松MOMO的教程,开发者可以提升自己的技能,并在实际项目中...
"Android开发实例大全源码第一部分"提供了1-80个案例的源代码,这是一份宝贵的资源,可以帮助开发者深入理解Android应用开发的各种技术和实践。下面将针对这些标签和源代码文件,详细阐述Android开发中的重要知识点...
"Android开发笔记"是由real6410公司为开发者提供的一份宝贵的资源,特别针对real6410开发板进行优化,旨在帮助开发者快速提升Android应用开发技能。这份资料包含了从基础知识到实战经验的全方位指导。 首先,"read ...
《Android开发艺术探索》是一本深受Android开发者喜爱的技术书籍,由任玉刚撰写。这本书深入浅出地讲解了Android开发中的各种技术难点和最佳实践,旨在帮助开发者提升技能,提高开发效率。书中涵盖了许多关键知识点...
总之,Android蓝牙开发涵盖了设备搜索、配对、连接和数据传输等多个环节,每个环节都有其特定的技术要点和注意事项。通过实践和学习,开发者可以掌握这项技术,从而在各种应用场景中实现设备间的无线通信。
"0308_数据存储"涵盖了Android中持久化数据的各种方法,包括SharedPreferences、SQLite数据库、文件存储以及ContentProvider的使用,这些知识对于实现应用的数据保存和恢复功能至关重要。 "0410_多媒体技术"涉及到...
- **File Storage**:可以通过文件系统来保存数据。 - **Content Provider**:用于存储和检索数据,并允许其他应用程序访问这些数据。 #### 七、Android网络编程 Android应用经常需要与服务器进行数据交换。常用的...
Android项目开发中使用的数据存储方式有:网络存储、sqlite存储、File存储和SharedPreferences存储,四种存储方式对应的Demo别人是NetworkDemo、SqliteDemo、FileDemo和SharedPreferencesDemo,根据应用的场景选择...
【Android开发实验一代码】是针对初学者或者对Android编程感兴趣的开发者提供的实践项目,这个压缩包包含了一系列的源代码,对应博主在其博客上的第一篇文章所讲解的内容。通过这个实验,学习者可以深入理解Android...
在“想到做到:Android开发关键技术与精彩案例”一书中,作者深入浅出地讲解了Android应用开发的关键技术和一系列实战案例。这些章节涵盖了Android开发的基础到进阶内容,旨在帮助开发者从理论到实践全面掌握Android...
总之,"Android开发实战经典课件.zip"提供了全面的Android开发教程,涵盖了从基础知识到进阶技术的各个方面,对于想要踏入Android开发领域的学习者来说,是一份非常宝贵的资源。通过深入学习并实践课件中的知识,...
在Android应用开发中,数据储存是一项至关重要的任务,它涉及到应用程序如何持久化用户数据、缓存网络请求结果以及优化性能。本主题将深入探讨“Android数据储存”,特别是针对非图片数据的处理,如将JSON数据序列...
《Android应用案例开发大全》是一本深入探讨Android应用程序开发的实战型书籍,其源代码提供了丰富的实例,旨在帮助开发者从实践中学习和理解Android开发的核心概念和技术。这些源代码覆盖了从基础到高级的各种应用...
Android开发还包括数据存储,比如SQLite数据库的使用,文件操作,以及SharedPreferences来保存轻量级的用户偏好数据。网络编程也是关键部分,如HTTP请求、WebSocket通信,以及使用Retrofit或Volley等库进行网络访问...
2. **数据存储**:学习如何使用SharedPreferences、SQLite数据库以及文件存储等方式保存应用数据。 3. **网络编程**:理解HTTP协议,掌握使用OkHttp或Retrofit等库进行网络请求的方法。 4. **多线程与异步处理**:...
书中涵盖了许多关键的知识点,对于想要提升Android开发能力的工程师来说,是一份非常有价值的参考资料。 首先,书中可能会涉及Android架构设计。这包括如何创建高效的组件化和模块化应用,以提高代码复用性和可维护...
《Android开发艺术探索》这本书是Android开发者们非常推崇的一本技术书籍,它深入浅出地讲解了Android开发的各种技术和实践。这份"《Android开发艺术探索》源码.zip"压缩包包含的是书中所有章节的源代码,这对于学习...
【标题】"Android开发-智能聊天机器人"是一个关于在安卓平台上构建聊天机器人的项目,它旨在教授开发者如何利用Android技术创建交互式、智能化的应用。在这个项目中,开发者将学习到如何设计用户界面,以及如何集成...
在Android开发中,数据保存是不可或缺的一部分,它涉及到应用程序如何持久化地存储用户数据或应用状态。本主题将深入探讨Android中的四种主要数据保存方法:内部文件存储、外部SD卡存储、首选项(SharedPreferences...