Android四大组件之Content Provide

       ContentProvider(内容提供者)是Android中的四大组件之一,主要用于对外共享数据库。


       数据可以存储于文件系统、SQLite数据库或SharePreferences。  ContentProvider的数据主要存储于SQLite数据库中 内容提供者继承于ContentProvider 基类,为其它应用程序取用和存储它管理的数据实现了一套标准方法。


      然而,应用程序并不直接调用这些方法,而是使用一个 ContentResolver 对象,调用它的方法作为替代。ContentResolver可以与任意ContentProvider进行会话,与其合作来对所有相关交互通讯进行管理。

       

        ContentResolver通过指定的URI来确定与其通信的是哪一个ContentResolver对象。


1、写一个Provider继承系统的ContentProvider

   AndroidManifest.xml,这里的authorities作为每个ContentProvider的唯一标识符(一般是以包名加类名的方式命名)。类似我们访问网页的时候,输入的网址。

        <provider
            android:name="com.android.pbs.PBSProvider"
            android:authorities="com.android.pbs.Provider"
            android:exported="true" />

PBSProvider这个类是继承ContentProvider,需要实现ContentProvider的6个接口,即 onCreate()、 getType()、 insert()、delete()、 query()、  update()。

包含数据库的插入,删除,查询,更新所有动作。具体的实现如下:

package com.android.pbs;

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.SQLiteQueryBuilder;
import android.net.Uri;

public class PBSProvider extends ContentProvider {

    private static final String TAG = "PBSProvider";
    private DatebaseHelper mDBOpenHelper = null;
    private SQLiteDatabase mDb;

    private static final int MULTIPLE = 1;
    private static final int SINGLE = 2;

    private static final UriMatcher mUriMatcher;
    static {
        mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        mUriMatcher.addURI(DBInfo.AUTHORITY, DBInfo.PATH_MULTIPLE, MULTIPLE);
        mUriMatcher.addURI(DBInfo.AUTHORITY, DBInfo.PATH_SINGLE, SINGLE);
    }

    @Override
    public boolean onCreate() {
        Context context = getContext();
        mDBOpenHelper = new DatebaseHelper(context, DBInfo.DB_NAME, DBInfo.DB_VERSION);
        mDb = mDBOpenHelper.getWritableDatabase();
        if (mDb == null) {
            XLog.i(TAG, "getWritableDatabase() fail!");
            return false;
        }

        XLog.i(TAG, "onCreate()");
        return true;
    }

    public String getType(Uri uri) {
        XLog.i(TAG, "getType()");
        switch (mUriMatcher.match(uri)) {
        case MULTIPLE:
            return DBInfo.MIME_TYPE_MULTIPLE;
        case SINGLE:
            return DBInfo.MIME_TYPE_SINGLE;
        default:
            XLog.i(TAG, "unknow uri");
            return null;
        }
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        XLog.i(TAG, "insert()");
        try {
            long id = mDb.insert(DBInfo.DB_TABLE, null, values);
            if (id > 0) {
                Uri newUri = ContentUris.withAppendedId(DBInfo.CONTENT_URI, id);
                getContext().getContentResolver().notifyChange(newUri, null);
                return newUri;
            }
        } catch (SQLException e) {
            XLog.i(TAG, " error insert values fail!");
        }
        return uri;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int type = mUriMatcher.match(uri);
        XLog.i(TAG, "delete() type = " + type);
        int count = 0;
        try {
            switch (type) {
            case MULTIPLE:
                count = mDb.delete(DBInfo.DB_TABLE, selection, selectionArgs);
                break;
            case SINGLE:
                String segment = uri.getPathSegments().get(1);
                count = mDb.delete(DBInfo.DB_TABLE, DBInfo.KEY_ID + "=" + segment, selectionArgs);
                break;
            default:
                XLog.i(TAG, " unknow uri!");
                return count;
            }
        } catch (SQLException e) {
            XLog.i(TAG, " error, delete fail!");
        }

        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }

    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {

        int type = mUriMatcher.match(uri);
        XLog.i(TAG, "query() type = " + type);

        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
        qb.setTables(DBInfo.DB_TABLE);
        switch (type) {
        case SINGLE:
            qb.appendWhere(DBInfo.KEY_ID + "=" + uri.getPathSegments().get(1));
            break;
        default:
            break;
        }

        Cursor cursor = null;
        try {
        cursor = qb.query(mDb, projection, selection, selectionArgs, null, null, sortOrder);
        cursor.setNotificationUri(getContext().getContentResolver(), uri);
        } catch (SQLException e){
            XLog.i(TAG, "error, query fail!");
        }
        return cursor;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        int count = 0;
        int type = mUriMatcher.match(uri);
        XLog.i(TAG, "update() type = " + type);
        try {
            switch (type) {
            case MULTIPLE:
                count = mDb.update(DBInfo.DB_TABLE, values, selection, selectionArgs);
                break;
            case SINGLE:
                String segment = uri.getPathSegments().get(1);
                count = mDb.update(DBInfo.DB_TABLE, values, DBInfo.KEY_ID + "=" + segment, selectionArgs);
                break;
            default:
                XLog.i(TAG, "unknow uri");
                return count;
            }
        } catch (SQLException e) {
            XLog.i(TAG, "error,update fail");
        }

        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }
}

 Provider通过Android已经封装好的SQLiteOpenHelper对象来创建数据库和表格。

