Content Provider(三) 自定义ContentProvider



自定义ContentProvider是要继承ContentProvider


1、定义合同类(Contract Class)

这个名字是我自己取的,可能翻译不到位 。这个就是用来提供外部接口的,像我们之前用的UserDictionary.WORD.Words 就是一个合同类

public class BookContract {
    public static final String AUTHORITY = "com.ckt.myprovider.bookprovider";

    public static final class ITBook implements BaseColumns {
        public static final String ID = BaseColumns._ID;
        public static final String TITLE = "_title";
        public static final String AUTHOR = "_author";

        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/itbook");

        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.ckt.itbook";
        public static final String CONTENT_ITME_TYPE = "vnd.android.cursor.item/vnd.ckt.itbook";

        public static final String DEFAULT_SORT = TITLE + " asc";
    }


}

AUTHORITY: 标准的构成是应用的包名+自定义Provider名子 ,如上面,包名为com.ckt.myprovider,自定义provider名子为bookprovider

ITBook : 这个类对应一个itbook表,实现BaseColumns是为了给这个表中加入一个BaseColumns_ID的列,这个对于ListView等等的来说是必须的,当然你也可以赋值"_id"

ID,TITLE,AUTHOR是表的列名

CONTENT_URI:标准构成为content:// + AUTHORITY + 表名 , 这个我们给表名取名为itbook

CONTENT_TYPE 和 CONTENT_ITEM_TYPE :  基本格式是type/subtype , 因为Android定义的MIME是自定义的符合运营商规定的MIME , 所以对于type

vnd.android.cursor.dir //for multiple rows 
vnd.android.cursor.item //for single row

代码中的两行分别对应请求的是多行数据和单行数据


DEFAULT_SORT : 默认的排序 ,这里是按照title来排序 



2、定义继承自ContentProvider的provider

package com.ckt.myprovider.book;

import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;

import java.util.HashMap;
import java.util.StringTokenizer;

import dalvik.annotation.TestTarget;

public class BookProvider extends ContentProvider {

    private ContentResolver mContentResolver;
    private DBHelper mDBHelper;
    private SQLiteDatabase mDatabase;
    private static final int ITBOOK_LIST = 0;
    private static final int ITBOOK_ITEM = 1;
    private static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    private static HashMap<String, String> mProjectionMap = new HashMap<>();

    static {
        mUriMatcher.addURI(BookContract.AUTHORITY, "itbook", ITBOOK_LIST);
        mUriMatcher.addURI(BookContract.AUTHORITY, "itbook/#", ITBOOK_ITEM);

        mProjectionMap.put(BookContract.ITBook.ID, BookContract.ITBook.ID);
        mProjectionMap.put(BookContract.ITBook.TITLE, BookContract.ITBook.TITLE);
        mProjectionMap.put(BookContract.ITBook.AUTHOR, BookContract.ITBook.AUTHOR);
    }


    public BookProvider() {
    }

    @Override
    public boolean onCreate() {
        Context context = getContext();
        mContentResolver = context.getContentResolver();
        mDBHelper = new DBHelper(context, DB_NAME, null, 1);
        return true;
    }

