SQLite数据库与Contentprovider

Posted 金洪光

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQLite数据库与Contentprovider相关的知识,希望对你有一定的参考价值。

ContentProvider

在创建ContentProvider时,需要首先使用数据库、文件系统或网络实现底层存储功能,

然后在继承ContentProvider的类中实现基本数据操作的接口函数,包括添加、删除、查找和更新等功能。

调用者不能够直接调用ContentProvider的接口函数,而需要使用ContentResolver对象,

通过URI间接调用ContentProvider。下图是ContentProvider调用关系。

 

URI

URI是通用资源标志符(Uniform Resource Identifier),用来定位任何远程或本地的可用资源

ContentProvider使用的URI语法结构如下

content://<authority>/<data_path>/<id>

content://是通用前缀,表示该URI用于ContentProvider定位资源,无需修改。

<authority>是授权者名称,用来确定具体由哪一个ContentProvider提供资源。因此,一般<authority>都由类的小写全称组成,以保证唯一性。

<data_path>是数据路径,用来确定请求的是哪个数据集。

 

例如:

content://edu.hrbeu.peopleprovider/people/3

可以省略id(/3)部分那么意味着整个数据。

 

UriMatcher:

在新构造的ContentProvider类中,通过构造一个UriMatcher,判断URI是单条数据还是多条数据。

public void  addURI  (String authority, String path, int code)

authority表示匹配的授权者名称

path表示数据路径

#可以代表任何数字 (content://<authority>/<data_path>/#

code表示返回代码uriMatcher.match(uri))的返回值

 

注册ContentProvider

<provider android:name = ".PeopleProvider" android:authorities = "edu.hrbeu.peopleprovider"/> 

 

实例:

ContentProvider一般用于两个不同的进程之间的数据共享。

  1. 假设我们有一个新的工程(app),在此工程中创建一个people.db数据库,然后通过自定义了一个ContentProvider来共享数据库中的data。
  2. 我们可以通过注册provider时用到的authority在配合db path之类的来连接(content://<authority>/<data_path>/#)读取内容提供者(不同进程)的数据。

首先是步骤1:

*只要在AndroidManifast中注册provider就会执行对应的provider类。无需再MainActivity中调用或无需直接调用自定义的new provider。

即系统自动会加载调用PeopleProvider类。

<provider android:name = ".PeopleProvider" android:authorities = "edu.hrbeu.peopleprovider"/> 

 

继承ContentProvider时代码如下:

import android.content.*;
import android.database.Cursor;
import android.net.Uri;
 
public class PeopleProvider extends ContentProvider{
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public String getType(Uri uri) {
        // TODO Auto-generated method stub
        return null;
    }
 
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        // TODO Auto-generated method stub
        return null;
    }
 
    @Override
    public boolean onCreate() {
        // TODO Auto-generated method stub
        return false;
    }
         @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        // TODO Auto-generated method stub
        return null;
    }
 
    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        // TODO Auto-generated method stub
        return 0;
    }
}

类似数据库操作。可以这么理解,相对来说好理解。

开始贴代码。。。

package edu.hrbeu.contentproviderdemo;
 
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;

public class PeopleProvider extends ContentProvider {
    
    private static final String DB_NAME = "people.db";
    private static final String DB_TABLE = "peopleinfo";
    private static final int DB_VERSION = 1;
    
    private SQLiteDatabase db;
    private DBOpenHelper dbOpenHelper;
    
    private static final int MULTIPLE_PEOPLE = 1;
    private static final int SINGLE_PEOPLE = 2;
    private static final UriMatcher uriMatcher;
    static {
         uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
         uriMatcher.addURI(People.AUTHORITY, People.PATH_MULTIPLE, MULTIPLE_PEOPLE);
         uriMatcher.addURI(People.AUTHORITY, People.PATH_SINGLE, SINGLE_PEOPLE);
    }

    @Override
    public boolean onCreate() {
        // TODO Auto-generated method stub
        Context context = getContext();
        dbOpenHelper = new DBOpenHelper(context, DB_NAME, null, DB_VERSION);
        db = dbOpenHelper.getWritableDatabase();
 
        if (db == null)
            return false;
        else 
            return true;    

    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        // TODO Auto-generated method stub
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
        qb.setTables(DB_TABLE);
        switch(uriMatcher.match(uri)){
            case SINGLE_PEOPLE:
                qb.appendWhere(People.KEY_ID + "=" + uri.getPathSegments().get(1));
                break;
            default:
                break;
        }
        Cursor cursor = qb.query(db, 
                projection, 
                selection, 
                selectionArgs, 
                null, 
                null, 
                sortOrder);
        cursor.setNotificationUri(getContext().getContentResolver(), uri);
        return cursor;

    }

