ContentProvider使用难点

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,contentprovider)