    @Override
    public String getType(Uri uri) {
        switch (mUriMatcher.match(uri)) {
            case ITBOOK_ITEM:
                return BookContract.ITBook.CONTENT_TYPE;

            case ITBOOK_LIST:
                return BookContract.ITBook.CONTENT_ITME_TYPE;

            default:
                throw new UnsupportedOperationException("Not yet implemented");
        }

    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        mDatabase = mDBHelper.getReadableDatabase();
        SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
        switch (mUriMatcher.match(uri)) {
            case ITBOOK_ITEM:
                long id = ContentUris.parseId(uri);
                builder.setTables(DB_TABLE);
                builder.setProjectionMap(mProjectionMap);
                builder.appendWhere(BookContract.ITBook.ID + " = " + id);
                break;

            case ITBOOK_LIST:
                builder.setTables(DB_TABLE);
                builder.setProjectionMap(mProjectionMap);
                break;

            default:
                throw new UnsupportedOperationException("Not yet implemented");
        }
        Cursor cursor = builder.query(mDatabase, projection, selection, selectionArgs, null, null, BookContract.ITBook.DEFAULT_SORT);
        //data change ,notify uri
        cursor.setNotificationUri(mContentResolver, uri);
        return cursor;

    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        mDatabase = mDBHelper.getReadableDatabase();
        Uri mNewUri = null;
        long id = 0;
        switch (mUriMatcher.match(uri)) {
            case ITBOOK_ITEM:
                throw new IllegalArgumentException("Error Uri: " + uri);

            case ITBOOK_LIST:
                id = mDatabase.insert(DB_TABLE, null, values);
                break;

            default:
                throw new UnsupportedOperationException("Not yet implemented");
        }

        //if successfully
        if (id > 0) {
            mNewUri = ContentUris.withAppendedId(uri, id);
        }
        //if error occurs
        else {
            throw new SQLiteException("Unable to insert");
        }
        //notify
        mContentResolver.notifyChange(uri, null);
        return mNewUri;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        mDatabase = mDBHelper.getWritableDatabase();
        int count = 0;
        switch (mUriMatcher.match(uri)) {
            case ITBOOK_ITEM:
                long id = ContentUris.parseId(uri);
                selection = BookContract.ITBook.ID + " = " + id + " " + selection;
                count = mDatabase.delete(DB_TABLE, selection, selectionArgs);
                break;

            case ITBOOK_LIST:
                count = mDatabase.delete(DB_TABLE, selection, selectionArgs);
                break;

            default:
                throw new UnsupportedOperationException("Not yet implemented");
        }
        //notify all uri
        mContentResolver.notifyChange(uri, null);
        //successfully count > 0 , or count =0
        return count;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        mDatabase = mDBHelper.getWritableDatabase();
        int count = 0;
        switch (mUriMatcher.match(uri)){
            case ITBOOK_ITEM:
                long id = ContentUris.parseId(uri);
                selection = BookContract.ITBook.ID + " = " + id + " " + selection;
                count = mDatabase.update(DB_TABLE,values,selection,selectionArgs);
                break;

            case ITBOOK_LIST:
                count = mDatabase.update(DB_TABLE,values,selection,selectionArgs);
                break;

            default:
                throw new UnsupportedOperationException("Not yet implemented");
        }
        //notify all uris
        mContentResolver.notifyChange(uri,null);
        //successfully count > 0 . or count = 0
        return count;
    }

    private static String DB_NAME = "book.db";
    private static String DB_TABLE = "itbook";
    private static final String SQL_CREATE = "create table " +
            DB_TABLE +
            " ( " +
            BookContract.ITBook.ID + " integer primary key, " +
            BookContract.ITBook.TITLE + " text not null, " +
            BookContract.ITBook.AUTHOR + " text not null)";


    private static class DBHelper extends SQLiteOpenHelper {

        public DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
            super(context, name, factory, version);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL(SQL_CREATE);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            db.execSQL("drop table if exists " + DB_TABLE);
            onCreate(db);
        }
    }
}

onCreate():  这里面不要执行一些耗时的操作

getType() : 根据URI来决定返回单行的CONTENT_ITEM_TYPE还是多行的CONTENT_TYPE,为了识别URI, 用到了UriMatcher类

    private static final int ITBOOK_LIST = 0;
    private static final int ITBOOK_ITEM = 1;
    private static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    static {
        mUriMatcher.addURI(BookContract.AUTHORITY, "itbook", ITBOOK_LIST);
        mUriMatcher.addURI(BookContract.AUTHORITY, "itbook/#", ITBOOK_ITEM);
    }

query():官方推荐用SQLiteQueryBuilder来构建查询。 在查询的最后要用cursor.setNotificationUri(mContentResolver, uri) 来通知监听uri的客户端来更新数据 ,如CursorLoader


