Andrio studio 学习 之 ContentProvider 系统URI

本文介绍如何在安卓设备上读取联系人、短信、图片、音频及视频等数据,并提供了详细的代码实现,包括权限申请、内容解析等关键步骤。
案例一,获取手机联系人,展现在ListView中并存储到数据库中

(1)添加获取手机联系人的权限

<uses-permission android:name="android.permission.WRITE_CONTACTS"></uses-permission>
<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permissio>

(2) 创建一个javabead.用来存信息

package com.example.day011;


public class Phone {
    private String name;
    private String number;

    public Phone() {
    }

    public Phone(String name, String number) {
        this.name = name;
        this.number = number;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    @Override
    public String toString() {
        return "Phone{" +
                "name='" + name + '\'' +
                ", number='" + number + '\'' +
                '}';
    }
}

(3)获得手机联系

package com.example.day011;

import android.Manifest;
import android.content.ContentResolver;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private Button buttonId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        buttonId = findViewById(R.id.button_id);

        buttonId.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            //根据版本动态获取授权(6.0以上)
                if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
                   requestPermissions(new String[]{Manifest.permission.WRITE_CONTACTS,Manifest.permission.READ_CONTACTS},100);
                }else{
                    resolverMethod();
                }
            }
        });
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestCode == 100 & grantResults[0] == PackageManager.PERMISSION_GRANTED){
            resolverMethod();
        }
    }

    //因为重复使用,所有封装
    private void resolverMethod() {
        ContentResolver contentResolver = getContentResolver();
        Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
        String[] strings = {ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME};
        Cursor cursor = contentResolver.query(uri, strings, null, null, null);
        while (cursor.moveToNext()){
            String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
            String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
            Toast.makeText(MainActivity.this, name, Toast.LENGTH_SHORT).show();
            //有了对象,其他都好说了.
            Phone phone = new Phone(name, number);
        }
    }
}
案例二,获取手机短信

1,在清单文件中添加授权

 <uses-permission android:name="android.permission.READ_SMS" />

2,获得短信内容,展现在ListView中 或者将信息存储到数据库中
uri:Telephony.Sms.CONTENT_URI (请求的地址)
字段:Telephony.Sms.ADDRESS 地址 Telephony.Sms.BODY 内容

 private void smsMethod() {
        ContentResolver resolver = getContentResolver();
        Uri uri= Telephony.Sms.CONTENT_URI;
        String[] strs={Telephony.Sms.BODY,Telephony.Sms.ADDRESS};
        Cursor cursor=resolver.query(uri,strs,null,null,null);
        //第一种ListView 中  第二种 :存到数据库
        ArrayList<Msm> list=new ArrayList<>();
        while(cursor.moveToNext()){
            String address=cursor.getString(cursor.getColumnIndex(Telephony.Sms.ADDRESS));
            String body=cursor.getString(cursor.getColumnIndex(Telephony.Sms.BODY));
            Toast.makeText(this, body, Toast.LENGTH_SHORT).show();
            list.add(new Msm(address,body));
            //执行insert语句
        }
    }

java中的添加的代码
1,添加一个按钮,在添加一个点击事件

smsId.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
                    requestPermissions(new String[]{Manifest.permission.READ_SMS,Manifest.permission.SEND_SMS},101);
                }else{
                    smsMethod();
                }

            }
        });

2,在授权回调的方法中,添加相应的逻辑

@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestCode == 100 & grantResults[0] == PackageManager.PERMISSION_GRANTED){
            resolverMethod();
        }else if (requestCode == 101 & grantResults[0] == PackageManager.PERMISSION_GRANTED){
            smsMethod();
        }
    }
案例三,获取手机所有的图片

1,添加权限.

<!--读写sd卡的权限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

2,添加一个点击事件

	picId.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
                requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE},102);
            }else{
                picMethod();
            }
        }
    });

3,添加java代码

