Content Provider(三) 自定义ContentProvider
2016-01-13 14:52
561 查看
自定义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做了介绍,如果有兴趣大家可以去看下。
我写的文章可能会很粗糙,但是要点都到位了,如果有什么不不到位 的地方 ,大家可以指出来,互相交流互相学习~
相关文章推荐
- Windows7下获得System权限问题解决方法
- 用一整天的时间安装postgreSQL NTFS权限
- 星外系统关于权限的综合说明
- 用vbs检查注册表项的访问权限的代码
- sqlserver附加.mdf权限问题解决
- C#实现自定义双击事件
- WinForm实现自定义右下角提示效果的方法
- MFC自定义消息的实现方法
- C#实现ProperTyGrid自定义属性的方法
- MongoDB系列教程(四):设置用户访问权限
- cacls命令设置文件及其文件夹权限的方法
- “SQL2000数据库”运行在普通用户下所需的权限
- php自定义错误处理用法实例
- ThinkPHP中自定义目录结构的设置方法
- 批处理设置文件访问权限的方法分享
- C#枚举中的位运算权限分配浅谈
- WordPress中创建用户角色的相关PHP函数使用详解
- C#自定义事件监听实现方法
- C#自定义事件及用法实例
- C#自定义签名章实现方法