一 ContentProvider简介
ContentProvider是四大组件之一 用来暴露应用里面的数据给其它应用访问
Uri: 代表了要操作的数据 Uri主要包含了 需要操作的内容提供者 和 内容提供者中需要操作的指定数据
UriMatcher: 用于匹配Uri
ContentUris: 用于操作Uri路径后面的参数部分
ContentProvider: 内容提供者 用于对外共享数据
ContentResolver: 内容解决者 用于外部应用中 操作指定Uri内容提供者里面数据
ContentObserver: 内容观察者 用于外部应用中 监听指定Uri内容提供者里面数据变化
AsyncQueryHandler: 用于执行内容解决者的耗时操作 多用于查询
二 举个例子
ContentProvider作为一个应用程序名叫Provider
ContentResolver作为一个应用程序名叫Resolver
ContentObserver作为一个应用程序名叫Observer
Provider端
1. 新建一个SQLiteOpenHelper
public class SQLiteUtils extends SQLiteOpenHelper { private static final String DB_NAME = "test.db"; private static final int DB_VERSION = 1; private static SQLiteOpenHelper mInstance; private SQLiteUtils(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); } public static synchronized SQLiteOpenHelper newInstance(Context context) { if (null == mInstance) { mInstance = new SQLiteUtils(context, DB_NAME, null, DB_VERSION); //数据库的版本号 如果版本号不同 执行onUpgrade()方法 } return mInstance; } @Override public void onCreate(SQLiteDatabase db) { // 创建表 String sql = "CREATE TABLE android_account (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "name TEXT NOT NULL, " + "money INTEGER NOT NULL)"; db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // 数据库升级(在数据库版本发生变化时会被调用 一般在软件升级时才需改变版本号) String sql = "ALTER TABLE android_account ADD age INTEGER"; db.execSQL(sql); } }
2. 新建一个ContentProvider
public class MyContentProvider extends ContentProvider { private static final String AUTHORITY = "com.hy.provider.provider.MyContentProvider"; private static final int ANDROID_ACCOUNT = 10010; private static UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH); static{ // authority(授权) + path(一般是表名) = uri = code(唯一标识) sMatcher.addURI(AUTHORITY, "android_account", ANDROID_ACCOUNT); //content://authority/android_account } private SQLiteOpenHelper mHelper; //数据库帮助类 @Override public boolean onCreate() { mHelper = SQLiteUtils.newInstance(getContext()); return false; } @Nullable @Override public String getType(@NonNull Uri uri) { return null; } @Nullable @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { SQLiteDatabase database = mHelper.getWritableDatabase(); switch (sMatcher.match(uri)) { case ANDROID_ACCOUNT: database.insert("android_account", null, values); break; default: // 如果匹配不上 对外抛出异常 throw new IllegalArgumentException("uri do not exist -> " + uri); } // SQLiteDatabase不需要手动关闭 内容提供者会自行维护 getContext().getContentResolver().notifyChange(uri, null); //发出改变通知 return null; } @Override public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { SQLiteDatabase database = mHelper.getWritableDatabase(); switch (sMatcher.match(uri)) { case ANDROID_ACCOUNT: database.delete("android_account", selection, selectionArgs); break; default: // 如果匹配不上 对外抛出异常 throw new IllegalArgumentException("uri do not exist -> " + uri); } // SQLiteDatabase不需要手动关闭 内容提供者会自行维护 getContext().getContentResolver().notifyChange(uri, null); //发出改变通知 return 0; } @Override public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { SQLiteDatabase database = mHelper.getWritableDatabase(); switch (sMatcher.match(uri)) { case ANDROID_ACCOUNT: database.update("android_account", values, selection, selectionArgs); break; default: // 如果匹配不上 对外抛出异常 throw new IllegalArgumentException("uri do not exist -> " + uri); } // SQLiteDatabase不需要手动关闭 内容提供者会自行维护 getContext().getContentResolver().notifyChange(uri, null); //发出改变通知 return 0; } @Nullable @Override public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) { SQLiteDatabase database = mHelper.getReadableDatabase(); Cursor cursor; switch (sMatcher.match(uri)) { case ANDROID_ACCOUNT: cursor = database.query("android_account", //表名 如果是多表联合查询 可以用逗号将两个表名分开 projection, //要查询出来的列名 selection, //查询条件子句 在条件子句允许使用占位符"?" selectionArgs, //selection语句中占位符的值 null, null, sortOrder); break; default: // 如果匹配不上 对外抛出异常 throw new IllegalArgumentException("uri do not exist -> " + uri); } // Cursor和SQLiteDatabase不需要手动关闭 内容提供者会自行维护 return cursor; } }
3. AndroidManifest.xml application节点里面配置provider
android:authorities="com.hy.provider.provider.MyContentProvider" android:exported="true" />
Resolver端
public class MainActivity extends AppCompatActivity implements View.OnClickListener { // android:authorities="com.hy.provider.provider.MyContentProvider" Uri mUri = Uri.parse("content://com.hy.provider.provider.MyContentProvider/android_account"); ContentResolver mResolver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.insert).setOnClickListener(this); findViewById(R.id.delete).setOnClickListener(this); findViewById(R.id.update).setOnClickListener(this); findViewById(R.id.select).setOnClickListener(this); findViewById(R.id.async).setOnClickListener(this); mResolver = getContentResolver(); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.insert: try { ContentValues values = new ContentValues(); values.put("name", "黄祎"); values.put("money", 222); mResolver.insert(mUri, values); } catch (Exception e) { e.printStackTrace(); } break; case R.id.delete: try { mResolver.delete(mUri, "id > ?", new String[]{"0"}); } catch (Exception e) { e.printStackTrace(); } break; case R.id.update: try { ContentValues values = new ContentValues(); values.put("money", 1100); mResolver.update(mUri, values, "id > ?", new String[]{"0"}); } catch (Exception e) { e.printStackTrace(); } break; case R.id.select: try { Cursor cursor = mResolver.query(mUri, new String[]{"id", "name", "money"}, null, null, null); while (cursor.moveToNext()) { int id = cursor.getInt(cursor.getColumnIndex("id")); String name = cursor.getString(cursor.getColumnIndex("name")); int money = cursor.getInt(cursor.getColumnIndex("money")); Log.i("HUANG", "id=" + id + ", name=" + name + ", money=" + money); } cursor.close(); } catch (Exception e) { e.printStackTrace(); } break; case R.id.async: // 查询的数据如果超级多 直接查询就可能导致ANR 这是一个耗时的操作 // Android专门设计了一个类 用于执行内容解决者的耗时操作 多用于查询 new QueryHandler(mResolver).startQuery(0, //查询的唯一标识 该参数会传递给onQueryComplete() null, //用来传递数据 该参数会传递给onQueryComplete() mUri, new String[]{"id", "name", "money"}, null, null, null); break; } } private class QueryHandler extends AsyncQueryHandler { public QueryHandler(ContentResolver cr) { super(cr); } @Override protected void onQueryComplete(int token, Object cookie, Cursor cursor) { super.onQueryComplete(token, cookie, cursor); while (cursor.moveToNext()) { int id = cursor.getInt(cursor.getColumnIndex("id")); String name = cursor.getString(cursor.getColumnIndex("name")); int money = cursor.getInt(cursor.getColumnIndex("money")); Log.i("HUANG", "id=" + id + ", name=" + name + ", money=" + money); } } } }
Observer端
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 注册内容观察者监听 getContentResolver().registerContentObserver(Uri.parse("content://com.hy.provider.provider.MyContentProvider/android_account"), true, //true = 监听指定Uri和指定Uri的子路径 new MyContentObserver(new Handler())); } private class MyContentObserver extends ContentObserver { public MyContentObserver(Handler handler) { super(handler); } @Override public void onChange(boolean selfChange) { super.onChange(selfChange); // 当内容提供者发出改变通知 该方法就会调用 Log.i("HUANG", "数据发生改变"); } } }