insert(), update(), insert()最后都需要用mContentResolver.nofityChange(uri, null).



3.在Manifest文件中定义

        <provider
            android:name=".book.BookProvider"
            android:authorities="com.ckt.myprovider.bookprovider"
            android:enabled="true"
            android:exported="true">
            <grant-uri-permission android:path="/itbook"/>
        </provider>
name和authorities不用说,enabled为true指的是允许系统去启动这个provider,exported为true是允许其它应用使用这个provider


4.使用自定义的Provider

package com.ckt.myprovider;

import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.app.LoaderManager;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.CursorLoader;
import android.content.DialogInterface;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.Toast;

import com.ckt.myprovider.book.BookContract;

import static android.widget.Toast.LENGTH_LONG;


public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {

    private static final String TAG = "MainActivity";
    private EditText mTitleEt, mAuthorEt;
    private ContentResolver mContentResolver;
    private LayoutInflater inflater;

    private ListView mListView;
    private SimpleCursorAdapter mAdapter;

    private String[] mProjection = {
            BookContract.ITBook.ID,
            BookContract.ITBook.TITLE,
            BookContract.ITBook.AUTHOR};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        init();

    }

    private void init() {
        inflater = LayoutInflater.from(getApplicationContext());
        mContentResolver = getContentResolver();
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                doInsert();
            }
        });

        mTitleEt = (EditText) findViewById(R.id.book_title);
        mAuthorEt = (EditText) findViewById(R.id.book_author);

        mListView = (ListView) findViewById(R.id.listview);
        mAdapter = new SimpleCursorAdapter(
                getApplicationContext(),
                R.layout.simple_item,
                null,
                new String[]{BookContract.ITBook.TITLE, BookContract.ITBook.AUTHOR},
                new int[]{R.id.item_title, R.id.item_author},
                0);
        mListView.setAdapter(mAdapter);
        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @TargetApi(Build.VERSION_CODES.LOLLIPOP)
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                final String author = ((TextView) view.findViewById(R.id.item_author)).getText().toString();
                final String title = ((TextView) view.findViewById(R.id.item_title)).getText().toString();
                View myView = inflater.inflate(R.layout.dialog, null);
                final EditText mDialogAuthor = (EditText) myView.findViewById(R.id.book_author);
                mDialogAuthor.setText(author);
                final EditText mDialogTitle = (EditText) myView.findViewById(R.id.book_title);
                mDialogTitle.setText(title);
                builder.setTitle("Book")
                        .setView(myView)
                                //delete
                        .setNegativeButton("Delete", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                int count = mContentResolver.delete(
                                        BookContract.ITBook.CONTENT_URI,
                                        BookContract.ITBook.TITLE + "= ?",
                                        new String[]{title}
                                );
                                if (count > 0) {
                                    Toast.makeText(MainActivity.this, "Delete Successfully", LENGTH_LONG).show();
                                }
                            }
                        })
                                //update
                        .setPositiveButton("Update", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                ContentValues mUpdateValue = new ContentValues();
                                mUpdateValue.put(BookContract.ITBook.TITLE, mDialogTitle.getText().toString());
                                mUpdateValue.put(BookContract.ITBook.AUTHOR, mDialogAuthor.getText().toString());
                                int count = mContentResolver.update(
                                        BookContract.ITBook.CONTENT_URI,
                                        mUpdateValue,
                                        BookContract.ITBook.TITLE + "=?",
                                        new String[]{title}
                                );
                                if (count > 0) {
                                    Log.d(TAG, "Update, count = " + count);
                                    Toast.makeText(MainActivity.this, "Update Successfully", LENGTH_LONG).show();
                                }
                            }
                        })
                                //nothing
                        .setNeutralButton("Cancel", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {

                            }
                        });
                builder.create().show();
            }
        });

        getLoaderManager().initLoader(0, null, this);
    }

    private void doInsert() {
        String title = mTitleEt.getText().toString();
        String author = mAuthorEt.getText().toString();
        ContentValues mNewValues = new ContentValues();
        mNewValues.put(BookContract.ITBook.TITLE, title);
        mNewValues.put(BookContract.ITBook.AUTHOR, author);
        Log.d(TAG, "title = " + title + " ,author = " + author);
        if (!TextUtils.isEmpty(title) && !TextUtils.isEmpty(author)) {
            Uri mNewUri = mContentResolver.insert(BookContract.ITBook.CONTENT_URI, mNewValues);
            if (mNewUri != null) {
                String id = mNewUri.getPathSegments().get(1);
                long id1 = ContentUris.parseId(mNewUri);
                Log.d(TAG, "Insert , id = " + id + " ,id1 = " + String.valueOf(id1));
                mTitleEt.setText(null);
                mAuthorEt.setText(null);
            }
        }
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        CursorLoader cursorLoader = new CursorLoader(
                getApplicationContext(), BookContract.ITBook.CONTENT_URI,
                mProjection,
                null,
                null,
                BookContract.ITBook.DEFAULT_SORT
        );
        return cursorLoader;
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        mAdapter.swapCursor(data);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        mAdapter.swapCursor(null);
    }
}