    @Override
    public String getType(Uri uri) {
        // TODO Auto-generated method stub
        switch(uriMatcher.match(uri)){
        case MULTIPLE_PEOPLE:
    return People.MINE_TYPE_MULTIPLE;
        case SINGLE_PEOPLE:
    return People.MINE_TYPE_SINGLE;
        default:
                throw new IllegalArgumentException("Unkown uri:"+uri);
}

    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        // TODO Auto-generated method stub
        long id = db.insert(DB_TABLE, null, values);
        if ( id > 0 ){
            Uri newUri = ContentUris.withAppendedId(People.CONTENT_URI, id);
            getContext().getContentResolver().notifyChange(newUri, null);
            return newUri;
        }
        throw new SQLException("Failed to insert row into " + uri);

    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // TODO Auto-generated method stub
        int count = 0;
        switch(uriMatcher.match(uri)){
    case MULTIPLE_PEOPLE:
           count = db.delete(DB_TABLE, selection, selectionArgs);
           break;
                  case SINGLE_PEOPLE:
           String segment = uri.getPathSegments().get(1);
                         count = db.delete(DB_TABLE, People.KEY_ID + "=" + segment, selectionArgs);
           break;
   default:
           throw new IllegalArgumentException("Unsupported URI:" + uri);
}
        getContext().getContentResolver().notifyChange(uri, null); 
        return count;

    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        // TODO Auto-generated method stub
        int count;
        switch(uriMatcher.match(uri)){
                 case MULTIPLE_PEOPLE:
                        count = db.update(DB_TABLE, values, selection, selectionArgs);
                        break;
                                     case SINGLE_PEOPLE:
                                             String segment = uri.getPathSegments().get(1);
                        count = db.update(DB_TABLE, values, People.KEY_ID+"="+segment, selectionArgs);
                           break;
                                     default:
            throw new IllegalArgumentException("Unknow URI:" + uri);     
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return count;

    }
    
      private static class DBOpenHelper extends SQLiteOpenHelper {
          
          public DBOpenHelper(Context context, String name, CursorFactory factory, int version) {
            super(context, name, factory, version);
          }
          private static final String DB_CREATE = "create table " + 
                    DB_TABLE + " (" + People.KEY_ID + " integer primary key autoincrement, " +
                           People.KEY_NAME+ " text not null, " + People.KEY_AGE+ " integer," + People.KEY_HEIGHT + " float);";
        @Override
        public void onCreate(SQLiteDatabase _db) {
            // TODO Auto-generated method stub
            _db.execSQL(DB_CREATE);
        }
        @Override
        public void onUpgrade(SQLiteDatabase _db, int oldVersion, int newVersion) {
            // TODO Auto-generated method stub
            _db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE);
               onCreate(_db);

        }

      }
    
}
package edu.hrbeu.contentproviderdemo;
import android.net.Uri;
 
public class People{
    
    public static final String MIME_DIR_PREFIX = "vnd.android.cursor.dir";
    public static final String MIME_ITEM_PREFIX = "vnd.android.cursor.item";
    public static final String MINE_ITEM = "vnd.hrbeu.people";
    
    public static final String MINE_TYPE_SINGLE = MIME_ITEM_PREFIX + "/" + MINE_ITEM;
    public static final String MINE_TYPE_MULTIPLE = MIME_DIR_PREFIX + "/" + MINE_ITEM;
    public static final String AUTHORITY = "edu.hrbeu.peopleprovider";
    public static final String PATH_SINGLE = "people/#";
    public static final String PATH_MULTIPLE = "people";
    public static final String CONTENT_URI_STRING = "content://" + AUTHORITY + "/" + PATH_MULTIPLE;
    public static final Uri  CONTENT_URI = Uri.parse(CONTENT_URI_STRING); 
    
    public static final String KEY_ID = "_id";
    public static final String KEY_NAME = "name";
    public static final String KEY_AGE = "age";
    public static final String KEY_HEIGHT = "height";
}

MainActivity是空的。。。不贴出来了。

运行结果没有任何内容,因为仅是添加了一个provider。

 

看一下步骤2:

在另一个App中调用此ContentProvider。

无需再AndroidManifast中注册provider。

只需对应步骤1中的People类里的静态变量是完全匹配的就是可以了。