private void picMethod() {
    //TODO 1:获得ContentResolver
    ContentResolver contentResolver = getContentResolver();
    //参数一 URI
    //TODO 2:获得图库的URI
    Uri uri1 = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;//图库的URI
    Cursor cursor = contentResolver.query(uri1, null, null, null, null);
    while (cursor.moveToNext()){
        //字段
        String title=cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.TITLE));
        //图片的地址
        String data=cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
        int height=cursor.getInt(cursor.getColumnIndex(MediaStore.Images.Media.HEIGHT));
        int width=cursor.getInt(cursor.getColumnIndex(MediaStore.Images.Media.WIDTH));
        long size=cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media.SIZE));
        Log.e("###", "图片: "+title+":"+data+":"+height+":"+width+":"+size);
    }
}

4,回调函数中,添加逻辑

@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestCode == 100 & grantResults[0] == PackageManager.PERMISSION_GRANTED){
            resolverMethod();
        }else if (requestCode == 101 & grantResults[0] == PackageManager.PERMISSION_GRANTED){
            smsMethod();
        }else if (requestCode == 102 & grantResults[0] == PackageManager.PERMISSION_GRANTED){
            picMethod();
        }
    }
案例四,获取手机所有的图片

1,添加权限.

<!--读写sd卡的权限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

2,添加一个监听事件

   musicId.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
                requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE},103);
            }else{
                musicMethod();
            }
        }
    });

3,添加java代码

private void musicMethod() {
    //TODO 1:获得ContentResolver
    ContentResolver contentResolver = getContentResolver();
    //参数一 URI
    //TODO 2:获得音乐的URI
    Uri uri1 = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;//音乐的URI
    Cursor cursor = contentResolver.query(uri1, null, null, null, null);
    while (cursor.moveToNext()){
        //字段
        String title=cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
        //地址
        String data=cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
        //歌手
        String artist=cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
        //时长
        long duration=cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION));
        long size=cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.SIZE));
        Log.i("###", "音乐: "+title+":"+data+":"+artist+":"+duration+":"+size);
    }
}

4,回调函数中,添加逻辑

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if(requestCode == 100 & grantResults[0] == PackageManager.PERMISSION_GRANTED){
        resolverMethod();
    }else if (requestCode == 101 & grantResults[0] == PackageManager.PERMISSION_GRANTED){
        smsMethod();
    }else if (requestCode == 102 & grantResults[0] == PackageManager.PERMISSION_GRANTED){
        picMethod();
    }else if (requestCode == 103 & grantResults[0] == PackageManager.PERMISSION_GRANTED){
        musicMethod();
    }
}
案例五,获取手机所有的视频

1,添加权限.

<!--读写sd卡的权限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

2,添加一个监听事件

 videoId.setOnClickListener(new View.OnClickListener() {
       @Override
       public void onClick(View v) {
           if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
               requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE},104);
           }else{
               videoMethod();
           }
       }
   });

3,添加java代码

 		private void videoMethod() {
   		//TODO 1:获得ContentResolver
       ContentResolver contentResolver = getContentResolver();
       //参数一 URI
       //TODO 2:获得视频的URI
       Uri uri1 = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;//视频的URI
//        Uri uri1 = Uri.parse("content://media/external/video/media");
       Cursor cursor = contentResolver.query(uri1, null, null, null, null);
       while (cursor.moveToNext()){
           //字段
           String title=cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.TITLE));
           String data=cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATA));
           String artist=cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.ARTIST));
           long duration=cursor.getLong(cursor.getColumnIndex(MediaStore.Video.Media.DURATION));
           long size=cursor.getLong(cursor.getColumnIndex(MediaStore.Video.Media.SIZE));
           Log.i("###", "视频: "+title+":"+data+":"+artist+":"+duration+":"+size);
       }
   }

4,回调函数中,添加逻辑

   else if (requestCode == 104 & grantResults[0] == PackageManager.PERMISSION_GRANTED){
       videoMethod();
   }
