Android-ContentProvider原理及流程
Android为什么设计出一个ContentProvider ?
答:ContentProvider的出现主要是暴露数据出去,暴露什么数据呢 (暴露数据库SqliteDatabase里面的数据),由ContentProvider管控好增删改查,让其他应用程序来访问增删改查
Android设计了intent-filter对外暴露(可以隐式意图激活/远程服务绑定通讯)这属于最组件的暴露,而ContentProvider属于数据库的暴露
ContentProvider属于四大组件之一,Android把它设计成组件,说明ContentProvider是很重要的,Android操作系统源码APP几乎都大量用ContentProvider暴露了数据。
流程图:
注意:在ContentProvider里面写对数据库增删改查的时候,千万不能 db.close(); cursor.close(); 等操作,不然其他应用访问不到数据,也没有必要写isOpen();
ContentProviderServer应用
ContentProvider是抽象类,所以写一个类继承ContentProvider,重写增删改查系列方法
package liudeli.cp.server.cp; import android.content.ContentProvider; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.util.Log; public class MyContentProvider extends ContentProvider { private final String TAG = MyContentProvider.class.getSimpleName(); /** * 只要在AndroidManifest.xml中配置了provider组件 * 应用打开后,会自动启动此方法 * @return */ @Override public boolean onCreate() { Log.d(TAG, "onCreate()"); return false; } /** * 查询 * @param uri 其他应用传递过来的Uri * @param projection 其他应用传递过来的查询列 * @param selection 其他应用传递过来的查询条件 * @param selectionArgs 其他应用传递过来的查询条件参数值 * @param sortOrder 其他应用传递过来的排序 * @return */ @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Log.d(TAG, "查询到了数据...."); return null; } /** * 增加 * @param uri 其他应用传递过来的Uri * @param values 其他应用传递过来的ContentValues * @return */ @Override public Uri insert(Uri uri, ContentValues values) { Log.d(TAG, "插入了数据...."); return null; } /** * 修改 * @param uri 其他应用传递过来的Uri * @param values 其他应用传递过来的ContentValues * @param selection 其他应用传递过来的查询条件 * @param selectionArgs 其他应用传递过来的查询条件参数值 * @return */ @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { Log.d(TAG, "修改了数据...."); return 0; } /** * 删除 * @param uri 其他应用传递过来的Uri * @param selection 其他应用传递过来的查询条件 * @param selectionArgs 其他应用传递过来的查询条件参数值 * @return */ @Override public int delete(Uri uri, String selection, String[] selectionArgs) { Log.d(TAG, "删除了数据...."); return 0; } /** * 得到类型 在后续的博客中会有讲解到 * @param uri * @return */ @Override public String getType(Uri uri) { return null; } }
在AndroidManifest.xml文件中,配置ContentProvider组件,然后对外暴露数据(设置授权唯一标识,允许对外输出,允许实例化激活)等操作
<!-- ContentProvider是组件需要配置 可以把ContentProvider看作是服务器 authorities 看作是服务器 服务器有访问的链接,authorities(授权) ,是唯一标识 android:enabled="true" 可以被系统实例化 android:exported="true" 允许对外输出 --> <provider android:authorities="autho.prov.cp.MyContentProvider" android:name=".cp.MyContentProvider" android:enabled="true" android:exported="true" />
启动ContentProviderServer应用,注意看:一启动ContentProviderServer应用,就会自动初始化 MyContentProvider --> onCreate()方法
12-14 09:22:55.187 2013-2013/liudeli.cp.server D/MyContentProvider: onCreate()
ContentProviderClient应用
点击Test按钮,成功调用到 ContentProviderServer应用的 MyContentProvider -- > query() 方法
package liudeli.cp.client; import android.content.ContentResolver; import android.net.Uri; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void test(View view) { /** * 可以想象客户端访问服务器,需要需要用到协议HTTP * 而想访问ContentProvider,需要ContentResolver */ ContentResolver contentProvider = getContentResolver(); /** * 可以想象访问服务器,需要这样拼接访问地址 http:// * 而想访问ContentProvider,需要这样拼接访问地址 content:// * 必须拿到暴露的授权authorities="autho.prov.cp.MyContentProvider" 进行拼接 */ Uri uri = Uri.parse("content://autho.prov.cp.MyContentProvider"); // 查询 contentProvider.query(uri, null, null, null, null, null); // 增加 // contentProvider.insert(uri, null); // 修改 // contentProvider.update(uri, null, null, null); // 删除 // contentProvider.delete(uri, null, null); } }
ContentProviderServer应用的 MyContentProvider -- > query() 方法
12-14 09:44:59.955 2013-2031/liudeli.cp.server D/MyContentProvider: 查询到了数据....