1、编写一个类,必须继承自ContentProvider类;
2、实现ContentProvider类中所有的抽象方法;
需要实现:onCreate() 、getType() 、query() 、insert() 、update()、delete() 等方法。
【备注:】
ContentProvider暴露出来的数据和方法并不是给自身调用的,而是给其他应用程序来调用。其他应用程序通过其ContentResolver对象调用的query() 、insert() 、update()、delete() 等方法就是我们在这里暴露出来的ContentProvider类中的重写后的query() 、insert() 、update()、delete() 方法。
3、定义ContentProvider的Uri。这个Uri是ContentResolver对象执行CRUD操作时重要的参数;
4、使用UriMatcher对象映射Uri返回代码;
5、在AndroidMainfest.xml文件中使用
(二)、ContentProvider类中的六个抽象方法:
1、boolean onCreate()
2、Uri insert(Uri uri, ContentValues values)
3、int delete(Uri uri, String selection, String[] selectionArgs)
4、int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
5、Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
6、String getType(Uri uri)
(三)、ContentProvider类中六个抽象方法的说明:
1、onCreate() 初始化provider
2、query() 返回数据给调用者
3、insert() 插入新数据到ContentProvider
4、update() 更新ContentProvider已经存在的数据
5、delete() 从ContentProvider中删除数据
6、getType() 返回ContentProvider数据的Mime类型
(四)、在清单文件中声明注册ContentProvider:
android:authorities="com.steven.wordscontentprovider"
android:exported="true"
/>
//android:name属性的值是:ContentProvider类的子类的完整路径;
//android:authorities属性的值是:content:URI中authority部分。一般就是将name属性的值全小写。
//android:exported属性是否允许其他应用调用。如果是false,则该ContentProvider不允许其他应用调用。
private static UriMatcher matcher = null;
static {
// 定义一个Uri匹配器。将UriMatcher.NO_MATCH,即-1作为参数。
matcher = new UriMatcher(UriMatcher.NO_MATCH);
// 定义一组匹配规则
matcher.addURI(AUTHORITY, "words", 1);
matcher.addURI(AUTHORITY, "newwords", 2);
}
一、清单配置文件中注册ContentProvider:
android:authorities="com.steven.wordscontentprovider"
android:exported="true"
/>
二、ContentProvider 的程序部分:
public class MyWordsProvider extends ContentProvider {
private MySQLiteOpenHelper dbHelper = null;
private SQLiteDatabase db = null;
private static UriMatcher matcher = null;
private static final String AUTHORITY = "com.steven.wordscontentprovider";
static {
matcher = new UriMatcher(UriMatcher.NO_MATCH);
matcher.addURI(AUTHORITY, "words", 1);
matcher.addURI(AUTHORITY, "newwords", 2);
}
@Override
public boolean onCreate() {
dbHelper = new MySQLiteOpenHelper(getContext());
db = dbHelper.getReadableDatabase();
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
switch (matcher.match(uri)) {
case 1:
Cursor cursor = db.query("tb_words", projection, selection,
selectionArgs, null, null, sortOrder);
return cursor;
case 2:
Cursor cursor2 = db.query("tb_newwords", projection, selection,
selectionArgs, null, null, sortOrder);
return cursor2;
default:
break;
}
return null;
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
long rowId = 0;
switch (matcher.match(uri)) {
case 1:
rowId = db.insert("tb_words", null, values);
if (rowId > 0) {
Uri newUri = ContentUris.withAppendedId(
Uri.parse("content://" + AUTHORITY + "/words"), rowId);
// 通知监听器,数据已经改变
getContext().getContentResolver().notifyChange(newUri, null);
return newUri;
}
break;
case 2:
rowId = db.insert("tb_newwords", null, values);
if (rowId > 0) {
Uri newUri = ContentUris.withAppendedId(
Uri.parse("content://" + AUTHORITY + "/newwords"),
rowId);
// 通知监听器,数据已经改变
getContext().getContentResolver().notifyChange(newUri, null);
return newUri;
}
break;
default:
break;
}
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
switch (matcher.match(uri)) {
case 1:
int count = db.delete("tb_words", selection, selectionArgs);
if (count > 0) {
// 通知监听器,数据已经改变
getContext().getContentResolver().notifyChange(uri, null);
}
return count;
case 2:
int count2 = db.delete("tb_newwords", selection, selectionArgs);
if (count2 > 0) {
// 通知监听器,数据已经改变
getContext().getContentResolver().notifyChange(uri, null);
}
return count2;
default:
break;
}
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
switch (matcher.match(uri)) {
case 1:
int count = db.update("tb_words", values, selection, selectionArgs);
if (count > 0) {
// 通知监听器,数据已经改变
getContext().getContentResolver().notifyChange(uri, null);
}
return count;
case 2:
int count2 = db.update("tb_newwords", values, selection,
selectionArgs);
if (count2 > 0) {
// 通知监听器,数据已经改变
getContext().getContentResolver().notifyChange(uri, null);
}
return count2;
default:
break;
}
return 0;
}
}
二、Java知识回顾:
(一)、静态代码块的作用:
一般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的。静态代码块和静态方法两者的区别就是:静态代码块是自动执行的;静态方法是被调用的时候才执行的。
1、在Java里,可以定义一个不需要创建对象的方法,这种方法就是静态方法。要实现这样的效果,只需要在类中定义的方法前加上static关键字。例如:
public static int maximum(int n1,int n2)
使用类的静态方法时,注意:
2、静态变量属于整个类,而不是属于某个对象的。注意不能把任何方法体内的变量声明为静态,例如:
fun() {
static int i=0;//非法。
}
3、一个类可以使用不包含在任何方法体中的静态代码块,当类被载入时,静态代码块被执行,且只被执行一次,静态块常用来执行类属性的初始化。例如:
static {
}
(二)、对象的初始化顺序:
静态代码块对象的初始化顺序 :内容先执行,接着执行父类非静态代码块和构造方法,然后执行子类非静态代码块和构造方法。
注意:子类的构造方法,不管这个构造方法带不带参数,默认的它都会先去寻找父类的无参构造方法。如果父类没有无参构造方法,那么子类必须用super关键子来调用父类带参构造方法,否则编译不能通过。
(三)、类装载步骤:
在Java中,类装载器把一个类装入Java虚拟机中,要经过三个步骤来完成:装载、链接和初始化,其中链接又可以分成校验、准备和解析三步,除了解析外,其它步骤是严格按照顺序完成的,各个步骤的主要工作如下:
1、装载:查找和导入类或接口的二进制数据;
三、UriMatcher对象的addURI方法的#和*问题:
(一)、#和*的含义:
1、UriMatcher.addURI(String authority, String path, int code)
Parameters:
authority the authority to match
path the path to match. * may be used as a wild card for any text, and # may be used as a wild card for numbers.
code the code that is returned when a URI is matched against the given components. Must be positive.
*和#是两个通配符,它们用在uri地址中,*可以匹配任何文本,#匹配任何数字。
(二)、截取Uri地址和拼接Uri地址的方法:【重点】
1、Uri对象的截取方法:
2、Uri对象的拼接方法:
3、ContentUris对象的截取id的方法:
4、ContentUris对象的拼接id的方法:
【备注:】Content URIs 的语法规则:content://authority/path/id
(三)、创建ContentProvider的示例代码:
1、MyProvider.java中的核心代码:
public class MyProvider extends ContentProvider {
private MySQLiteOpenHelper dbHelper = null;
private SQLiteDatabase db = null;
private static UriMatcher matcher = null;
private static final String AUTHORITY = "com.steven.contentprovider.mywordsprovider";
static {
matcher = new UriMatcher(-1);
matcher.addURI(AUTHORITY, "words", 1);
matcher.addURI(AUTHORITY, "newwords", 2);
matcher.addURI(AUTHORITY, "words/*", 3);// 匹配任何文本
matcher.addURI(AUTHORITY, "words_id/#", 4);// 匹配任何数字
matcher.addURI(AUTHORITY, "words_zh/*", 5);// 匹配任何中文文本
}
@Override
public boolean onCreate() {
dbHelper = new MySQLiteOpenHelper(this.getContext());
db = dbHelper.getReadableDatabase();
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
switch (matcher.match(uri)) {
case 1:
return db.query("tb_words", projection, selection, selectionArgs,
null, null, sortOrder);
case 2:
return db.query("tb_newwords", projection, selection,
selectionArgs, null, null, sortOrder);
case 3:
Log.i("MyProvider", "==返回值是:" + matcher.match(uri));
String data = uri.getLastPathSegment();
Log.i("MyProvider", "==" + data);
return db.query("tb_words", projection, "word like ?",
new String[] { data + "%" }, null, null, sortOrder);
case 4:
Log.i("MyProvider", "==返回值是:" + matcher.match(uri));
String data2 = uri.getLastPathSegment();
// long id = ContentUris.parseId(uri);
Log.i("MyProvider", "==" + data2);
return db.query("tb_words", projection, "_id=?",
new String[] { data2 }, null, null, sortOrder);
case 5:
String data3 = uri.getLastPathSegment();
return db.query("tb_words", projection, "detail like ?",
new String[] { data3 + "%" }, null, null, sortOrder);
default:
Log.i("MyProvider", "==返回值是:" + matcher.match(uri));
return null;
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
switch (matcher.match(uri)) {
case 1:
long id = db.insert("tb_words", null, values);
return Uri.parse("content://" + AUTHORITY + "/words/" + id);
case 2:
long id2 = db.insert("tb_newwords", null, values);
return Uri.parse("content://" + AUTHORITY + "/newwords/" + id2);
}
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
switch (matcher.match(uri)) {
case 1:
return db.delete("tb_words", selection, selectionArgs);
case 2:
return db.delete("tb_newwords", selection, selectionArgs);
}
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
switch (matcher.match(uri)) {
case 1:
return db.update("tb_words", values, selection, selectionArgs);
case 2:
return db.update("tb_newwords", values, selection, selectionArgs);
}
return 0;
}
@Override
public String getType(Uri uri) {
return null;
}
}
2、日志截图:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<SearchView
android:id="@+id/searchView_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
SearchView>
<ListView
android:id="@+id/listView_main"
android:layout_width="match_parent"
android:layout_height="match_parent" >
ListView>
LinearLayout>
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private ListView listView_main;
private SearchView searchView_main;
private MySQLiteOpenHelper dbHelper = null;
private SQLiteDatabase db = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView_main = (ListView) findViewById(R.id.listView_main);
searchView_main = (SearchView) findViewById(R.id.searchView_main);
dbHelper = new MySQLiteOpenHelper(this);
db = dbHelper.getReadableDatabase();
// SearchView控件的监听器:查询文本监听器OnQueryTextListener
searchView_main.setOnQueryTextListener(new OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
// 当查询内容发生改变时执行该方法
@Override
public boolean onQueryTextChange(String newText) {
fillListView(newText);
return false;
}
});
}
public void fillListView(String data) {
Cursor cursor = null;
ContentResolver resolver = getContentResolver();
Uri uri_words = Uri
.parse("content://com.steven.contentprovider.mywordsprovider/words");
// 如果查询的关键词为空,则执行没有where条件的查询,也就是显示所有数据。
if (data != null && !"".equals(data)) {
// 如果查询关键词不为空,则在原来的uri地址后追加需要查询的内容
uri_words = Uri.withAppendedPath(uri_words, data);
}
cursor = resolver.query(uri_words, null, null, null, null);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
R.layout.item_listview_main, cursor, new String[] { "word",
"detail" }, new int[] { R.id.text_item_word,
R.id.text_item_detail }, 2);
listView_main.setAdapter(adapter);
}
/*
* 以下代码跟本案例《SearchView实现查询》无关,而是测试Cursor是否为null的例子。
* 如果数据库的表为空,返回的Cursor是否为null? 结果证明cursor都不为null,只不过其中没有数据而已,但是存在表结构。
* 也就是说:即便是没有一条数据的cursor也可以获取到列名称。
*/
public void clickButton(View view) {
switch (view.getId()) {
case R.id.button_main_show:
// 第一种cursor的生成方法
String sql = "select id ,abc from tb_words";
Cursor cursor1 = dbHelper.selectCursor(sql, null);
// 第二种cursor的生成方法
Cursor cursor2 = db.query("tb_words", null, null, null, null, null,
null);
if (!cursor1.moveToFirst()) {
Toast.makeText(this, "数据为空!", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, cursor1.moveToFirst() + "",
Toast.LENGTH_LONG).show();
String[] arrClos = cursor1.getColumnNames();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < arrClos.length; i++) {
sb.append(arrClos[i]);
sb.append(",");
}
Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show();
}
break;
default:
break;
}
}
}