说明一点问题:

在加载数据到ListView的Adapter中的时候 ,用的是Loader中的CursorLoader,因为如果数据量较大查询是非常耗时的,一般我们开辟新的线程,而且要监听数据的改变来做相应的改变

使用CursorLoader好处
(1)适用任何Activity和Fragment
(2)提供异步加载
(3)对数据源监测,数据改变了及时更新
(4)配置(如屏幕方向)改变时候 ,重新连接最后 一个Loader的游标 ,不用重新查询。

5. 外部应用访问ContentProvider权限定义

如果我们自己写个ContentProvider却又在自己的应用中用这个玩意 ,未免大材小用,直接用数据库就行,那么如何在外部的应用中访问呢。

首先,如果我们的自定义provider不定义读写权限的话,默认,外部应用是无法访问自己的provider的,这个大家可以自己试试。

那么问题来了,怎么定定义权限呢

在我们的provider应用的manifest文件中

    <permission android:name="ckt.permission.READ_ITBOOK" />
    <permission android:name="ckt.permission.WRITE_ITBOOK" />
这样我们就定义了向系统申请的权限

现在我来使用

        <provider
            android:name=".book.BookProvider"
            android:authorities="com.ckt.myprovider.bookprovider"
            android:writePermission="ckt.permission.WRITE_ITBOOK"
            android:enabled="true"
            android:exported="true"
            android:readPermission="ckt.permission.READ_ITBOOK">
        </provider>
writePermission和readPermission就是我们用的读写权限,这样一来,只要外部应用能申请了权限就可以用content uri来操作content provider了


6、外部应用访问自定义的provider

首先是拥有完全的权限

    <uses-permission android:name="ckt.permission.READ_ITBOOK" />
    <uses-permission android:name="ckt.permission.WRITE_ITBOOK" />


package com.ckt.readprovider;

import android.app.LoaderManager;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.widget.SimpleCursorAdapter;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.ListView;

public class MainActivity extends AppCompatActivity {
    private ListView mListView;
    private SimpleCursorAdapter mAdapter;
    private String[] from = {BookContract.ITBook.TITLE, BookContract.ITBook.AUTHOR};
    private int[] to = {R.id.item_title, R.id.item_author};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
        mListView = (ListView) findViewById(R.id.listview);
        mAdapter = new SimpleCursorAdapter(MainActivity.this, R.layout.simple_item, null, from, to, 0);
        mListView.setAdapter(mAdapter);
        getLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks<Cursor>() {
            @Override
            public Loader<Cursor> onCreateLoader(int id, Bundle args) {
                String[] projection = {BookContract.ITBook.ID, BookContract.ITBook.TITLE, BookContract.ITBook.AUTHOR};
                CursorLoader cursorLoader = new CursorLoader(MainActivity.this,
                        BookContract.ITBook.CONTENT_URI,
                        projection,
                        null,
                        null,
                        BookContract.ITBook.DEFAULT_SORT
                );
                return cursorLoader;
            }

            @Override
            public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
                mAdapter.swapCursor(data);
            }

