《第一行代码Android》学习总结第七章 内容提供器ContentProvider

        主要用于在不同应用程序之间实现数据共享功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证数据的安全性。

ContentProvider一共有两种用法:

1、使用系统现有的ContentProvider来读取和操作相应程序中的数据。

2、创建自己的ContentProvider给程序的数据提供外部访问接口。

一、访问其他程序中的数据。

ContentResolver的基本用法

        对于一个应用程序来讲,如果想要访问内容提供器ContentProvider中的数据,就一定要借助ContentResolver类,该类实例可以通过Context的getContentResolver()方法获得。ContentResolver中提供了insert()、update()、delete()、query()等方法对数据进行CRUD操作。

        与SQLiteDatabase不同,ContentResolver中的增删改查并不是接受表名参数,而是使用一个Uri作为参数代替,成为内容URI。内容URI为内容提供器中的数据建立了唯一标识符。

content://com.example.app.provider/table1
content://com.example.app.provider/table2

格式:协议声明+authority+path

authority:用于对不同应用程序做区分,一般避免冲突都会采用程序报名的方式做命名。

Path:对于同一应用程序中不同的表做区分,加在authority之后。

        在得到内容URI字符串之后,还需要将它解析成Uri对象作为参数传入:

Uri uri = Uri.parse(“content://com.example.app.provider/table1”)

实例:读取系统联系人

1、将读取到的信息联系人在ListView中显示,修改activity_main.xml文件。


    
    

2、修改MainActivity中代码。

public class MainActivity extends AppCompatActivity {
    ArrayAdapter adapter;
    List contactsList = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//创建ListView并创建适配器
        ListView contactsView = (ListView) findViewById(R.id.contacts_view);
        adapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,contactsList);
        contactsView.setAdapter(adapter);
//运行时权限
        if(ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(this,new String[]{ Manifest.permission.READ_CONTACTS },1);
        }else {
            readContacts();
        }
}
//读取系统联系人信息
    private void readContacts() {
        Cursor cursor = null;
        try{
//查询联系人数据,其中ContactsContract.CommonDataKinds.Phone.CONTENT_URI已做好封装
            cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,null,null,null);
            if(cursor != null){
//遍历cursor
                while(cursor.moveToNext()){
                    String displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                    String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                    contactsList.add(displayName + "\n" + number);
                    adapter.notifyDataSetChanged();
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(cursor != null){
//关闭cursor
                cursor.close();
            }
        }
    }
    @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){
                    readContacts();
                }else {
                    Toast.makeText(this,"You denied the permission" , Toast.LENGTH_LONG).show();
                }
				break;
			default:
        }
    }
}

3、修改AndroidManifest.xml代码,加入权限申请。

二、创建自己的内容提供器ContentProvider

分为以下几个步骤:

1)新建一个类继承ContentProvider来创建自己的内容提供器,并重写以下六个方法:

onCreate():初始化ContentProvider时调用,通常在这里完成对数据库的创建和升级等操作。返回true则表示初始化成功。

query():从ContentProvider查询数据。查询结果放在Cursor中。

insert():从ContentProvid插入数据,返回一个用于表示新纪录的URI。

update():从ContentProvider更新数据,返回受影响的行数。

delete():从ContentProvider删除数据,返回被删除的行数。

getType():根据传入的内容URI返回相应的MIME类型。

 

uri参数:表示查询哪张表。

projection参数:用于确定查询哪些列。

selection与selectionArgs参数:用于约束查询哪些行。

sortOrder参数:用于对结果进行排序。

2)Uri参数是从调用ContentResolver的增删改查方法时传递过来的,所以需要对传入的Uri参数进行解析,从中分析出调用方期望访问的表和数据。

内容URI的格式主要分两种:

    1、以路径结尾,表示期望访问该表中所有数据。

    2、以id结尾表示期望访问表中拥有相应id的数据。

当使用通配符来匹配时:

    1、*表示匹配任意长度任意字符。

    2、#表示匹配任意长度数字。

3)借助UriMatcher实现匹配内容URI。

        UriMatcher类提供了一个addURI()方法:

第一个参数:authority

第二个参数:path

第三个参数:自定义代码

        此时再调用UriMatcher类的match()方法时,就可以讲一个Uri对象传入,返回值是某个能匹配这个Uri对象所对应的自定义代码,利用这个代码就可以判断调用方期望访问哪张表中的数据了。

4)getType()方法是所有内容提供器都必须提供的方法,用于获取Uri对象所对应的MIME类型。

        主要分为三部分:

1、必须以vnd开头。

2、如果内容URI以路径结尾,则后接vnd.android.cursor.dir/;如果内容URI以id结尾,则后接vnd.android.cursor.item/。

3、最后接上vnd..

实例:实现跨进程数据共享

1、创建一个ContentProvider,右击com.launcher.databasetest包→New→Other→Content Provider

命名为DatabaseProvider:

        Exported属性表示是否允许外部程序访问我们的ContentProvider。

        Enabled属性表示是否启用这个ContentProvider。

2、修改DatabaseProvider中的代码。

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.launcher.databasetest.provider";
    private static UriMatcher uriMatcher;
    private MyDatabaseHelper dbHelper;