所有权限及接口明细
  • 获取图库:(读sd卡的权限)

    • (1)uri:MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    • (2)字段: MediaStore.Images.Media.TITLE; 图片名称 MediaStore.Images.Media.SIZE; 大小 MediaStore.Images.Media.DATA; 地址
      MediaStore.Images.Media.HEIGHT; 高 MediaStore.Images.Media.WIDTH; 宽
  • 获取视频:(读sd卡的权限)

    • (1)uri:MediaStore.Video.Media.EXTERNAL_CONTENT_URI
    • (2)字段:TITLE:歌名 ARTIST 歌手 DURATION 总时长 DATA 地址 SIZE 大小
    • String[] strs= new String[]{ MediaStore.Video.Media.TITLE, 歌名 MediaStore.Video.Media.ARTIST, 歌手
      MediaStore.Video.Media.DURATION, 总时长
      MediaStore.Video.Media.DATA, 地址 MediaStore.Audio.Media.SIZE}; 大小

*获取音频 : (读sd卡的权限)
* (1)uri:MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
* (2)字段:TITLE:歌名 ARTIST 歌手 DURATION 总时长 DATA 地址 SIZE 大小
* String[] strs= new String[]{ MediaStore.Audio.Media.TITLE, 歌名 MediaStore.Audio.Media.ARTIST, 歌手
MediaStore.Audio.Media.DURATION, 总时长 MediaStore.Audio.Media.DATA, 地址
MediaStore.Audio.Media.SIZE}; 大小

*获取联系人: (读联系人的权限)
* (1)uri:ContactsContract.CommonDataKinds.Phone.CONTENT_URI
* (2)字段:Phone.DISPLAY_NAME 姓名 NUMBER 电话
* String[] strs= new String[]{ ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, 姓名
ContactsContract.CommonDataKinds.Phone.NUMBER}; 电话

*获取短信: (读短信的权限)
* (1)uri:Telephony.Sms.CONTENT_URI
* (2)字段:ADDRESS 地址 BODY 内容
* String[] strs= new String[]{ Telephony.Sms.ADDRESS, 地址 Telephony.Sms.BODY}; 内容

*通话记录:
* (1)uri:CallLog.Calls.CONTENT_URI
* (2)字段: NUMBER:电话号码 DATE:时间 毫秒 DURATION:总时长 秒 TYPE 类型

清单文件中: 联网的权限:

写SD卡权限:

读SD卡权限:

读取联系人的权限:

读取短信的权限:

读取通话记录的权限:

案例六,手机联系人的增删改

步骤和以上相同
1,添加一个权限
2,是添加一个点击事件
3.java代码

 private void addPerson() {
        ContentResolver contentResolver = getContentResolver();
        Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
        //ContactsContract.RawContacts.CONTENT_URI
        ContentValues values = new ContentValues();
        //插入一条空数据,返回当前空数据的id.
        long contactid = ContentUris.parseId(contentResolver.insert(uri, values));
        uri = Uri.parse("content://com.android.contacts/data");
        //添加姓名
        values.put("raw_contact_id", contactid);
        values.put("mimetype", "vnd.android.cursor.item/name");
        values.put("data1", "xiaoming11");
        contentResolver.insert(uri, values);
        values.clear();

        
        //添加电话
        values.put(ContactsContract.CommonDataKinds.Phone.RAW_CONTACT_ID, contactid);
        //ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE;
        values.put(ContactsContract.Data.MIMETYPE, "vnd.android.cursor.item/phone_v2");
        //ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE;
        values.put(ContactsContract.Data.DATA1, "12312312311");
        contentResolver.insert(uri, values);
        values.clear();
        
        //添加Email
        values.put("raw_contact_id", contactid);
        //ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE;
        values.put(ContactsContract.Data.MIMETYPE, "vnd.android.cursor.item/email_v2");
        values.put("data1", "11111111@qq.com");
        contentResolver.insert(uri, values);
    }

4,在回调事件中,添加方法.
扩展资料
两个博客结合看.
https://www.cnblogs.com/yanganok/p/4584043.html

https://blog.youkuaiyun.com/cbk861110/article/details/50930828