也就是说URI需要与我们自定义的ContentProvider保持一致。

package edu.hrbeu.contentresolverdemo;
import android.net.Uri;
 
public class People{
    
    public static final String MIME_DIR_PREFIX = "vnd.android.cursor.dir";
    public static final String MIME_ITEM_PREFIX = "vnd.android.cursor.item";
    public static final String MINE_ITEM = "vnd.hrbeu.people";
    
    public static final String MINE_TYPE_SINGLE = MIME_ITEM_PREFIX + "/" + MINE_ITEM;
    public static final String MINE_TYPE_MULTIPLE = MIME_DIR_PREFIX + "/" + MINE_ITEM;
    public static final String AUTHORITY = "edu.hrbeu.peopleprovider";
    public static final String PATH_SINGLE = "people/#";
    public static final String PATH_MULTIPLE = "people";
    public static final String CONTENT_URI_STRING = "content://" + AUTHORITY + "/" + PATH_MULTIPLE;
    public static final Uri  CONTENT_URI = Uri.parse(CONTENT_URI_STRING); 
    
    public static final String KEY_ID = "_id";
    public static final String KEY_NAME = "name";
    public static final String KEY_AGE = "age";
    public static final String KEY_HEIGHT = "height";
}

操作Contentpriver提供的数据我们需要用到ContentResolver:

package edu.hrbeu.contentresolverdemo;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class ContentResolverDemo extends Activity {

    private EditText nameText;
    private EditText ageText;
    private EditText heightText;
    private EditText idEntry;

    private TextView labelView;
    private TextView displayView;

    private ContentResolver resolver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_content_resolver_demo);
        nameText = (EditText) findViewById(R.id.name);
        ageText = (EditText) findViewById(R.id.age);
        heightText = (EditText) findViewById(R.id.hight);
        idEntry = (EditText) findViewById(R.id.id);

        labelView = (TextView) findViewById(R.id.label);
        displayView = (TextView) findViewById(R.id.display);
        Button addButton = (Button) findViewById(R.id.button1);
        Button queryAllButton = (Button) findViewById(R.id.button2);
        Button clearButton = (Button) findViewById(R.id.button3);
        Button queryButton = (Button) findViewById(R.id.button6);
        Button deleteButton = (Button) findViewById(R.id.button5);
        Button updateButton = (Button) findViewById(R.id.button7);

        resolver = this.getContentResolver();
        addButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                ContentValues values = new ContentValues();

                values.put(People.KEY_NAME, nameText.getText().toString());
                values.put(People.KEY_AGE,
                        Integer.parseInt(ageText.getText().toString()));
                values.put(People.KEY_HEIGHT,
                        Float.parseFloat(heightText.getText().toString()));

                Uri newUri = resolver.insert(People.CONTENT_URI, values);
                labelView.setText("添加成功,URI:" + newUri);

            }
        });
        queryAllButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Cursor cursor = resolver.query(People.CONTENT_URI,
                        new String[] { People.KEY_ID, People.KEY_NAME,
                                People.KEY_AGE, People.KEY_HEIGHT }, null,
                        null, null);
                if (cursor == null) {
                    labelView.setText("数据库中没有数据");
                    return;
                }
                labelView.setText("数据库:" + String.valueOf(cursor.getCount())
                        + "条记录");

                String msg = "";
                if (cursor.moveToFirst()) {
                    do {
                        msg += "ID:"
                                + cursor.getInt(cursor
                                        .getColumnIndex(People.KEY_ID)) + ",";
                        msg += "姓名:"
                                + cursor.getString(cursor
                                        .getColumnIndex(People.KEY_NAME)) + ",";
                        msg += "年龄:"
                                + cursor.getInt(cursor
                                        .getColumnIndex(People.KEY_AGE)) + ", ";
                        msg += "身高:"
                                + cursor.getFloat(cursor
                                        .getColumnIndex(People.KEY_HEIGHT))
                                + "\\n";
                    } while (cursor.moveToNext());
                }

                displayView.setText(msg);

            }
        });

        clearButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                displayView.setText("");
            }
        });

        queryButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Uri uri = Uri.parse(People.CONTENT_URI_STRING + "/"
                        + idEntry.getText().toString());
                Cursor cursor = resolver.query(uri, new String[] {
                        People.KEY_ID, People.KEY_NAME, People.KEY_AGE,
                        People.KEY_HEIGHT }, null, null, null);
                if (cursor == null) {
                    labelView.setText("数据库中没有数据");
                    return;
                }

                String msg = "";
                if (cursor.moveToFirst()) {
                    msg += "ID:"
                            + cursor.getInt(cursor
                                    .getColumnIndex(People.KEY_ID)) + ",";
                    msg += "姓名:"
                            + cursor.getString(cursor
                                    .getColumnIndex(People.KEY_NAME)) + ",";
                    msg += "年龄:"
                            + cursor.getInt(cursor
                                    .getColumnIndex(People.KEY_AGE)) + ", ";
                    msg += "身高:"
                            + cursor.getFloat(cursor
                                    .getColumnIndex(People.KEY_HEIGHT)) + "\\n";
                }

                labelView.setText("数据库:");
                displayView.setText(msg);

            }
        });
        deleteButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Uri uri = Uri.parse(People.CONTENT_URI_STRING + "/"
                        + idEntry.getText().toString());
                int result = resolver.delete(uri, null, null);
                String msg = "删除ID为" + idEntry.getText().toString() + "的数据"
                        + (result > 0 ? "成功" : "失败");
                labelView.setText(msg);
            }
        });

        updateButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                ContentValues values = new ContentValues();
                values.put(People.KEY_NAME, nameText.getText().toString());
                values.put(People.KEY_AGE,
                        Integer.parseInt(ageText.getText().toString()));
                values.put(People.KEY_HEIGHT,
                        Float.parseFloat(heightText.getText().toString()));

                Uri uri = Uri.parse(People.CONTENT_URI_STRING + "/"
                        + idEntry.getText().toString());
                int result = resolver.update(uri, values, null, null);

                String msg = "更新ID为" + idEntry.getText().toString() + "的数据"
                        + (result > 0 ? "成功" : "失败");
                labelView.setText(msg);

            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.content_resolver_demo, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