static {
//初始化
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//加入匹配模式 authority+path+自定义代码
        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 int delete(Uri uri, String selection, String[] selectionArgs) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        int deletedRows = 0;
        switch (uriMatcher.match(uri)){
            case BOOK_DIR:
                deletedRows = db.delete("Book", selection, selectionArgs);
                break;
            case BOOK_ITEM:
                String bookId = uri.getPathSegments().get(1);
                deletedRows = db.delete("Book", "id = ?", new String[]{ bookId });
                break;
            case CATEGORY_DIR:
                deletedRows = db.delete("Category", selection, selectionArgs);
                break;
            case CATEGORY_ITEM:
                String categoryId = uri.getPathSegments().get(1);
                deletedRows = db.delete("Category", "id = ?", new String[]{ categoryId });
                break;
            default:
                break;
        }
        return deletedRows;
    }

    @Override
    public String getType(Uri uri) {
        switch (uriMatcher.match(uri)){
            case BOOK_DIR:
                return "vnd.android.cursor.dir/vnd.com.launcher.databasetest.provider.book";
            case BOOK_ITEM:
                return "vnd.android.cursor.item/vnd.com.launcher.databasetest.provider.book";
            case CATEGORY_DIR:
                return "vnd.android.cursor.dir/vnd.com.launcher.databasetest.provider.category";
            case CATEGORY_ITEM:
                return "vnd.android.cursor.item/vnd.com.launcher.databasetest.provider.category";
        }
        return null;
    }

    @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);
//内容Uri解析为新id的URI对象
                uriReturn = Uri.parse("content://" + AUTHORITY + "/category/" + newCategoryId);
                break;
            default:
                break;
        }
        return uriReturn;
    }

    @Override
public boolean onCreate() {
//创建MyDatabaseHelper实例,返回true表示初始化成功。
        dbHelper = new MyDatabaseHelper(getContext(), "BookStore.db", null, 2);
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        Cursor cursor = null;
        switch (uriMatcher.match(uri)){
            case BOOK_DIR:
                cursor = db.query("Book", projection, selection, selectionArgs, null, null, sortOrder);
                break;
            case BOOK_ITEM:
//将内容URI权限之后的部分以/分割,并把分割后的结果放在一个字符串列表里面第0个位置为路径,第1位置为id。
                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 int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        int updatedRows = 0;
        switch (uriMatcher.match(uri)){
            case BOOK_DIR:
                updatedRows = db.update("Book", values,selection, selectionArgs);
                break;
            case BOOK_ITEM:
                String bookId = uri.getPathSegments().get(1);
                updatedRows = db.update("Book", values, "id = ?", new String[]{ bookId });
                break;
            case CATEGORY_DIR:
                updatedRows = db.update("Category", values,selection, selectionArgs);
                break;
            case CATEGORY_ITEM:
                String categoryId = uri.getPathSegments().get(1);
                updatedRows = db.update("Category", values, "id = ?", new String[]{ categoryId });
                break;
            default:
                break;
        }
        return updatedRows;
    }
}

2、在AndroidManifest中注册内容提供器。

 
 

        android:name属性指定了DatabaseProvider的类名。

 

访问DatabaseTestzh中的数据

1、新建ProviderTest项目访问DatabaseTest中的数据。

2、修改activity_main中代码,放置4个Button,分别用于添加、查询、修改和删除。


   

3、修改MainActivity中代码。

public class MainActivity extends AppCompatActivity {
    private String newId;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button addData = (Button) findViewById(R.id.add_data);
        addData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Uri uri = Uri.parse("content://com.launcher.databasetest.provider/book");
                ContentValues values = new ContentValues();
                values.put("name", "A Clash of Kings");
                values.put("author", "George Martin");
                values.put("pages", 1040);
                values.put("price", 22.85);
                Uri newUri = getContentResolver().insert(uri, values);
// getPathSegments()方法取出id,得到新增数据的id
                newId = newUri.getPathSegments().get(1);
            }
        });
        Button queryData = (Button) findViewById(R.id.query_data);
        queryData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
// Uri.parse()方法将内容URI解析为Uri对象
                Uri uri = Uri.parse("content://com.launcher.databasetest.provider/book");
                Cursor cursor = getContentResolver().query(uri, null, null, null,null);
                if(cursor != null){
//遍历Cursor
                    while (cursor.moveToNext()){
                        String name = cursor.getString(cursor.getColumnIndex("name"));
                        String author = cursor.getString(cursor.getColumnIndex("author"));
                        int pages = cursor.getInt(cursor.getColumnIndex("pages"));
                        double price = cursor.getDouble(cursor.getColumnIndex("price"));
                        Log.d("MainActivity", "book name is " + name);
                        Log.d("MainActivity", "book author is " + author);
                        Log.d("MainActivity", "book pages is " + pages);
                        Log.d("MainActivity", "book prices is " + price);
                    }
                    cursor.close();
                }
            }
        });
        Button updateData = (Button) findViewById(R.id.update_data);
        updateData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Uri uri = Uri.parse("content://com.launcher.databasetest.provider/book/" + newId);
                ContentValues values = new ContentValues();
                values.put("name", "A Storm of Swords");
                values.put("pages", 1216);
                values.put("price",24.05);
                getContentResolver().update(uri, values,null, null);
            }
        });
        Button deleteData = (Button) findViewById(R.id.delete_data);
        deleteData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Uri uri = Uri.parse("content://com.launcher.databasetest.provider/book/" + newId);
                getContentResolver().delete(uri, null, null);
            }
        });
    }
}

 

你可能感兴趣的:(Android,第一行代码)