案例七,自动填写注册手机验证码

1,创建一个观察者

package com.example.day011;

import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.os.Handler;
import android.os.Message;
import android.provider.Telephony;
import android.util.Log;
import android.widget.Toast;

/**
 * 原理,
 * 1,写一个观察者,
 * 2,观察者一直在监视的短信的动态
 * 3,一旦发现有短信的变化(也就是短信的数据库里的数据有变化)
 * 4,就执行相应的业务逻辑
 */
public class SmsObserver  extends ContentObserver {
    private static final String TAG = "SmsObserver";
    private ContentResolver contentResolver;
    private Handler handler;
    public SmsObserver(Handler handler ,Context context) {
        super(handler);
        this.handler = handler;
        contentResolver = context.getContentResolver();
    }

    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);
        String[] strs={Telephony.Sms.BODY,Telephony.Sms.ADDRESS};
        Cursor cursor = contentResolver.query(Telephony.Sms.CONTENT_URI, strs, null, null, null);
        if (cursor != null){
            cursor.moveToFirst();
            String string = cursor.getString(cursor.getColumnIndex(Telephony.Sms.BODY));
            Log.i(TAG, "onChange: 0000"+string);
            Message obtain = Message.obtain();
            obtain.obj = string;
            handler.sendMessage(obtain);
        }else{
            Log.i(TAG, "onChange: kong");
        }
    }
}

2.Activity中的代码

package com.example.day011;

import android.content.ContentResolver;
import android.os.Handler;
import android.os.Message;
import android.provider.Telephony;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.EditText;
import android.widget.Toast;

public class SmsActivity extends AppCompatActivity {
    private EditText smsId;
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            String s = (String)msg.obj;
            Toast.makeText(SmsActivity.this, s, Toast.LENGTH_SHORT).show();
            smsId.setText(s);
        }
    };
    private SmsObserver smsObserver;
    private ContentResolver contentResolver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sms);
        smsId = findViewById(R.id.sms_id);

        smsObserver = new SmsObserver(handler,this);
        contentResolver = getContentResolver();