并且通过SQLiteOpenHelper的getWritableDatabase()得到SQLiteDatabase对象,这样子就可以对数据库操作了。


2、对应的SQLiteOpenHelper的实现如下:

package com.android.pbs;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;

public class DatebaseHelper extends SQLiteOpenHelper {

    private final String TAG = "DatebaseHelper";

    private static final String DB_CREATE = "create table " + DBInfo.DB_TABLE
            + "(" + DBInfo.KEY_ID + " integer primary key autoincrement, "
            + DBInfo.KEY_SOURCE + " text not null, "
            + DBInfo.KEY_CHANNEL + " integer, "
            + DBInfo.KEY_STATE + " text);";

    public DatebaseHelper(Context context, String dbName) {
        this(context, dbName, DBInfo.DB_VERSION);
    }

    public DatebaseHelper(Context context, String dbName, int version) {
        this(context, dbName, null, version);
    }

    public DatebaseHelper(Context context, String dbName, CursorFactory factory, int version) {
        super(context, dbName, factory, version);
        XLog.i(TAG, "DatebaseHelper() name = " + dbName + " version = " + version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        XLog.i(TAG, "onCreate()");
        db.execSQL(DB_CREATE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int arg1, int arg2) {
        XLog.i(TAG, "onUpgrade()");
        db.execSQL("DROP TABLE IF EXISTS " + DBInfo.DB_TABLE);
        onCreate(db);
    }
}

2.1 首先是通过父类的SQLiteOpenHelper()构造函数来创建对应的.db文件,传入对应的db的名字和版本号。

2.2 然后在通过 SQLiteDatabase的execSQL来创建对应的表格 table。创建table的时候,表格里有那几项和对应的数据格式确定下来。

     

 这样子对应的数据库的.db文件和对应的table就都创建好了。

 同时Provider里面也已经写好了对数据库进行删除,插入,查询和更新的接口。就等具体的应用来调用了。


3、应用程序并不直接调用provider写好的这些方法。而是使用一个 ContentResolver 对象,调用它的方法作为替代。

 怎么确保一定调用到我们写好的Provider? 答案是通过URI来确定。

 在AndroidManifest.xml里面我们写好了Provide的唯一标识符 android:authorities="com.android.pbs.Provider" 

ContentResolver在调用Provide的接口的时候,需要传一个URI,这个URI里面包含了我们Provide的唯一标识符。


3.1 我们事先把需要传入的URI先定义好,使用的时候不容易出错。

DBInfo.java

    public static final String AUTHORITY = "com.android.pbs.Provider";
    public static final String PATH_SINGLE = "pbsinfo/#";
    public static final String PATH_MULTIPLE = "pbsinfo";
    public static final String CONTENT_URI_STRING = "content://" + AUTHORITY + "/" + PATH_MULTIPLE;
    public static final Uri CONTENT_URI = Uri.parse(CONTENT_URI_STRING);


3.2  查询的时候,只要填入正确的URI和对应的要查询的条件,通过Resolver的query()接口就可以了。

    private String getSqlSelectionString() {
        String selection = DBInfo.KEY_SOURCE + " = ?" + " AND " + DBInfo.KEY_CHANNEL + " = ?";
        XLog.i(TAG, "getSqlSelectionString() " + selection);
        return selection;

    }

    private String[] getSqlSelectArgs() {
        mTvSource = mSourceSpinner.getSelectedItem().toString();
        mChannel = mChannelSpinner.getSelectedItem().toString();
        XLog.i(TAG, "getSqlSelectArgs() source = " + mTvSource);
        XLog.i(TAG, "getSqlSelectArgs() channel = " + mChannel);

        String[] selectionArg = new String[] {mTvSource, mChannel};
        return selectionArg;
    }

   ....
        case R.id.btn_query: {
            String selection = getSqlSelectionString();
            String[] selectionArg = getSqlSelectArgs();

            Cursor cursor = mContentResolver.query(DBInfo.CONTENT_URI,
                    new String[] {DBInfo.KEY_ID, DBInfo.KEY_STATE},
                    selection, selectionArg, null);

            if (!cursor.moveToFirst()) {
                XLog.i(TAG, "no record !");
                String no_record = mResources.getString(R.string.no_record);
                String info = mQueryStr + ":" + mTvSource + " " + mChannel + " " + no_record;
                updateInfoView(info);
                return;
            }

            String state;
            do {
                String id = cursor.getString(cursor.getColumnIndex(DBInfo.KEY_ID));
                state = cursor.getString(cursor.getColumnIndex(DBInfo.KEY_STATE));
                XLog.i(TAG, "id = " + id);
                XLog.i(TAG, "state = " + state);
            } while (cursor.moveToNext());
            cursor.close();

            String info = mQueryStr + ":" + mTvSource + " " + mChannel + " " + state;
            updateInfoView(info);
            return;
        }


在这里我们是查询数据库的KEY_ID 和KEY_STATE两个字段。

Cursor cursor = mContentResolver.query(DBInfo.CONTENT_URI,
                    new String[] {DBInfo.KEY_ID, DBInfo.KEY_STATE},
                    selection, selectionArg, null)

查询完后,我们可以通过cursor.moveToFirst()是否为空来判断,数据库里面是否有对应的数据。

最后通过cursor.getString(cursor.getColumnIndex(" "))就可以拿到对应项的数据了。


4、应用通过ContentResolver的其他接口对provider的相关操作,基本上都是差不多的。

完整的MainActivity的code如下:

package com.android.pbs;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.res.Resources;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;

import java.text.SimpleDateFormat;

public class MainActivity extends Activity implements OnClickListener {

    private static final String TAG = "MainActivity";
    private Spinner mSourceSpinner = null;
    private Spinner mChannelSpinner = null;
    private Spinner mStateSpinner = null;
    private Button mInsertBtn = null;
    private Button mQueryBtn = null;
    private Button mDeleteBtn = null;
    private Button mUpdateBtn = null;
    private TextView mInfo = null;
    private ScrollView mScrollView = null;

    private String mTvSource = null;
    private String mChannel = null;
    private String mState = null;

    private Resources mResources = null;
    private String mInsertStr = null;
    private String mQueryStr = null;
    private String mUpdateStr = null;
    private String mDeleteStr = null;

    private ContentResolver mContentResolver = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        XLog.i(TAG, "onCreate()");
        setContentView(R.layout.activity_main);
        findViews();
        setListeners();
        initData();
    }

    private void initData() {
        mContentResolver = getContentResolver();
        mResources = getResources();
        mInsertStr = mResources.getString(R.string.insert);
        mQueryStr = mResources.getString(R.string.query);
        mUpdateStr = mResources.getString(R.string.update);
        mDeleteStr = mResources.getString(R.string.delete);
        mInfo.setText("");

    }

    private void findViews() {
        // mStateItem = (LinearLayout) findViewById(R.id.state_item);
        mSourceSpinner = (Spinner) findViewById(R.id.sp_tv_source);
        mChannelSpinner = (Spinner) findViewById(R.id.sp_tv_channel);
        mStateSpinner = (Spinner) findViewById(R.id.sp_status);
        mInsertBtn = (Button) findViewById(R.id.btn_insert);
        mQueryBtn = (Button) findViewById(R.id.btn_query);
        mDeleteBtn = (Button) findViewById(R.id.btn_delete);
        mUpdateBtn = (Button) findViewById(R.id.btn_update);
        mInfo = (TextView) findViewById(R.id.info);
        mScrollView = (ScrollView) findViewById(R.id.scroll_view);
    }

    private void setListeners() {
        mInsertBtn.setOnClickListener(this);
        mQueryBtn.setOnClickListener(this);
        mUpdateBtn.setOnClickListener(this);
        mDeleteBtn.setOnClickListener(this);
    }

    private String getSqlSelectionString() {
        String selection = DBInfo.KEY_SOURCE + " = ?" + " AND " + DBInfo.KEY_CHANNEL + " = ?";
        XLog.i(TAG, "getSqlSelectionString() " + selection);
        return selection;

    }

    private String[] getSqlSelectArgs() {
        mTvSource = mSourceSpinner.getSelectedItem().toString();
        mChannel = mChannelSpinner.getSelectedItem().toString();
        XLog.i(TAG, "getSqlSelectArgs() source = " + mTvSource);
        XLog.i(TAG, "getSqlSelectArgs() channel = " + mChannel);

        String[] selectionArg = new String[] {mTvSource, mChannel};
        return selectionArg;
    }

    @Override
    public void onClick(View view) {
        int viewId = view.getId();
        XLog.i(TAG, "onClick() id = 0X" + Integer.toHexString(viewId));
        switch (viewId) {
        case R.id.btn_insert: {
            mTvSource = mSourceSpinner.getSelectedItem().toString();
            mChannel = mChannelSpinner.getSelectedItem().toString();
            mState = mStateSpinner.getSelectedItem().toString();

            ContentValues values = new ContentValues();
            values.put(DBInfo.KEY_SOURCE, mTvSource);
            values.put(DBInfo.KEY_CHANNEL, mChannel);
            values.put(DBInfo.KEY_STATE, mState);

            String selection = getSqlSelectionString();
            String[] selectionArg = getSqlSelectArgs();

            Cursor cursor = mContentResolver.query(DBInfo.CONTENT_URI,
                    new String[] {DBInfo.KEY_STATE}, selection, selectionArg, null);
            //has record,just update value
            if (cursor.moveToFirst()) {
                int result = mContentResolver.update(DBInfo.CONTENT_URI, values, selection, selectionArg);
                String resultStr = mResources.getString(R.string.fail);
                if (result > 0) {
                    resultStr = mResources.getString(R.string.success);
                }
                String info = mUpdateStr + ":" + mTvSource + " " + mChannel + " " + mState + " " + resultStr;
                updateInfoView(info);
                return;
            }

            //no record, insert the values
            mContentResolver.insert(DBInfo.CONTENT_URI, values);
            String info = mInsertStr + ":" + mTvSource + " " + mChannel + " " + mState;
            updateInfoView(info);
            return;
        }

        case R.id.btn_query: {
            String selection = getSqlSelectionString();
            String[] selectionArg = getSqlSelectArgs();

            Cursor cursor = mContentResolver.query(DBInfo.CONTENT_URI,
                    new String[] {DBInfo.KEY_ID, DBInfo.KEY_STATE},
                    selection, selectionArg, null);

            if (!cursor.moveToFirst()) {
                XLog.i(TAG, "no record !");
                String no_record = mResources.getString(R.string.no_record);
                String info = mQueryStr + ":" + mTvSource + " " + mChannel + " " + no_record;
                updateInfoView(info);
                return;
            }

            String state;
            do {
                String id = cursor.getString(cursor.getColumnIndex(DBInfo.KEY_ID));
                state = cursor.getString(cursor.getColumnIndex(DBInfo.KEY_STATE));
                XLog.i(TAG, "id = " + id);
                XLog.i(TAG, "state = " + state);
            } while (cursor.moveToNext());
            cursor.close();

            String info = mQueryStr + ":" + mTvSource + " " + mChannel + " " + state;
            updateInfoView(info);
            return;
        }

        case R.id.btn_update: {
            mTvSource = mSourceSpinner.getSelectedItem().toString();
            mChannel = mChannelSpinner.getSelectedItem().toString();
            mState = mStateSpinner.getSelectedItem().toString();

            ContentValues values = new ContentValues();
            values.put(DBInfo.KEY_SOURCE, mTvSource);
            values.put(DBInfo.KEY_CHANNEL, mChannel);
            values.put(DBInfo.KEY_STATE, mState);

            String selection = getSqlSelectionString();
            String[] selectionArg = getSqlSelectArgs();
            int result = mContentResolver.update(DBInfo.CONTENT_URI, values, selection, selectionArg);

            String resultStr = mResources.getString(R.string.fail);
            if (result > 0) {
                resultStr = mResources.getString(R.string.success);
            }

            String info = mUpdateStr + ":" + mTvSource + " " + mChannel + " " + mState + resultStr;
            updateInfoView(info);
            return;
        }

        case R.id.btn_delete: {
            String selection = getSqlSelectionString();
            String[] selectionArg = getSqlSelectArgs();
            int count = mContentResolver.delete(DBInfo.CONTENT_URI, selection, selectionArg);
            String resultStr = mResources.getString(R.string.fail);
            if (count > 0) {
                resultStr = mResources.getString(R.string.success);
            }

            String info = mDeleteStr + ":" + mTvSource + " " + mChannel + " " + resultStr;
            updateInfoView(info);
            return;
        }

        default:
            break;
        }
    }

    @SuppressLint("SimpleDateFormat")
    private void updateInfoView(String info) {
        XLog.i(TAG, "updateInbfo()");
        SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr = dateformat.format(System.currentTimeMillis());
        String newInfo = dateStr + " " + info + "\n";
        mInfo.setText(mInfo.getText() + newInfo);
        mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
    }

    @Override
    protected void onResume() {
        super.onResume();
        XLog.i(TAG, "onResume() ");
    }

    @Override
    protected void onPause() {
        super.onPause();
        XLog.i(TAG, "onPause() ");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        XLog.i(TAG, "onDestroy()");
    }

}

 附件: Provide的Demo Source code下载



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值