美文网首页6.0Android技术知识Android知识
Android中用ContentProvider实现跨程序访问

Android中用ContentProvider实现跨程序访问

作者: uniapp | 来源:发表于2017-07-07 18:19 被阅读88次

    使用Android手机中的应用时,经常会出现访问其他应用中数据的场景.比如读取用户联系人,获取其它应用的登录状态等.不同应用间的数据访问,涉及到数据访问安全的问题.作为应用的开发者,一方面我们希望自己应用中关系到用户隐私的信息,如账户和密码等,要绝对安全,不能被其他应用获取.另一方面,一些并非私密的数据可以公开,供其他应用读取使用,从而减少用户重复设置的麻烦,提高用户使用该应用活跃度.基于上述目的,Anroid在6.0时推出了ContentProvider.

    使用ContentProvider,需要先了解Android的权限.权限是基于对用户隐私的保护,比如安装摩拜,ofo等应用时,都会遇到获取用户位置权限的请求.如果有一天,自己不想行踪被应用获取,我们可以在设置/应用管理中,关闭位置请求权限.同理,其它的拨打电话,获取信息,使用通知等都涉及到权限,也都可以由用户进行打开或者关闭的选择.

    Android中所有的私人权限如下图.

    Android私有权限

    下面是一个简单的调用打电话的示例.

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Button btn_makeCall = (Button)findViewById(R.id.make_call);
            btn_makeCall.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE) !=
                            PackageManager.PERMISSION_GRANTED){
                        ActivityCompat.requestPermissions(MainActivity.this, new String[] { Manifest.permission.CALL_PHONE}, 1);
    
                    }else {
                        call();
                    }
                }
            });
        }
    
        private void call() {
            Intent intent = new Intent(Intent.ACTION_CALL);
            intent.setData(Uri.parse("tel:10086"));
            try {
                startActivity(intent);
            }catch (SecurityException e){
                e.printStackTrace();
            }
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            switch (requestCode) {
                case 1:
                    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                        call();
                    }else {
                        Toast.makeText(this, "HAVE NOT PERMISSION", Toast.LENGTH_SHORT).show();
                    }
                    break;
                    default:
            }
        }
    }
    

    btn_makeCall是在布局中添加的Button组件.
    最后需要在AndroidManifest.xml文件中进行注册.

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.zhudong.makecalltest">
        <uses-permission android:name="android.permission.CALL_PHONE" />
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    </manifest>
    

    类似请求系统权限,不同的应用程序之间的数据访问,可以通过ContentProvider实现.下面实现一个ProviderTest应用访问DatabaseTest应用.

    DatabaseTest应用中用MyOpenHelper类新建数据库,并提供给ProviderTest应用.其中MyOpenHelper类的实现参考Andoid数据持久化的方式.

    新建DatabaseProvider,继承至ContentProvider,实现抽象方法query, insert, update, delete方法,就可以方便的供其它应用来查询,插入,更新和删除数据了.

    public class DatabaseProvider extends ContentProvider {
        public static final int BOOK_DIR = 0;
    
        public static final int BOOK_ITEM = 1;
    
        public static final int CATEGORY_DIR = 2;
    
        public static final int CATEGORY_ITEM = 3;
    
        public static final String AUTHORITY = "com.example.databasetest.provider";
    
        private static UriMatcher uriMatcher;
    
        private MyOpenHelper dbHelper;
    
        static {
            uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
            uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR);
            uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);
            uriMatcher.addURI(AUTHORITY, "category", CATEGORY_DIR);
            uriMatcher.addURI(AUTHORITY, "category/#", CATEGORY_ITEM);
        }
    
        @Override
        public boolean onCreate() {
            dbHelper = new MyOpenHelper(getContext(), "BookStore.db", null, 1);
            return true;
        }
    
        @Override
        public Cursor query(Uri uri, String[] projection, String selection,
                            String[] selectionArgs, String sortOrder) {
            Cursor cursor = null;
            SQLiteDatabase db = dbHelper.getReadableDatabase();
            switch (uriMatcher.match(uri)){
                case BOOK_DIR:
                    cursor = db.query("Book", projection, selection, selectionArgs, null, null, sortOrder);
                    break;
                case BOOK_ITEM:
                    String bookId = uri.getPathSegments().get(1);
                    cursor = db.query("Book", projection, "id = ?", new String[] {bookId}, null, null, sortOrder);
                    break;
                case CATEGORY_DIR:
                    cursor = db.query("Category", projection, selection, selectionArgs, null, null, sortOrder);
                    break;
                case CATEGORY_ITEM:
                    String categoryId = uri.getPathSegments().get(1);
                    cursor = db.query("Category", projection, "id = ?", new String[] {categoryId}, null, null, sortOrder);
                    break;
                default:
                    break;
            }
            return cursor;
        }
    
        @Override
        public Uri insert(Uri uri, ContentValues values) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            Uri uriReturn = null;
            switch (uriMatcher.match(uri)){
                case BOOK_DIR:
                case BOOK_ITEM:
                    long newBookId = db.insert("Book", null, values);
                    uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId);
                    break;
                case CATEGORY_DIR:
                case CATEGORY_ITEM:
                    long newCategoryId = db.insert("Category", null, values);
                    uriReturn = Uri.parse("content://" + AUTHORITY + "/category/" + newCategoryId);
                    break;
                default:
                    break;
            }
            return uriReturn;
        }
    
        @Override
        public int update(Uri uri, ContentValues values, String selection,
                          String[] selectionArgs) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            int rowReturn = 0;
            switch (uriMatcher.match(uri)){
                case BOOK_DIR:
                    rowReturn = db.update("Book", values, selection, selectionArgs);
                    break;
                case BOOK_ITEM:
                    String bookId = uri.getPathSegments().get(1);
                    rowReturn = db.update("Book", values, "id = ?", new String[]{bookId});
                    break;
                case CATEGORY_DIR:
                    rowReturn = db.update("Category", values, selection, selectionArgs);
                    break;
                case CATEGORY_ITEM:
                    String categoryId = uri.getPathSegments().get(1);
                    rowReturn = db.update("Category", values, "id = ?", new String[]{categoryId});
                    break;
                default:
                    break;
            }
            return rowReturn;
        }
    
        @Override
        public int delete(Uri uri, String selection, String[] selectionArgs) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            int deleteReturn = 0;
            switch (uriMatcher.match(uri)){
                case BOOK_DIR:
                    deleteReturn = db.delete("Book", selection, selectionArgs);
                    break;
                case BOOK_ITEM:
                    String bookId = uri.getPathSegments().get(1);
                    deleteReturn = db.delete("Book", "id = ?", new String[]{bookId});
                    break;
                case CATEGORY_DIR:
                    deleteReturn = db.delete("Category", selection, selectionArgs);
                    break;
                case CATEGORY_ITEM:
                    String categoryId = uri.getPathSegments().get(1);
                    deleteReturn = db.delete("Category", "id = ?", new String[]{categoryId});
                    break;
                default:
                    break;
            }
            return deleteReturn;
        }
    
        @Override
        public String getType(Uri uri) {
            String strReturn = null;
            switch (uriMatcher.match(uri)){
                case BOOK_DIR:
                    strReturn = "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.book";
                    break;
                case BOOK_ITEM:
                    strReturn = "vnd.android.cursor.item/vnd.com.example.databasetest.provider.book";
                    break;
                case CATEGORY_DIR:
                    strReturn = "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.category";
                    break;
                case CATEGORY_ITEM:
                    strReturn = "vnd.android.cursor.item/vnd.com.example.databasetest.provider.category";
                    break;
                default:
                    break;
            }
            return strReturn;
        }
    }
    

    然后在AndroidManifest.xml文件中进行注册:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.zhudong.databasetest2">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
            <provider
                android:name=".DatabaseProvider"
                android:authorities="com.example.databasetest.provider"
                android:enabled="true"
                android:exported="true"></provider>
        </application>
    
    </manifest>
    

    运行工程,生成DatabaseTest应用.

    接下来新建ProviderTest工程.在activity_main.xml布局文件中添加Button组件:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:android="http://schemas.android.com/apk/res/android">
    
        <Button
            android:id="@+id/button_add"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="add to book"/>
        <Button
            android:id="@+id/button_query"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="query from book"/>
        <Button
            android:id="@+id/button_upate"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="upate to book"/>
        <Button
            android:id="@+id/button_delete"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="delete from book"/>
    
    </LinearLayout>
    

    然后在MainActivity中使用添加的Button组件.

    public class MainActivity extends AppCompatActivity {
    
        private String newId;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Button button_add = (Button)findViewById(R.id.button_add);
            button_add.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) { 
                    Uri uri = Uri.parse("content://com.example.databasetest.provider/book");
                    ContentValues values = new ContentValues();
                    values.put("author", "StormZhang");
                    values.put("price", "21.99");
                    values.put("pages", "199.11");
                    values.put("name", "First Git");
                    Uri newUri = getContentResolver().insert(uri,values);
                    newId = newUri.getPathSegments().get(1);
                    Log.d("newId", "onClick:" + newId);
                }
            });
    
            Button button_query = (Button)findViewById(R.id.button_query);
            button_query.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Uri uri = Uri.parse("content://com.example.databasetest.provider/book");
                    Cursor cursor = getContentResolver().query(uri, null, null, null,null);
                    if (cursor != null){
                        while (cursor.moveToNext()){
                            String author = cursor.getString(cursor.getColumnIndex("author"));
                            double price = cursor.getDouble(cursor.getColumnIndex("price"));
                            String name = cursor.getString(cursor.getColumnIndex("name"));
                            int pages = cursor.getInt(cursor.getColumnIndex("pages"));
                            Log.e("MainActivity", author + price + name + pages);
                        }
                    }
                    cursor.close();
                }
            });
    
            Button button_update = (Button)findViewById(R.id.button_upate);
            button_update.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Uri uri = Uri.parse("content://com.example.databasetest.provider/book/" + newId);
                    ContentValues values = new ContentValues();
                    values.put("name", "a New Name");
                    values.put("pages", "1999");
                    values.put("price", "199.9");
                    getContentResolver().update(uri, values, null, null);
                }
            });
    
            Button button_delete = (Button)findViewById(R.id.button_delete);
            button_delete.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Uri uri = Uri.parse("content://com.example.databasetest.provider/book/" + newId);
                    getContentResolver().delete(uri,null,null);
                }
            });
        }
    }
    

    运行应用,点击不同的Button后,我们能在Anroid Monitor的控制台中看到打印的信息:

    E/MainActivity: StormZhang199.9a New Name1999
    E/MainActivity: StormZhang21.99First Git199
    E/MainActivity: StormZhang21.99First Git199
    
    E/MainActivity: StormZhang199.9a New Name1999
    E/MainActivity: StormZhang21.99First Git199
    E/MainActivity: StormZhang199.9a New Name1999
    

    总结
    Android的权限控制,增加了不同应用数据的安全性,更好地保护了用户隐私.其提供的ContentProvider可以让开发者方便的暴露给其他应用数据,并保证其他数据的安全性.

    关注和喜欢都是对我的鼓励和支持~

    相关文章

      网友评论

        本文标题:Android中用ContentProvider实现跨程序访问

        本文链接:https://www.haomeiwen.com/subject/qucrhxtx.html