这几天接触到了android上面的数据库使用到了sqlite和contentProvider就自己的理解来写一篇博客,sqlite是一个小型的数据库,功能强大。我们可以自己写一个SQLiteOpenHelper的子类来对sqlite进行操作包括对数据库的增删改查,这里子类里面的oncreate方法只会执行一次,如果下次应用程序启动的使用数据库已经创建那么oncreate方法将不会在执行只会打开数据库。
public class DatabaseHelper extends SQLiteOpenHelper
{
//数据库的名称
private static final String DATABASE_NAME = "artits.db";
//版本号
private static final int VERSION = 1;
@Override
public void onOpen(SQLiteDatabase db)
{
Log.i("dataBase", "数据库打开");
super.onOpen(db);
}
//构造器,用来在activity中创建数据库帮助类的对象
public DatabaseHelper(Context context)
{
super(context, DATABASE_NAME, null, VERSION);
}
@Override
public void onCreate(SQLiteDatabase sqlitedatabase)
{
Log.i("dataBase", "只会运行一次");
//创建数据库只会创建一次,这个运行一次的概念需要理解清楚,就是在应用程序在第一次启动的时候运行而不是每次启动程序之后只会运行一次。他要执行必须使用SQLiteDatabase 对象调用getWritableDatabase() 或者是getReadableDatabase()方法是调用。
}
@Override
public void onUpgrade(SQLiteDatabase sqlitedatabase, int i, int j)
{
}
}
//使用数据的的activity
public class ShowArtistDetail extends Activity
{
/**
* 创建SQLiteOpenHelper的对象
*/
private DatabaseHelper dbHelper;
/**
* SQLiteDatabase的对象用来操作sqlite的增删该查;
*/
private SQLiteDatabase db;
private Map<String, Integer> artistMap = new HashMap<String, Integer>();
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.artist_detail_dialog);
//获取前面一个页面传过来的值
Intent intent = getIntent();
String artistName = intent.getStringExtra(Constant.Parma.MUSIC_ARTIST);
ArrayList<String> artistArrayList = intent.getStringArrayListExtra(Constant.Parma.ARTITSARRAYLIST);
int position = intent.getIntExtra("position", 0);
artitsGallery = (Gallery) findViewById(R.id.gallery_artits_img);
BaseAdapter adapter = new AristDetailGalleryAdapter(artistMap,
artistArrayList, artistName, getApplicationContext());
artitsGallery.setAdapter(adapter);
artitsGallery.setSelection(position);
// 创建了一个DatabaseHelper对象,只执行这句话是不会创建或打开连接的
dbHelper = new DatabaseHelper(getApplicationContext());
// 只有调用了DatabaseHelper的getWritableDatabase()方法或者getReadableDatabase()方法之后,才会创建或打开一个连接
db = dbHelper.getReadableDatabase();
}
/**
* 升级数据库
*/
void updateDatabase(){
DatabaseHelper dbHelper = new DatabaseHelper(ShowArtistDetail.this,2);
// 得到一个只读的SQLiteDatabase对象
SQLiteDatabase sqliteDatabase = dbHelper.getReadableDatabase();
}
/**
* 向指定的表中插入数据
*/
void insert(){
// 创建ContentValues对象
ContentValues values = new ContentValues();
// 向该对象中插入键值对,其中键是列名,值是希望插入到这一列的值,值必须和数据库当中的数据类型一致
values.put("id", 1);
values.put("name", "yangyz");
// 创建DatabaseHelper对象
// 调用insert方法,就可以将数据插入到数据库当中
// 第一个参数:表名称
// 第二个参数:SQl不允许一个空列,如果ContentValues是空的,那么这一列被明确的指明为NULL值
// 第三个参数:ContentValues对象
db.insert(Artist.ARTISTTABLENAME, null, values);
}
/**
* 跟新数据库中指定表的数据
*/
void update(){
// 创建一个ContentValues对象
ContentValues values = new ContentValues();
values.put("name", "zhangsan");
// 调用update方法
// 第一个参数String:表名
// 第二个参数ContentValues:ContentValues对象
// 第三个参数String:where字句,相当于sql语句where后面的语句,?号是占位符
// 第四个参数String[]:占位符的值
db.update(Artist.ARTISTTABLENAME, values, "id=?", new String[] { "1" });
System.out.println("-----------update------------");
}
/**
* 根据条件查询数据
*/
void select(){
// 调用SQLiteDatabase对象的query方法进行查询,返回一个Cursor对象:由数据库查询返回的结果集对象
// 第一个参数String:表名
// 第二个参数String[]:要查询的列名
// 第三个参数String:查询条件
// 第四个参数String[]:查询条件的参数
// 第五个参数String:对查询的结果进行分组
// 第六个参数String:对分组的结果进行限制
// 第七个参数String:对查询的结果进行排序
Cursor cursor = db.query(Artist.ARTISTTABLENAME, new String[] { "id",
"name" }, "id=?", new String[] { "1" }, null, null, null);
// 将光标移动到下一行,从而判断该结果集是否还有下一条数据,如果有则返回true,没有则返回false
while (cursor.moveToNext()) {
String id = cursor.getString(cursor.getColumnIndex("id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
System.out.println("-------------select------------");
System.out.println("id: "+id);
System.out.println("name: "+name);
}
}
/**
* 删除指定的表中的数据
*/
void delete(){
//调用SQLiteDatabase对象的delete方法进行删除操作
//第一个参数String:表名
//第二个参数String:条件语句
//第三个参数String[]:条件值
db.delete(Artist.ARTISTTABLENAME, "id=?", new String[]{"1"});
System.out.println("----------delete----------");
}
}
//这里有一个写的很好Sqlite的博文:我是参考这个写的,
http://byandby.iteye.com/blog/835580
那么我们什么时候呀使用contentProvider,contentProvider是数据共享的一个抽象的概念:
其中ContentProvider负责
- 组织应用程序的数据;
- 向其他应用程序提供数据;
ContentResolver则负责
- 获取ContentProvider提供的数据;
- 修改/添加/删除更新数据等;
ContentProvider 是如何向外界提供数据的?
Android提供了ContentProvider,一个程序可以通过实现一个ContentProvider的抽象接口将自己的数据完全暴露出去,而且ContentProviders是以类似数据库中表的方式将数据暴露,也就是说ContentProvider就像一个“数据库”。那么外界获取其提供的数据,也就应该与从数据库中获取数据的操作基本一样,只不过是采用URI来表示外界需要访问的“数据库”。至于如何从URI中识别出外界需要的是哪个“数据库”,这就是Android底层需要做的事情了,不在此详细说。简要分析下ContentProvider向外界提供数据操作的接口:
query(Uri, String[], String, String[], String)
update(Uri, ContentValues, String, String[])
这些操作与数据库的操作基本上完全一样,在此不详细说,具体的解析可以参考Android Sqlite解析篇中的详细说明。需要特殊说明的地方是URI:
在URI的D部分可能包含一个_ID ,这个应该出现在SQL语句中的,可以以种特殊的方式出现,这就要求我们在提供数据的时候,需要来额外关注这个特殊的信息。Android SDK推荐的方法是:在提供数据表字段中包含一个ID,在创建表时INTEGER PRIMARY KEY AUTOINCREMENT标识此ID字段。
ContentProvider 是如何组织数据的?
组织数据主要包括:存储数据,读取数据,以数据库的方式暴露数据。数据的存储需要根据设计的需求,选择合适的存储结构,首选数据库,当然也可以选择本地其他文件,甚至可以是网络上的数据。数据的读取,以数据库的方式暴露数据这就要求,无论数据是如何存储的,数据最后必须以数据的方式访问。
可能还有2个问题,是需要关注的。
- ContentProvider是什么时候创建的,是谁创建的?访问某个应用程序共享的数据,是否需要启动这个应用程序?这个问题在Android SDK中没有明确说明,但是从数据共享的角度出发,ContentProvider应该是Android在系统启动时就创建了,否则就谈不上数据共享了。这就要求在AndroidManifest.XML中使用<provider>元素明确定义。
- 可能会有多个程序同时通过ContentResolver访问一个ContentProvider,会不会导致像数据库那样的“脏数据”?这个问题一方面需要数据库访问的同步,尤其是数据写入的同步,在AndroidManifest.XML中定义ContentProvider的时候,需要考虑是<provider>元素multiprocess属性的值;另外一方面Android在ContentResolver中提供了notifyChange()接口,在数据改变时会通知其他ContentObserver,这个地方应该使用了观察者模式,在ContentResolver中应该有一些类似register,unregister的接口。
至此,已经对ContentProvider提供了比较全面的分析,至于如何创建ContentProvider,可通过2种方法:创建一个属于你自己的ContentProvider或者将你的数据添加到一个已经存在的ContentProvider中,当然前提是有相同数据类型并且有写入Content provider的权限。在Android SDK的sample中提供的Notepad具体实例中去看源代码!
/**
* 使用contentProvider来添加数据
*/
btn_add_content.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View view)
{
ContentResolver contentResolver = BeginActivity.this.getContentResolver();
ContentValues values = new ContentValues();
values.put(ArtistConstant.NAME, et_name.getText().toString());
values.put(ArtistConstant.SEX, et_sex.getText().toString());
//程序通过ArtistConstant.Artist.CONTENT_URI找到对应的ContentProvider的子类。也就是对那个数据库中的表来操作
Uri result = contentResolver.insert(ArtistConstant.Artist.CONTENT_URI, values);
System.out.println(result.toString());
}
});
//在常量类中的定义CONTENT_URI 的值是
public static final Uri CONTENT_URI = Uri.parse("content://com.webabcd.MyContentProvider/");
在androidManifrest.Xml需要定义一个
<provider android:name="MyContentProvider" android:authorities="com.webabcd.MyContentProvider"></provider>
//MyContentProvider使我们继承ContentProvider的子类。那么上面的Uri result = contentResolver.insert(ArtistConstant.Artist.CONTENT_URI, values);这句话就表示我们使用指定的contentProvider来进行数据的操作。他现在相当于是调用者,这个操作我们同样想可以写在其他的应用程序中同样可以调用只要CONTENT_URI相同就可以了。