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);