//注册观察者
        contentResolver.registerContentObserver(Telephony.Sms.CONTENT_URI,true,smsObserver);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //注销观察者
        contentResolver.unregisterContentObserver(smsObserver);
    }
}
<think>首先,用户的问题是:“我想查找在Android Studio中使用ContentProvider实现两个程序间共享数据的方法”。用户提供了几个引用,这些引用来自于之前的上下文,我应该参考它们。 系统级指令: - 所有行内数学表达式用$...$。 - 独立公式用$$...$$。 - 使用中文回答。 - 生成相关问题。 - 引用的段落末尾自然地添加引用标识,如[^1]。 - 用户可见层:回答结构清晰,逐步解决问题,尽量真实可靠。 用户的问题是关于在Android Studio中使用ContentProvider实现两个程序间共享数据的方法。引用[1]到[^5]提供了相关信息: - [^1]: 解释了ContentProvider的作用:解决不同应用间的数据共享问题。 - [^2]: 描述了实现自定义ContentProvider的过程,包括创建URI、数据表结构、实现CRUD操作。 - [^3]: ContentProvider用于管理和共享数据,提供权限控制。 - [^4]: ContentProvider是四大组件之一,用于共享数据,如访问系统数据。 - [^5]: 具体说明了一个应用使用ContentProvider暴露数据,另一个使用ContentResolver访问。 我的回答需要结构化: 1. **介绍ContentProvider**:简要解释什么是ContentProvider及其作用。 2. **实现步骤**:详细说明如何在Android Studio中实现两个程序间共享数据。 3. **实际应用场景**:基于引用,提供一些场景。 4. **注意事项**:如权限控制、URI定义等。 5. **生成相关问题**:在最后添加相关问题。 回答应该使用中文。 结构化回答: - **引言**:介绍主题。 - **核心方法**:分步解释实现过程。 - **总结关键点**。 - **结尾相关问题**。 确保真实可靠:基于标准Android开发知识,结合引用中的细节。 生成相关问题: - 类似示例中的快速排序问题,例如: 1. ContentProvider的安全风险有哪些? 2. 如何调试ContentProvider的数据共享? 3. ContentProviderAndroid开发中的其他应用? 引用标识:在引用的地方自然地添加[^1], [^2]等。例如,引用[1]提到ContentProvider解决数据共享问题,所以在相关段落末尾加[^1]。 实现步骤: 1. **创建ContentProvider应用**: - 定义ContentProvider类。 - 实现CRUD方法(query, insert, update, delete)。 - 定义URI和权限。 2. **创建ContentResolver应用**: - 使用ContentResolver访问数据。 - 指定URI进行CRUD操作。 3. **配置AndroidManifest.xml**:声明权限和Provider。 从引用[^5]:“一个应用使用ContentProvider暴露数据,其他应用使用ContentResolver调用”。 完整回答框架: 1. 解释ContentProvider的作用。 2. 详细步骤: - 步骤1: 创建提供数据的应用(定义ContentProvider)。 - 步骤2: 定义URI和MIME类型。 - 步骤3: 实现数据操作。 - 步骤4: 配置清单文件。 - 步骤5: 创建访问数据的应用(使用ContentResolver)。 3. 示例代码片段。 4. 总结。 5. 相关问题。 数学表达式:用户问题没有数学相关内容,所以可能不需要。但如果有变量等,用$...$。 最后,生成相关问题。 </think>### 在Android Studio中使用ContentProvider实现两个程序间共享数据的方法 ContentProviderAndroid四大组件之一,主要用于解决不同应用程序之间的数据共享问题。它允许一个应用(提供者)将私有数据暴露给其他应用(消费者),通过URI(统一资源标识符)和ContentResolver实现安全的数据访问。以下我将逐步介绍实现方法,基于标准Android开发实践和参考引用内容。实现过程包括创建ContentProvider应用(数据提供方)和ContentResolver应用(数据访问方),确保结构清晰且可靠[^1][^3]。 #### 1. **理解ContentProvider的核心概念** - ContentProvider充当数据中介,管理数据库或文件系统的访问权限。提供方应用定义URI(如`content://com.example.provider/table_name`)来标识共享数据,并通过MIME类型定义数据类型。访问方应用使用ContentResolver发送CRUD请求(增删改查)。这种机制确保了数据隔离和安全性,防止未经授权的访问[^2][^5]。 - 关键组件: - **URI**:唯一标识共享数据,通常包含authority(如包名)。 - **ContentResolver**:消费者应用使用的类,调用提供方的CRUD方法。 - **权限机制**:在AndroidManifest.xml中声明权限来控制访问。 #### 2. **实现步骤:分步指南** 在Android Studio中创建一个项目包含两个模块(或两个独立应用):一个用于提供数据(ProviderApp),另一个用于访问数据(ResolverApp)。以下是具体步骤: **步骤1: 创建ProviderApp(数据提供方)** - 在ProviderApp中,定义一个自定义ContentProvider类。 - 继承`ContentProvider`并重写关键方法:`onCreate()`, `query()`, `insert()`, `update()`, `delete()`。 - 使用SQLite数据库存储数据(示例中创建一个简单的表)。 - 定义URI常量,使用`UriMatcher`匹配请求。 ```java // 在ProviderApp的MyContentProvider.java中 public class MyContentProvider extends ContentProvider { private static final String AUTHORITY = "com.example.provider"; private static final String PATH = "data"; public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + PATH); private static final int DATA = 1; private UriMatcher uriMatcher; private SQLiteDatabase database; @Override public boolean onCreate() { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(AUTHORITY, PATH, DATA); // 初始化数据库 DatabaseHelper dbHelper = new DatabaseHelper(getContext()); database = dbHelper.getWritableDatabase(); return database != null; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { if (uriMatcher.match(uri) == DATA) { // 查询数据库并返回Cursor return database.query("my_table", projection, selection, selectionArgs, null, null, sortOrder); } throw new IllegalArgumentException("Unknown URI: " + uri); } // 实现insert, update, delete等方法类似,省略... } ``` - 创建数据库辅助类: ```java // DatabaseHelper.java public class DatabaseHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "provider.db"; private static final int DATABASE_VERSION = 1; public static final String TABLE_NAME = "my_table"; public static final String COLUMN_ID = "_id"; public static final String COLUMN_DATA = "data"; public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE " + TABLE_NAME + " (" + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + COLUMN_DATA + " TEXT);"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); onCreate(db); } } ``` - 在AndroidManifest.xml中声明ContentProvider和权限: ```xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.providerapp"> <application> <provider android:name=".MyContentProvider" android:authorities="com.example.provider" android:exported="true" <!-- 允许其他应用访问 --> android:permission="com.example.provider.PERMISSION" /> <!-- 自定义权限 --> </application> <!-- 定义权限 --> <permission android:name="com.example.provider.PERMISSION" android:protectionLevel="normal" /> </manifest> ``` **步骤2: 创建ResolverApp(数据访问方)** - 在ResolverApp中,使用ContentResolver访问共享数据。 - 确保ResolverApp的build.gradle中添加对ProviderApp的依赖(如果同项目),或通过安装包访问。 - 发送CRUD请求:query(), insert(), etc., 使用ProviderApp定义的URI。 ```java // 在ResolverApp的MainActivity.java中 public class MainActivity extends AppCompatActivity { private static final Uri CONTENT_URI = Uri.parse("content://com.example.provider/data"); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 示例:查询数据 Cursor cursor = getContentResolver().query(CONTENT_URI, null, null, null, null); if (cursor != null) { while (cursor.moveToNext()) { String data = cursor.getString(cursor.getColumnIndex("data")); Log.d("ResolverApp", "Shared data: " + data); } cursor.close(); } // 示例:插入数据 ContentValues values = new ContentValues(); values.put("data", "Hello from ResolverApp"); getContentResolver().insert(CONTENT_URI, values); } } ``` - 在ResolverApp的AndroidManifest.xml中声明权限: ```xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.resolverapp"> <uses-permission android:name="com.example.provider.PERMISSION" /> <!-- 请求提供方的权限 --> <application> <!-- 应用代码 --> </application> </manifest> ``` **步骤3: 测试与调试** - 在Android Studio中,安装两个应用到设备或模拟器:先安装ProviderApp,再安装ResolverApp。 - 使用Logcat查看数据共享结果:ResolverApp调用query()或insert()后,检查数据库变化。 - 常见问题解决: - 如果出现`Permission Denial`错误,确保权限声明正确且ResolverApp请求了权限。 - URI不匹配时,检查UriMatcher的定义是否一致。 #### 3. **实际应用场景和最佳实践** - **应用场景**: - 共享联系人或媒体数据(如引用[^4]所述)。 - 企业应用中,主应用共享配置数据给子应用。 - 实现插件式架构,例如一个应用提供数据源,另一个显示数据。 - **最佳实践**: - **安全性**:使用`android:protectionLevel`定义权限级别(如signature级仅允许相同签名应用访问),防止恶意访问[^3]。 - **性能优化**:批量操作使用`ContentProviderOperation`减少IPC调用开销。 - **错误处理**:在ContentProvider方法中添加异常捕获,返回null或抛出`IllegalArgumentException`。 - 参考实验中提到,通过URI匹配和MIME类型定义,确保数据访问安全可靠[^2]。 #### 4. **总结** 在Android Studio中实现ContentProvider数据共享的核心是:创建提供方应用暴露数据(定义URI、数据库和CRUD方法),消费者应用使用ContentResolver访问。这解决了Android沙箱环境下的数据隔离问题,并支持权限控制。整个过程在Android Studio中开发高效,可利用内置工具(如Database Inspector)调试SQLite[^5]。确保遵循权限机制以避免安全问题。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值