            @Override
            public void onLoaderReset(Loader<Cursor> loader) {
                mAdapter.swapCursor(null);
            }
        });
    }


}
这里也是用ListView和CursorLoader,基本没什么好说的。


有时候,我们不想把太多的数据暴露出去,我们只想提供某些数据给其它应用查询,那么怎么办呢,我们可以限制访问权限 ,只允许外部 应用访问特定的uri来查询数据

        <provider
            android:name=".book.BookProvider"
            android:authorities="com.ckt.myprovider.bookprovider"
            android:grantUriPermissions="true"
            android:enabled="true"
            android:exported="true">
            <grant-uri-permission android:path="/itbook"/>
        </provider>

我们这里不设置了读写权限 ,用grantUriPermission来定义可以授予uri临时的权限,而且我还定义了<grant-uri-permission>来决定哪个uri是我们才给授权 ,当然我写的例子中只有一个表格,如果我们还加了一个表authorInfo,这个作者信息,我们并不想公布,这样我们可以达到限制效果


而对于请求数据的应用,如果它们并不知道这个权限 ,也就没办法去申请这个权限了,只能通过有完全权限的应用来申请临时的uri权限,虽然申请到了这个uri权限 ,但是我们只能操作这个uri对应的数据 


先来看看效果


图上的效果是 , 我们这个应用没有在manifest文件中申请权限(可能我们并不知道有这个权限 ), 但是我们知道 readprovider这个应用有这个权限可以读取,我们可以向这个应用发送一个intent, 来得到一个临时的uri权限 ,进而操作这个uri来获取数据 ,但是这个readprovider只给了我们读的权限 ,所以我们又不能用这个uri来直接的update , delete, insert,这个时候 ,我们要启动这个readprovider一个界面 ,让用户自己操作这个界面 ,这样用户能看到,也保证了数据 的安全。


申请权限的应用tempermissionClient

package com.ckt.tempermissionclient;

import android.app.LoaderManager;
import android.content.ComponentName;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.widget.SimpleCursorAdapter;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;

public class MainActivity extends AppCompatActivity {
    private ListView mListView;
    private SimpleCursorAdapter mAdapter;
    private Button mBtGetTemPer, mBtUpdate;
    private String[] from = {BookContract.ITBook.TITLE, BookContract.ITBook.AUTHOR};
    private int[] to = {R.id.item_title, R.id.item_author};
    private EditText mEtTitle,mEtAuthor;
    private static Uri uri;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);


        mListView = (ListView) findViewById(R.id.listview);
        mAdapter = new SimpleCursorAdapter(MainActivity.this, R.layout.simple_item, null, from, to, 0);
        mListView.setAdapter(mAdapter);
        mBtGetTemPer = (Button) findViewById(R.id.tem);
        mBtGetTemPer.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setAction("ckt.action.gettempermission");
                startActivityForResult(intent, 888);
            }
        });

        mBtUpdate = (Button) findViewById(R.id.update);
        mBtUpdate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                Bundle bundle = new Bundle();
                bundle.putString("title",mEtTitle.getText().toString());
                bundle.putString("author", mEtAuthor.getText().toString());
                intent.putExtras(bundle);
                intent.setAction("ckt.action.updatebook");
                startActivityForResult(intent,886);
            }
        });

        mEtTitle = (EditText) findViewById(R.id.book_title);
        mEtAuthor = (EditText) findViewById(R.id.book_author);
    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == 666) {
            Log.d("david", "requestcode == " + requestCode);
            uri = data.getData();
            getLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks<Cursor>() {
                @Override
                public Loader<Cursor> onCreateLoader(int id, Bundle args) {
                    String[] projection = {BookContract.ITBook.ID, BookContract.ITBook.TITLE, BookContract.ITBook.AUTHOR};
                    CursorLoader cursorLoader = new CursorLoader(MainActivity.this, uri, projection, null, null, BookContract.ITBook.DEFAULT_SORT);
                    return cursorLoader;
                }

                @Override
                public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
                    mAdapter.swapCursor(data);
                }

                @Override
                public void onLoaderReset(Loader<Cursor> loader) {
                    mAdapter.swapCursor(null);
                }
            });
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        getApplicationContext().revokeUriPermission(uri,Intent.FLAG_GRANT_READ_URI_PERMISSION);
    }
}

