Android-ContentProvider数据库操作
来源:互联网 发布:数据库select into 编辑:程序博客网 时间:2024/06/05 06:47
在实际的开发过程中,Android提供了5种方式存储数据:
1.文件存储数据
2.使用 Sharedpreferences 存储数据
3.SQLite数据库存储数据
4.使用ContentProvider存储数据
5.网络存储数据
首先我们先简单了解下文件、SharedPreferred如何进行数据存储
1.文件存储操作
文件存储一般存储在sdcard或者ROM,当文件存储在ROM上时,如果是存储在除自己私有空间外(data/data/包名/),在其他地方是需要system系统权限的(http://my.oschina.net/zhoulc/blog/119282)。
文件IO流创建比较简单,就不详述了,在进行文件存储的时候注意两个路径方法就行。
存储到ROM:
Context mContext = XXXActivity.this;
mContext.getFilesDir().getAbsolutePath();
获取路径:/data/data/包名/files
存储到sdCard :
首先判断sdcard是否可用
Environment.getExternalStorageState()是否等于Environment.MEDIA_MOUNTED
Environment.getExternalStorageDirectory().getAbsolutePath()
对sdcard目录操作需要添加权限:
<!-- 添加对SDCARD的写权限 -->
< uses-permission android:name ="android.permission.WRITE_EXTERNAL_STORAGE" >
获取路径:/sdcard
拓展下 :支持u盘的移动设备,u盘一般都是挂载mnt/sda/sdal外设上面
顺带说下以前一直纠结的一个问题:
getApplicationContext() 生命周期是整个应用,应用摧毁它才摧毁
Activity.this的context属于activity ,activity 摧毁他就摧毁
2.通过Sharedpreferences进行数据存储
<span style=
"line-height:19px;"
>
private
final
static
String PERFS_NAME =
"com.zlc.test"
;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//存放
//第一个参数是存储时的名称,第二个参数则是文件的打开方式(Context.
MODE_PRIVATE)
SharedPreferences userInfo = getSharedPreferences(PERFS_NAME,
0
);
SharedPreferences.Editor editor = userInfo.edit();
editor.putString(
"userName"
,
"zhoulc"
);
editor.putString(
"passWord"
,
"ds"
);
editor.commit();
//读取
System.out.println(
"##########################################"
);
SharedPreferences readInfo = getSharedPreferences(PERFS_NAME,
0
);
String name = readInfo.getString(
"userName"
,
"no_name"
);
String psword = readInfo.getString(
"passWord"
,
"000000"
);
System.out.println(
"name = "
+name+
" password = "
+psword);
}</span>
1)getSharedPreferences有两个参数,第一个参数是存储时的名称, 第二个参数则是文件的打开方式(一般使用0或者Context.MODE_PRIVATE)
2)默认的模式为0或MODE_PRIVATE,如果访问其他应用中的Preference,前提条件是:该 preference创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE权限。
3)千万不要偷懒写成
userInfo.edit().putString("userName", "zhoulc");
userInfo.edit().putString("passWord", "ds");
userInfo.edit().commit();
edit()方法每次都要产生一个新的SharedPreferences.Edit类的对象,所以commit
之后数据没有存储成功。
3.其他几个就不详细介绍了,说下今天的重点ContentProvider
创建一个可对数据库进行操作的ContentProvider我们先要了解涉及到的知识点:
(1)Parcelable(实体类数据一般会用在进程之间通信)
http://my.oschina.net/zhoulc/blog/172163
(2)BaseColumns,这个类只是提供了两个字段,一个是"_id"一个是"_count",便于调用数据库时导致拼写错误,你也可以扩展它,或者自定义这么个,然后直接调用它的常量名,防止写sql语句时把列名拼错。
<span style=
"line-height:19px;"
>
package
android.provider;
public
interface
BaseColumns
{
/**
* The unique ID for a row.
* <P>Type: INTEGER (long)</P>
*/
public
static
final
String _ID =
"_id"
;
/**
* The count of rows in a directory.
* <P>Type: INTEGER</P>
*/
public
static
final
String _COUNT =
"_count"
;
}</span>
主要实现三个方法
创建数据库:public DatabaseHelper(Context context)
创建表:public void onCreate(SQLiteDatabase db)
更新表:public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
(4)UriMatcher用来匹配URI。
主要实现两个接口:
添加需要匹配的URI:MATCHER.addURI(String authority, String path, int code) 进行匹配返回定义的value;MATCHER.match(Uri uri)
例:
MATCHER.addURI(Information.AUTHORITY, "informations", INFORMATIONS);
MATCHER.addURI(Information.AUTHORITY, "informations/#", INFORMATION);
# 号为通配符
* 号为任意字符
(5)ContentUris一个工具类,主要是用来处理使用 "content" 约束的Uri对象,经常用到条件查询某个_ID的数据。
主要实现两个接口:
static long parseId(Uri contentUri) 将uri中的id解析出来,此方法返回的是一个long型的id。
static Uri withAppendedId(Uri contentUri, long id)在指定的uri后面添加一条id
为指定参数的记录。
(6)SQLiteDatabase,这个类是核心类,用于管理和操作SQLite数据库,几乎所有的数据库操作,最终都将由这个类完成。
(7)ContentProvider,提供数据库增删改查的接口。
主要实现接口:
public int delete(Uri uri, String selection, String[] selectionArgs)
public String getType(Uri uri)
public Uri insert(Uri uri, ContentValues values)
public boolean onCreate()
public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder)
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs)
(8)ContentResolver接口和ContentProvider类似,两个区别一个是用户是通过ContentResolver调用ContentProvider提供的接口。
以上类都只是简单介绍,有兴趣的朋友可以去研究下源码和实现过程。这里主要讲使用过程和一些注意细节。
4.ContentProvider 在使用过程中需要注意两点:
(1)在AndroidManifest.xml里面需要注册这个ContentProvider
<provider android:name=".MyProvider" android:authorities="com.zlc.provider.MyProvider" />
(2)当提供给其他进程调用(假如是其他应用),如果当前提供ContentProvider的应用在退出的时候把自己给kill掉了(这个时候ContentProvider也无法使用),则我们需要在AndroidManifest.xml里面再添加一条属性
android:process="com.zlc.provider.MyProvider"
为该组件指定一个不同的默认进程
5.下面贴一下具体实现代码:
(1)ContentProvider提供者TestContentProvider.apk实体类:Information.java
package
com.zlc.provider;
import
android.net.Uri;
import
android.os.Parcel;
import
android.os.Parcelable;
import
android.provider.BaseColumns;
public
class
Information
implements
Parcelable,BaseColumns{
public
final
static
String AUTHORITY =
"com.zlc.provider.MyProvider"
;
public
final
static
Uri CONTENT_URI = Uri.parse(
"content://"
+AUTHORITY+
"/informations"
);
//表字段
public
final
static
String INFO_ID =
"info_id"
;
public
final
static
String INFO_NAME =
"info_name"
;
public
final
static
String INFO_AGE =
"info_age"
;
private
String info_id,info_name,info_age;
public
Information(Parcel source){
info_id = source.readString();
info_name = source.readString();
info_age = source.readString();
}
public
String getInfo_id() {
return
info_id;
}
public
void
setInfo_id(String info_id) {
this
.info_id = info_id;
}
public
String getInfo_name() {
return
info_name;
}
public
void
setInfo_name(String info_name) {
this
.info_name = info_name;
}
public
String getInfo_age() {
return
info_age;
}
public
void
setInfo_age(String info_age) {
this
.info_age = info_age;
}
@Override
public
int
describeContents() {
// TODO Auto-generated method stub
return
0
;
}
@Override
public
void
writeToParcel(Parcel dest,
int
flags) {
// TODO Auto-generated method stub
dest.writeString(info_id);
dest.writeString(info_name);
dest.writeString(info_age);
}
public
final
static
Parcelable.Creator<Information> CREATOR =
new
Parcelable.Creator<Information>() {
@Override
public
Information createFromParcel(Parcel source) {
// TODO Auto-generated method stub
return
new
Information(source);
}
@Override
public
Information[] newArray(
int
size) {
// TODO Auto-generated method stub
return
new
Information[size];
}
};
}
package
com.zlc.provider;
import
android.content.ContentProvider;
import
android.content.ContentUris;
import
android.content.ContentValues;
import
android.content.Context;
import
android.content.UriMatcher;
import
android.database.Cursor;
import
android.database.sqlite.SQLiteDatabase;
import
android.database.sqlite.SQLiteOpenHelper;
import
android.net.Uri;
import
android.provider.BaseColumns;
import
android.util.Log;
public
class
MyProvider
extends
ContentProvider {
private
SQLiteDatabase sqDb;
private
DatabaseHelper helper;
// 数据库名
private
final
static
String DATABASE_NAME =
"zhoulc.db"
;
// 版本
private
static
final
int
DATABASE_VERSION =
1
;
// 表名
private
static
final
String TABLE_NAME =
"Information"
;
// 创建表的sql语句
private
final
static
String CREATE_TABLE =
"Create table "
+ TABLE_NAME
+
"( "
+Information._ID+
" integer primary key autoincrement,"
+ Information.INFO_ID
+
" TEXT,"
+ Information.INFO_NAME +
" TEXT,"
+ Information.INFO_AGE
+
" TEXT);"
;
// Declaration Datababsehelper
private
static
class
DatabaseHelper
extends
SQLiteOpenHelper {
public
DatabaseHelper(Context context) {
super
(context, DATABASE_NAME,
null
, DATABASE_VERSION);
}
@Override
public
void
onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL(CREATE_TABLE);
}
@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);
}
}
// UriMatcher add URI
private
static
final
UriMatcher MATCHER =
new
UriMatcher(
UriMatcher.NO_MATCH);
private
final
static
int
INFORMATIONS =
1
;
private
final
static
int
INFORMATION =
2
;
static
{
MATCHER.addURI(Information.AUTHORITY,
"informations"
, INFORMATIONS);
MATCHER.addURI(Information.AUTHORITY,
"informations/#"
, INFORMATION);
}
@Override
public
int
delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
sqDb = helper.getWritableDatabase();
int
count =
0
;
switch
(MATCHER.match(uri)) {
case
INFORMATIONS:
count = sqDb.delete(TABLE_NAME, selection, selectionArgs);
break
;
default
:
throw
new
IllegalArgumentException(
"Unkwon Uri:"
+ uri.toString());
}
return
count;
}
@Override
public
String getType(Uri uri) {
// TODO Auto-generated method stub
switch
(MATCHER.match(uri)) {
case
INFORMATIONS:
return
"vnd.android.cursor.dir/Information"
;
case
INFORMATION:
return
"vnd.android.cursor.item/Information"
;
default
:
throw
new
IllegalArgumentException(
"Unkwon Uri:"
+ uri.toString());
}
}
@Override
public
Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
sqDb = helper.getWritableDatabase();
Uri insertUri =
null
;
long
rowid =
0
;
switch
(MATCHER.match(uri)) {
case
INFORMATIONS:
rowid = sqDb.insert(TABLE_NAME, Information.INFO_ID, values);
insertUri = ContentUris.withAppendedId(uri, rowid);
Log.i(
"zhoulc"
,
"insert record...values:"
+ values.toString());
break
;
default
:
throw
new
IllegalArgumentException(
"Unkwon Uri:"
+ uri.toString());
}
return
insertUri;
}
@Override
public
boolean
onCreate() {
// TODO Auto-generated method stub
helper =
new
DatabaseHelper(getContext());
return
helper ==
null
?
false
:
true
;
}
@Override
public
Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// TODO Auto-generated method stub
sqDb = helper.getWritableDatabase();
switch
(MATCHER.match(uri)) {
case
INFORMATIONS:
Cursor cursor = sqDb.query(TABLE_NAME, projection, selection,
selectionArgs,
null
,
null
, sortOrder);
return
cursor;
case
INFORMATION:
//条件查询,
long
id = ContentUris.parseId(uri);
String where = Information._ID +
"="
+ id;
if
(selection !=
null
&& !
""
.equals(selection))
{
where = where +
" and "
+ selection;
}
return
sqDb.query(TABLE_NAME, projection, where, selectionArgs,
null
,
null
, sortOrder);
default
:
throw
new
IllegalArgumentException(
"unknow uri"
+ uri.toString());
}
}
@Override
public
int
update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
sqDb = helper.getWritableDatabase();
int
count =
0
;
switch
(MATCHER.match(uri)) {
case
INFORMATIONS:
count = sqDb.update(TABLE_NAME, values, selection, selectionArgs);
return
count;
default
:
throw
new
IllegalArgumentException(
"unknow uri"
+ uri.toString());
}
}
}
在同一个应用本身里面(进程)测试插入数据:MainActivity.java
package
com.zlc.provider;
import
android.app.Activity;
import
android.content.ContentValues;
import
android.content.Context;
import
android.content.pm.ApplicationInfo;
import
android.content.pm.PackageManager;
import
android.content.pm.PackageManager.NameNotFoundException;
import
android.net.Uri;
import
android.os.Bundle;
public
class
MainActivity
extends
Activity {
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
Context mContext = MainActivity.
this
;
Uri myUri = Information.CONTENT_URI;
ContentValues values =
new
ContentValues();
values.put(Information.INFO_NAME,
"zhoulc"
);
values.put(Information.INFO_AGE,
"99"
);
getContentResolver().insert(myUri, values);
}
}
其他应用里面测试(跨进程使用)
TestActivity.java
package
com.zlc.database;
import
android.app.Activity;
import
android.content.ContentResolver;
import
android.content.ContentValues;
import
android.database.Cursor;
import
android.net.Uri;
import
android.os.Bundle;
public
class
TestActivity
extends
Activity {
private
ContentResolver resolver;
public
final
static
String AUTHORITY =
"com.zlc.provider.MyProvider"
;
private
final
static
Uri CONTENT_URIS = Uri.parse(
"content://"
+AUTHORITY+
"/informations"
);
private
final
static
Uri CONTENT_URI = Uri.parse(
"content://"
+AUTHORITY+
"/informations/1"
);
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
resolver = getContentResolver();
//step 1 insert data
ContentValues values =
new
ContentValues();
values.put(
"info_name"
,
"zhoulc"
);
values.put(
"info_age"
,
"24"
);
insert(CONTENT_URIS,values);
//查询
Cursor cursor = query(CONTENT_URI,
null
,
null
,
null
,
null
);
if
(cursor !=
null
){
if
(cursor.moveToFirst()){
int
index[] =
new
int
[]{
cursor.getColumnIndex(
"info_id"
),
cursor.getColumnIndex(
"info_name"
),
cursor.getColumnIndex(
"info_age"
)
};
do
{
System.out.println(cursor.getString(index[
1
]));
System.out.println(cursor.getString(index[
2
]));
}
while
(cursor.moveToNext());
}
}
}
// 该方法用于往ContentProvider添加数据。
public
Uri insert(Uri uri,ContentValues values){
Uri dst = resolver.insert(uri, values);
return
dst;
}
// 该方法用于从ContentProvider删除数据。
public
int
delete(Uri uri,String where, String[] selectionArgs){
int
colums = resolver.delete(CONTENT_URI, where, selectionArgs);
return
colums;
}
// 该方法用于更新ContentProvider中的数据。
public
int
update(Uri uri,ContentValues values, String where, String[] selectionArgs){
int
colums = resolver.update(CONTENT_URI, values, where, selectionArgs);
return
colums;
}
// 该方法用于从ContentProvider中获取数据。
public
Cursor query(Uri uri,String[] projection, String where, String[] selectionArgs, String sortOrder){
Cursor cursor = resolver.query(CONTENT_URI, projection, where, selectionArgs, sortOrder);
return
cursor;
}
}
6.运行过程中遇到的一些问题以及如何解决
(1)Open quote is expected
for
attribute
"{1}"
associated with an element
type
"
android:authorities".
android:authorities=
"com.zlc.provider.MyProvider"
/
(2)E
/AndroidRuntime
( 4509): FATAL EXCEPTION: main
E
/AndroidRuntime
( 4509): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.zlc.provider
/com
.zlc.provider.MainActivity}: java.lang.IllegalArgumentException: Unknown URL content:
//com
.zlc.provider.MyProviderinformations
E
/AndroidRuntime
( 4509): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
E
/AndroidRuntime
( 4509): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
E
/AndroidRuntime
( 4509): at android.app.ActivityThread.access$600(ActivityThread.java:141)
E
/AndroidRuntime
( 4509): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
E
/AndroidRuntime
( 4509): at android.os.Handler.dispatchMessage(Handler.java:99)
E
/AndroidRuntime
( 4509): at android.os.Looper.loop(Looper.java:137)
E
/AndroidRuntime
( 4509): at android.app.ActivityThread.main(ActivityThread.java:5041)
E
/AndroidRuntime
( 4509): at java.lang.reflect.Method.invokeNative(Native Method)
E
/AndroidRuntime
( 4509): at java.lang.reflect.Method.invoke(Method.java:511)
E
/AndroidRuntime
( 4509): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
E
/AndroidRuntime
( 4509): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
E
/AndroidRuntime
( 4509): at dalvik.system.NativeStart.main(Native Method)
E
/AndroidRuntime
( 4509): Caused by: java.lang.IllegalArgumentException: Unknown URL content:
//com
.zlc.provider.MyProviderinformations
E
/AndroidRuntime
( 4509): at android.content.ContentResolver.insert(ContentResolver.java:862)
E
/AndroidRuntime
( 4509): at com.zlc.provider.MainActivity.onCreate(MainActivity.java:17)
E
/AndroidRuntime
( 4509): at android.app.Activity.performCreate(Activity.java:5104)
E
/AndroidRuntime
( 4509): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
E
/AndroidRuntime
( 4509): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
E
/AndroidRuntime
( 4509): ... 11
more
W
/ActivityManager
( 2138): Force finishing activity com.zlc.provider/.MainActivity
D
/dalvikvm
( 2138): GC_FOR_ALLOC freed 596K, 13%
free
7327K
/8412K
, paused 63ms, total 63ms
(3)E
/AndroidRuntime
( 5411): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.zlc.provider
/com
.zlc.provider.MainActivity}: android.database.sqlite.SQLiteException: near
"tableInformation"
: syntax error (code 1): ,
while
compiling: Create tableInformation(_id integer primary key autoincrement,info_idTEXT,info_nameTEXT,info_ageTEXT);
E
/AndroidRuntime
( 5411): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
E
/AndroidRuntime
( 5411): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
E
/AndroidRuntime
( 5411): at android.app.ActivityThread.access$600(ActivityThread.java:141)
E
/AndroidRuntime
( 5411): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
E
/AndroidRuntime
( 5411): at android.os.Handler.dispatchMessage(Handler.java:99)
E
/AndroidRuntime
( 5411): at android.os.Looper.loop(Looper.java:137)
E
/AndroidRuntime
( 5411): at android.app.ActivityThread.main(ActivityThread.java:5041)
E
/AndroidRuntime
( 5411): at java.lang.reflect.Method.invokeNative(Native Method)
E
/AndroidRuntime
( 5411): at java.lang.reflect.Method.invoke(Method.java:511)
E
/AndroidRuntime
( 5411): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
E
/AndroidRuntime
( 5411): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
E
/AndroidRuntime
( 5411): at dalvik.system.NativeStart.main(Native Method)
E
/AndroidRuntime
( 5411): Caused by: android.database.sqlite.SQLiteException: near
"tableInformation"
: syntax error (code 1): ,
while
compiling: Create tableInformation(_id integer primary key autoincrement,info_idTEXT,info_nameTEXT,info_ageTEXT);
E
/AndroidRuntime
( 5411): at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
E
/AndroidRuntime
( 5411): at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:882)
E
/AndroidRuntime
( 5411): at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:493)
E
/AndroidRuntime
( 5411): at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
E
/AndroidRuntime
( 5411): at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
E
/AndroidRuntime
( 5411): at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:31)
E
/AndroidRuntime
( 5411): at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1663)
E
/AndroidRuntime
( 5411): at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1594)
E
/AndroidRuntime
( 5411): at com.zlc.provider.MyProvider$DatabaseHelper.onCreate(MyProvider.java:39)
E
/AndroidRuntime
( 5411): at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:252)
E
/AndroidRuntime
( 5411): at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
E
/AndroidRuntime
( 5411): at com.zlc.provider.MyProvider.insert(MyProvider.java:92)
E
/AndroidRuntime
( 5411): at android.content.ContentProvider$Transport.insert(ContentProvider.java:201)
E
/AndroidRuntime
( 5411): at android.content.ContentResolver.insert(ContentResolver.java:866)
E
/AndroidRuntime
( 5411): at com.zlc.provider.MainActivity.onCreate(MainActivity.java:17)
E
/AndroidRuntime
( 5411): at android.app.Activity.performCreate(Activity.java:5104)
E
/AndroidRuntime
( 5411): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
E
/AndroidRuntime
( 5411): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
E
/AndroidRuntime
( 5411): ... 11
more
W
/ActivityManager
( 2138): Force finishing activity com.zlc.provider/.MainActivity
+ "( _id integer primary key autoincrement," + Information.INFO_ID
+ " TEXT," + Information.INFO_NAME + " TEXT," + Information.INFO_AGE+ " TEXT);";
注意空格
代码下载
- Android-ContentProvider数据库操作
- Android-ContentProvider数据库操作
- android数据库操作(ContentProvider)
- Android ContentProvider之联系人数据库及操作
- ContentProvider操作数据库
- android中跨项目的数据库操作ContentProvider的使用
- Android基础之ContentProvider操作本地短信数据库
- ContentProvider操作数据库—一项古老的Android技术
- Android数据库 contentprovider
- Android之数据库ContentProvider
- android 玩转ContentProvider之一--实现ContentProvider操作数据库
- android 玩转ContentProvider之一--实现ContentProvider操作数据库
- Android--操作联系人的ContentProvider
- Android (SQLite 数据库与ContentProvider)
- Android数据库ContentProvider封装原理
- Android数据库ContentProvider封装原理
- android ContentProvider applyBatch数据库事务
- Android使用ContentProvider监听数据库
- tomcat绑定域名
- 关于PAE Paging与32-Bit Paging的区别
- 理解Python的with语句
- Oracle查询全部表信息
- Android开发过程中R文件的离奇消失
- Android-ContentProvider数据库操作
- oracle select into null的问题
- 有关Linux
- 【超清晰】并行和并发的区别
- Java并发编程:volatile关键字解析(四.深入剖析volatile关键字)
- Git
- phpStorm连接到服务器
- 百度启用新顶级域名baidu.news
- 句法结构可视化工具(成分句法)