事成相识的布局文件也附上:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="edu.hrbeu.contentresolverdemo.ContentResolverDemo" >

    <TextView android:id="@+id/Username" 
        android:layout_height="wrap_content" 
        android:layout_width="fill_parent" 
        android:text="用户名:">
    </TextView>

    <EditText
        android:id="@+id/name"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/Username" >

    </EditText>

    <TextView android:id="@+id/Userage" 
        android:layout_height="wrap_content" 
        android:layout_width="fill_parent" 
        android:layout_below="@id/name"
        android:text="年龄:">
    </TextView>
    <EditText android:id="@+id/age" 
        android:layout_height="wrap_content" 
        android:layout_width="fill_parent" 
        android:layout_below="@id/Userage">
    </EditText>
    
     <TextView android:id="@+id/Userhight" 
        android:layout_height="wrap_content" 
        android:layout_width="fill_parent" 
        android:layout_below="@id/age"
        android:text="身高:">
    </TextView>
    <EditText android:id="@+id/hight" 
        android:layout_height="wrap_content" 
        android:layout_width="fill_parent" 
        android:layout_below="@id/Userhight">
    </EditText>

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/button1"
        android:layout_alignBottom="@+id/button1"
        android:layout_centerHorizontal="true"
        android:text="全部显示" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/button2"
        android:layout_alignBottom="@+id/button2"
        android:layout_alignRight="@+id/hight"
        android:text="清除显示" />
    
    <TextView android:id="@+id/Userid" 
        android:layout_height="wrap_content" 
        android:layout_width="fill_parent" 
        android:layout_below="@id/button1"
        android:text="ID:">
    </TextView>
    <EditText android:id="@+id/id" 
        android:layout_height="wrap_content" 
        android:layout_width="fill_parent" 
        android:layout_below="@id/Userid">
    </EditText>

    <Button
        android:id="@+id/button6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/button5"
        android:layout_alignBottom="@+id/button5"
        android:layout_alignLeft="@+id/button2"
        android:text="ID查询" />

    <Button
        android:id="@+id/button7"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/button6"
        android:layout_alignBottom="@+id/button6"
        android:layout_alignLeft="@+id/button3"
        android:text="ID更新" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/hight"
        android:text="添加数据" />

    <以上是关于SQLite数据库与Contentprovider的主要内容,如果未能解决你的问题,请参考以下文章

Android 存储(本地存储 SD卡存储 SharedPreference SQLite ContentProvider)

android - 没有 Content Provider 的 CursorLoader 和 SQLite

Android 之 ContentProvider 与 ContentResolver

ContentProvider 的批处理操作

ContentProvider 的批处理操作

Android面试四大组件之内容提供者ContentProvider