如上面gif图中描述的一样,这个不解释这代码了,我们看readprovider中的响应的activity

package com.ckt.readprovider;

import android.content.ContentValues;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class Main2Activity extends AppCompatActivity {
    private String action;
    private Button mBtUpdate;
    private TextView mTvTitle,mTvAuthor;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
        mTvTitle = (TextView) findViewById(R.id.read_title);
        mTvAuthor = (TextView) findViewById(R.id.read_author);
        Intent intent = getIntent();
        action = intent.getAction();
        if (("ckt.action.gettempermission").equals(action)) {
            grantPermission();
        } else if (("ckt.action.updatebook").equals(action)) {
            Bundle bundle = getIntent().getExtras();
            String title = bundle.getString("title");
            String author = bundle.getString("author");
            mTvTitle.setText(title);
            mTvAuthor.setText(author);
        }

        mBtUpdate = (Button) findViewById(R.id.update);

        mBtUpdate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (("ckt.action.updatebook").equals(action)) {
                    Log.d("david", "insert ~");
                    Bundle bundle = getIntent().getExtras();
                    String title = bundle.getString("title");
                    String author = bundle.getString("author");
                    if (!TextUtils.isEmpty(title) && !TextUtils.isEmpty(author)) {
                        ContentValues contentValues = new ContentValues();
                        contentValues.put(BookContract.ITBook.TITLE, title);
                        contentValues.put(BookContract.ITBook.AUTHOR, author);
                        Log.d("david", "title = " + title + " ,author = " + author);
                        Uri uri = getContentResolver().insert(BookContract.ITBook.CONTENT_URI, contentValues);
                        if(uri != null){
                            Log.d("david","insert successfully");
                            finish();
                        }
                    }
                }
            }
        });
    }

    private void grantPermission() {
        Uri uri = BookContract.ITBook.CONTENT_URI;
        Intent intent = new Intent();
        intent.setData(uri);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        //intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        grantUriPermission("com.ckt.tempermissionclient", uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
        setResult(666, intent);
        finish();
    }

}

这个我们看下这个 grantPermission 里面有intent.setFlags 和 grantUriPermisson ,都是授予权限,那么有什么区别

intent.setFlags: 这个权限在请求权限的一方的任务栈消失之前,一直存在 ,也就是说重启或者用back button一把返回,会让这个任务栈消失,自然也就没有权限了,大家可以一起按返回的按钮,再进入应用就没有权限了

而这个grangUriPermission 就有点屌了, 它一定要手动去调用 Context.revokeUriPermission,才会释放uri权限 



好了,基本上自定义content provider的东西到这里都应用涉及到了,我搜了baidu和google搜了很多文章,我这个算是比较齐全的,不过我们google中搜索文章的时候 ,有人提了一个问题,这个问题是:我如何把内部存储中的文件提供给外部应用呢,于是我在我前往篇文章中就对ContentProvider的子类FileProvider做了介绍,如果有兴趣大家可以去看下。  


我写的文章可能会很粗糙,但是要点都到位了,如果有什么不不到位 的地方 ,大家可以指出来,互相交流互相学习~


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值