ContentProvider使用难点
16lz
2021-01-26
1 ContentProvider的生命周期
直接看代码实例比较清晰,主要是onCreate和CRUD(增删改查)以及getType。首先需要在manifest声明,android:authorities是contentprovider的唯一标识。
(1) query、update、insert、delete存在多线程并发访问,需要做好线程同步。
(2) contentprovider的oncreate方法在application的oncreate方法之前执行。
访问contentprovider如下:
Uri uri = Uri.parse("content://com.cwx.test.Provider");getContentResolver().query(uri,null,null,null,null);
public class StudentContentProvider extends ContentProvider { //这里的AUTHORITY就是我们在AndroidManifest.xml中配置的authorities private static final String AUTHORITY = "com.cwx.test.provider"; //匹配成功后的匹配码1 private static final int MATCH_CODE = 100; //匹配成功后的匹配码2 private static final int MATCH_CODE1 = 101; private static UriMatcher uriMatcher; private StudentDao studentDao; private TeacherDao teacherDao; //数据改变后指定通知的Uri private static final Uri NOTIFY_URI = Uri.parse("content://" + AUTHORITY + "/student"); private static final Uri NOTIFY_URI1 = Uri.parse("content://" + AUTHORITY + "/teacher"); static { //匹配不成功返回NO_MATCH(-1) uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); //添加我们需要匹配的uri uriMatcher.addURI(AUTHORITY,"student", MATCH_CODE); //继续添加 uriMatcher.addURI(AUTHORITY,"teacher", MATCH_CODE1); } @Override public boolean onCreate() { studentDao = StudentDao.getInstance(getContext()); teacherDao = TeacherDao.getInstance(getContext()); return false; } @Nullable @Override public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) { int match = uriMatcher.match(uri); if (match == MATCH_CODE){ Cursor cursor = studentDao.queryStudent(); return cursor; } else if(match == MATCH_CODE1){ Cursor cursor = teacherDao.queryTeacher(); return cursor; } return null; } @Nullable @Override public String getType(@NonNull Uri uri) { return null; } @Nullable @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { if (uriMatcher.match(uri) == MATCH_CODE){ studentDao.insertStudent(values); notifyChange(); } else if(uriMatcher.match(uri) == MATCH_CODE1){ teacherDao.insertTeacher(values); notifyChange1(); } return null; } @Override public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { if (uriMatcher.match(uri) == MATCH_CODE){ int delCount = studentDao.deleteStudent(); notifyChange(); return delCount; } else if(uriMatcher.match(uri == MATCH_CODE1){ int delCount = teacherDao.deleteTeacher(); notifyChange1(); return delCount; } return 0; } @Override public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { return 0; } private void notifyChange(){ getContext().getContentResolver().notifyChange(NOTIFY_URI,null); } private void notifyChange1(){ getContext().getContentResolver().notifyChange(NOTIFY_URI1,null); }}
2 ContentProvider的onCreate和CRUD运行在哪个线程?它们是线程安全的吗?如何保证线程安全?
2.1运行线程
onCreate、query、update、insert、delete和getType这六个方法均运行在contentprovider进程当中,除了onCreate由系统回调运行在主线程当中,其他五个方法均运行在binder线程池当中。是否线程安全这个要区分contentprovider是否是跨进程访问的:(1)如果是跨进程访问,由于CRUD运行在binder线程池所以是线程不安全的 (2)如果是进程内部调用,根据binder的原理会直接对象调用,这时候是运行在调用者线程也就不存在线程安全问题了。
2.2保证线程安全
3 ContentProvider的内部存储只能是sqlite吗?
ContentProvider的内部存储不一定是sqlite,它可以是任意数据,比如contentprovider存储文件图片:
/* * 为了简单起见,这里直接将asset/pic.*png拷贝到了程序的ExternalFilesDir,实际中应该是从网络上下载图片到ExternalFilesDir。 */ public class FileProvider extends ContentProvider { @Override public boolean onCreate() { File file = new File(getContext().getExternalFilesDir(null), "pic.png"); if (!file.exists()) { AssetManager assetManager = getContext().getAssets(); try { InputStream is = assetManager.open("pic.png"); OutputStream os = new BufferedOutputStream(new FileOutputStream(file)); byte [] buf = new byte[1024]; int len = 0; while ((len = is.read(buf)) > 0) { os.write(buf, 0, len); } is.close(); os.close(); } catch (IOException e) { e.printStackTrace(); return false; } } return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // TODO Auto-generated method stub return null; } @Override public String getType(Uri uri) { if (uri.toString().endsWith(".png")) { return "image/png"; } return null; } /* * 就是做一次映射,返回uri指定的文件的文件描述符 */ @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { if ("image/png".equals(getType(uri))) { File file = new File(getContext().getExternalFilesDir(null), uri.getPath()); if (file.exists()) { return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); } } throw new FileNotFoundException(uri.getPath()); } @Override public Uri insert(Uri uri, ContentValues values) { // TODO Auto-generated method stub return null; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // TODO Auto-generated method stub return 0; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // TODO Auto-generated method stub return 0; } }
调用:
public static final Uri URI = Uri.parse("content://com.ipjmc.demo.fileprovider/pic.png"); //通过ContentResolver获取图片的输入流,再转化为Bitmap InputStream is = getContentResolver().openInputStream(URI); Bitmap bitmap = BitmapFactory.decodeStream(is);
更多相关文章
- 详解Android(安卓)Handler的使用
- UI与线程交互
- android中锁屏后代码不运行的问题
- android上运行gcc
- android线程模型文章集合
- android 异步加载
- Android实现掷骰子效果
- Android(安卓)自动化测试—robotium(七)Ant 构建脚本
- Mms模块ConversationList流程分析(1)