由于牵涉到两个应用程序,布局文件等等等等的东西太多,每个项目还不一样。我这里就拉出重点的思路,详细讲解一下。
我们的思路是这样,一个程序使用ContentProvider连接数据库的查询接口。另一个程序使用ContentResolver,连接ContentProvider的查询接口,思路很简单,接下来我们先来看看ContentProvider。
ContentProvider的使用还是很方便的,只需要继承该类,实现抽象方法就可以了,之后会详细说,我先把我代码中的类写出来,方便之后讲解
public class SQLiteProvider extends ContentProvider
首先还是看权限,如果在完全分离的不同应用程序下,需要允许外部应用接入我们应用下的Provider,就需要在AndroidManifest里去注册这个Provider,就和注册Activity一样
<provider
android:authorities="com.ty.messagedb_provider_demo1.util.SQLite.Provider.SQLiteProvider"
android:name=".util.SQLite.Provider.SQLiteProvider"
android:exported="true">
</provider>
注册的语句一共有三条
第一条authoritiess,应该填的是需要注册的Provider的全名(我是理解成,这个名字是给外部应用调用的时候匹配的)
第二条name,就是指定继承了ContentProvider这个类的所属位置(这个应该是内部定位)
第三条exported就是权限的设置,true是允许外部接入,false反之
好了 准备工作做完,我们看如何实现ContentProvider这个类
按照我们的思路,我们是需要通过provider去访问数据库的
我这里已经创建好了,SQLiteOpenHelper 和 SQLiteDAO并实现了query查询方法,和insert插入方法,之前有专门博客讲解,我这里就直接跳过了
当继承了ContentProvider这个类之后,需要实现他的几个方法,其实我感觉就是一层接口,看了就明白了,我先把他们列出来,一会再实现
public boolean onCreate()
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
public String getType(Uri uri)
public Uri insert(Uri uri, ContentValues values)
public int delete(Uri uri, String selection, String[] selectionArgs)
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
方法列出来了,那我们还需要操作数据库啊,那就还需要DB
SQLiteDatabase db;
我们所需要的元素都集齐了,接下来就来看方法吧
onCreate这个方法已经太常见了,那Provider的OnCreate什么时候被调用呢
我给activity的oncreate onStrat onResume打上了Log
02-22 08:30:48.393 21046-21046/com.ty.messagedb_provider_demo1 D/Provider: OnCreate
02-22 08:30:48.613 21046-21046/com.ty.messagedb_provider_demo1 D/Provider: Activity OnCreate
02-22 08:30:48.613 21046-21046/com.ty.messagedb_provider_demo1 D/Provider: Activity onStart
02-22 08:30:48.613 21046-21046/com.ty.messagedb_provider_demo1 D/Provider: Activity onResume
结果是这样的,说明他与activity其实是没有关系的,在程序编译阶段,或者之后一点点,他就会创建
下面是完整的OnCreate方法
public boolean onCreate() {
SQLiteHelper sqLiteHelper = new SQLiteHelper(getContext());
db = sqLiteHelper.getReadableDatabase();
Log.d("Provider", "OnCreate");
return true;
}
注意返回值
true if the provider was successfully loaded, false otherwise
直接看代码可能好理解一点
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Cursor cursor = db.query(SQLiteHelper.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
return cursor;
}
我这里要附上一段英文的解释,很详细,虽然我还么i仔细看,但是我一定会看的,如果我看完以后,我会在中间插入中文的解释
/** * Implement this to handle query requests from clients. * This method can be called from multiple threads, as described in * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes * and Threads</a>. * <p> * Example client call:<p> * <pre>// Request a specific record. * Cursor managedCursor = managedQuery( ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2), projection, // Which columns to return. null, // WHERE clause. null, // WHERE clause value substitution People.NAME + " ASC"); // Sort order.</pre> * Example implementation:<p> * <pre>// SQLiteQueryBuilder is a helper class that creates the // proper SQL syntax for us. SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder(); // Set the table we're querying. qBuilder.setTables(DATABASE_TABLE_NAME); // If the query ends in a specific record number, we're // being asked for a specific record, so set the // WHERE clause in our query. if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){ qBuilder.appendWhere("_id=" + uri.getPathLeafId()); } // Make the query. Cursor c = qBuilder.query(mDb, projection, selection, selectionArgs, groupBy, having, sortOrder); c.setNotificationUri(getContext().getContentResolver(), uri); return c;</pre> * * @param uri The URI to query. This will be the full URI sent by the client; * if the client is requesting a specific record, the URI will end in a record number * that the implementation should parse and add to a WHERE or HAVING clause, specifying * that _id value. * @param projection The list of columns to put into the cursor. If * {@code null} all columns are included. * @param selection A selection criteria to apply when filtering rows. * If {@code null} then all rows are included. * @param selectionArgs You may include ?s in selection, which will be replaced by * the values from selectionArgs, in order that they appear in the selection. * The values will be bound as Strings. * @param sortOrder How the rows in the cursor should be sorted. * If {@code null} then the provider is free to define the sort order. * @return a Cursor or {@code null}. */
好了,因为只需要提供给外部应用查询,我就只实现了这两个接口,接下来就是Solver的时间了,因为之前已经写过一篇了,我这里就快速点
定义需要的变量
ListView listView;
ListBaseAdapter adapter;
ArrayList<MessageData> dataList;
ContentResolver resolver;
实现
listView = (ListView) findViewById(R.id.LV_Main_ListView);
dataList = new ArrayList<>();
resolver = getContentResolver();
接下来就是唯一的新内容
Cursor cursor = resolver.query(Uri.parse("content://com.ty.messagedb_provider_demo1.util.SQLite.Provider.SQLiteProvider"), new String[]{"message", "type", "time"},
null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
dataList.add(new MessageData(cursor.getString(cursor.getColumnIndex("message")),
cursor.getInt(cursor.getColumnIndex("type")),
cursor.getLong(cursor.getColumnIndex("time"))));
}
cursor.close();
}
注意resolber.query的第一个参数 他需要的是一个Uri,并且这个获取的格式是固定的,后面的内容其实就是我们在Provider的AndroidManifest的注册的第一条authoritiess,
然后就能通过Resolver的query去调用Provider的query最后去调用我们SQLite的query,就是这个逻辑
好了,之后就是一下数据设置,大家看看就可以了
adapter = new ListBaseAdapter(this, dataList);
listView.setAdapter(adapter);
这样内容就讲完了,梳理一遍,自己的记忆也更清晰哈