Android ContentProvider使用样例

需要在AndroidMainfest.xml中添加组件provider:

<provider
            android:authorities="com.sudoku.jack.sudoku.provider.common"
            android:name="com.sudoku.jack.sudoku.provider.CommonContentProvider"
            android:exported="false"
            />

在ContentProvider维护着一个SqliteOpenHelper类,随应用启动时调用onCreate()方法一次来进行初始化,之后不再调用该方法。onCreate()方法中实例化Sqlite数据库时传入数据库版本号,当新的版本号大于旧的版本号时,数据库将会调用onUpgrade()方法进行升级,里面实现自己的升级逻辑,通常是drop表再重建表。

package com.sudoku.jack.sudoku.provider;

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.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.provider.BaseColumns;
import android.support.annotation.NonNull;
import android.text.TextUtils;

public class CommonContentProvider extends ContentProvider {
    private MySQLiteOpenHelper myOpenHelper;

    public static final String AUTHORITY = "com.sudoku.jack.sudoku.provider.common";
    public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sudoku.common";
    public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sudoku.common";

    //PuzzleTable表定义
    public static final class PuzzleTable implements BaseColumns {
        public static final String TABLE_NAME = "puzzles";
        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"+TABLE_NAME);
        //表字段
        public static final String COL_NAME = "COL_NAME";//数独标题,唯一
        public static final String COL_PUZZLE = "COL_PUZZLE";//数独内容,唯一
        public static final String COL_PUZZLE_TYPE = "COL_PUZZLE_TYPE";//数独分类,外键
        public static final String COL_GRADE_USER = "COL_GRADE_USER";//用户评级
        public static final String COL_GRADE_GLOBAL = "COL_GRADE_GLOBAL";//系统评级
        public static final String COL_TIME_BEST = "COL_TIME_BEST";//最佳完成用时,秒(s)
        public static final String COL_TIME_CURRENT = "COL_TIME_CURRENT";//当前用时,秒(s)
        public static final String COl_TIME_COMPUTER = "COl_TIME_COMPUTER";//计算机执行用时,毫秒(ms)
        public static final String COL_RESULT_USER = "COL_RESULT_USER";//用户最后求解的结果
        public static final String COL_RESULT = "COL_RESULT";//数独的解
        public static final String COL_RESULT_COUNT = "COL_RESULT_COUNT";//解的数量
        public static final String COL_IS_COMPLETE = "COL_IS_COMPLETE";//用户是否完成答题,0表示false未完成
        //完成状态常量
        //public static final int STATUS_NOT_COMPLETE = 0;//初始状态,未完成
        public static final int STATUS_COMPLETE = 1;//完成过,只能由未完成转变成完成,不可逆
        //创建语句
        public static final String CREATE_PUZZLE_TABLE = "create table " + PuzzleTable.TABLE_NAME +
                "(" + PuzzleTable._ID + " INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL ," +
                PuzzleTable.COL_NAME + " TEXT UNIQUE NOT NULL ," +
                PuzzleTable.COL_PUZZLE_TYPE + " TEXT  NOT NULL," +
                PuzzleTable.COL_PUZZLE + " COL_PUZZLE TEXT UNIQUE NOT NULL  ," +
                PuzzleTable.COL_GRADE_USER + " INTEGER DEFAULT (0) NOT NULL," +
                PuzzleTable.COL_GRADE_GLOBAL + " INTEGER NOT NULL DEFAULT (0)," +
                PuzzleTable.COL_TIME_BEST + " INTEGER NOT NULL DEFAULT (0)," +
                PuzzleTable.COL_TIME_CURRENT + " INTEGER NOT NULL DEFAULT (0)," +
                PuzzleTable.COl_TIME_COMPUTER + " INTEGER NOT NULL DEFAULT (0)," +
                PuzzleTable.COL_RESULT_USER + "  TEXT," +
                PuzzleTable.COL_RESULT + " TEXT," +
                PuzzleTable.COL_IS_COMPLETE + " INTEGER NOT NULL DEFAULT (0)," +
                PuzzleTable.COL_RESULT_COUNT + " INTEGER NOT NULL DEFAULT (1) " +
                ")";
    }

    //Type表定义
    public static final class TypeTable implements BaseColumns {
        public static final String TABLE_NAME = "types";
        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME);
        //表字段
        public static final String COL_NAME = "COL_NAME";//类型名称,唯一,对应于一个文件
        public static final String COL_LOADED = "COL_LOADED";//表示该类型是否已经加载过了,只加载一次
        public static final String COL_FLAG = "COL_FLAG";//分类标志,0表示系统初始默认的分类,1表示自定义
        //创建语句
        public static final String CREATE_TYPE_TABLE = "create table " + TABLE_NAME +
                "(" + _ID + " INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL ," +
                COL_NAME + " TEXT UNIQUE NOT NULL ," +
                COL_FLAG + " INTEGER DEFAULT (0) NOT NULL ," +
                COL_LOADED + " INTEGER NOT NULL DEFAULT (0) " +
                ")";
        public static final int TYPE_FLAG_SYS = 0;//系统默认分类标志,此分类不允许修改
    }
    @Override
    public boolean onCreate() {
        System.out.println("创建数据源组件");
        myOpenHelper = new MySQLiteOpenHelper(getContext(), MySQLiteOpenHelper.DATABASE_NAME,
                null, MySQLiteOpenHelper.DATABASE_VERSION);
        return true;
    }

    private static final int PUZZLE_ALLROWS = 1;
    private static final int PUZZLE_SINGLE_ROW = 2;
    private static final int TYPE_ALLROWS = 3;
    private static final int TYPE_SINGLE_ROW = 4;
    //增加

    private static final UriMatcher uriMatcher;

    //Populate the UriMatcher object, where a URI ending in 'files' will
    //correspond to a request for all items, and 'files/[rowID]'
    //represents a single row.
    static {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(AUTHORITY, PuzzleTable.TABLE_NAME, PUZZLE_ALLROWS);
        uriMatcher.addURI(AUTHORITY, PuzzleTable.TABLE_NAME + "/#", PUZZLE_SINGLE_ROW);
        uriMatcher.addURI(AUTHORITY, TypeTable.TABLE_NAME, TYPE_ALLROWS);
        uriMatcher.addURI(AUTHORITY, TypeTable.TABLE_NAME + "/#", TYPE_SINGLE_ROW);
    }

    @Override
    public String getType(@NonNull Uri uri) {
        switch (uriMatcher.match(uri)) {
            case PUZZLE_ALLROWS:
            case TYPE_ALLROWS:
                return CONTENT_TYPE;
            case PUZZLE_SINGLE_ROW:
            case TYPE_SINGLE_ROW:
                return CONTENT_ITEM_TYPE;
            default:
                throw new IllegalArgumentException("Unsupported URI: " + uri);
        }
    }
@Override
    public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        System.out.println("查询Uri"+uri);
        // Open a read-only database.
        SQLiteDatabase db ;
        try{
            db = myOpenHelper.getWritableDatabase();
        }catch(SQLiteException ex){
            db = myOpenHelper.getReadableDatabase();
        }
         // Replace these with valid SQL statements if necessary.
        String groupBy = null;
        String having = null;

        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
        // If this is a row query, limit the result set to the passed in row.
        String type = getType(uri);
        String tableName = uri.getPathSegments().get(0);
        if(CONTENT_ITEM_TYPE.equals(type)){
            queryBuilder.appendWhere("_id = "+uri.getPathSegments().get(1));
        }
        queryBuilder.setTables(tableName);
        return queryBuilder.query(db, projection, selection, selectionArgs, groupBy, having, sortOrder);
    }
    @Override
    public Uri insert(@NonNull Uri uri, ContentValues contentvalues) {
        System.out.println("插入Uri"+uri);
        // Open a read / write database to support the transaction.
        SQLiteDatabase db = myOpenHelper.getWritableDatabase();
         // To add empty rows to your database by passing in an empty Content Values
        // object, you must use the null column hack parameter to specify the name of
        // the column that can be set to null.
        String nullColumnHack = null;
        String type = getType(uri);
        if(CONTENT_ITEM_TYPE.equals(type)) throw new IllegalArgumentException("Unknown URI " + uri);
        String tableName = uri.getPathSegments().get(0);
        long id = db.insert(tableName, nullColumnHack, contentvalues);
        if(id>-1){
             // Construct and return the URI of the newly inserted row.
            Uri insertId = ContentUris.withAppendedId(uri, id);
            // Notify any observers of the change in the data set.
            if(getContext()!=null)
                getContext().getContentResolver().notifyChange(insertId, null);
            return insertId;
        }
        else
            return null;
    }
    @Override
    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
        System.out.println("删除uri:"+uri);
         // Open a read / write database to support the transaction.
        SQLiteDatabase db = myOpenHelper.getWritableDatabase();
        String type = getType(uri);
        String tableName = uri.getPathSegments().get(0);
        if(CONTENT_ITEM_TYPE.equals(type)){
            selection = "_id="+uri.getPathSegments().get(1)+
                    (!TextUtils.isEmpty(selection)?" and ("+selection+")":"");
        }
        int deleteCount = db.delete(tableName,selection,selectionArgs);
        // To return the number of deleted items, you must specify a where
        // clause. To delete all rows and return a value, pass in "1".
        /*if(selection == null){
            selection = "1";
        }
         // Execute the deletion.
        int deleteCount = db.delete(MySQLiteOpenHelper.DATABASE_TABLE, selection, selectionArgs);*/
        if(getContext()!=null)
            getContext().getContentResolver().notifyChange(uri, null);
        return deleteCount;
    }

    @Override
    public int update(@NonNull Uri uri, ContentValues contentvalues, String selection,
            String[] selectionArgs) {
        System.out.println("fileContProv update");
         // Open a read / write database to support the transaction.
        SQLiteDatabase db = myOpenHelper.getWritableDatabase();
        String type = getType(uri);
        String tableName = uri.getPathSegments().get(0);
        if(CONTENT_ITEM_TYPE.equals(type)){
            selection = "_id="+uri.getPathSegments().get(1)+
                    (!TextUtils.isEmpty(selection)?" and ("+selection+")":"");
        }
        int updateCount = db.update(tableName,contentvalues,selection,selectionArgs);
        // Notify any observers of the change in the data set.
        if(getContext()!=null)
            getContext().getContentResolver().notifyChange(uri, null);
        return updateCount;
    }

    private static class MySQLiteOpenHelper extends SQLiteOpenHelper {
        private static final String DATABASE_NAME = "sudoku.db";
        private static final int DATABASE_VERSION = 19;
        public MySQLiteOpenHelper(Context context, String name,
                                  CursorFactory factory, int version) {
            super(context, name, factory, version);
        }
        // SQL statement to create a new database.       files
        // Called when no database exists in disk and the helper class needs
        // to create a new one.
        @Override
        public void onCreate(SQLiteDatabase db) {
            System.out.println("SQLiteDatabase onCreate");
            db.execSQL(PuzzleTable.CREATE_PUZZLE_TABLE);
            db.execSQL(TypeTable.CREATE_TYPE_TABLE);
            //初始化
        }
        // Called when there is a database version mismatch, meaning that the version
        // of the database on disk needs to be upgraded to the current version.
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            System.out.println("TaskDBAdapter" + "Upgrading from version " +
                    oldVersion + " to " +
                    newVersion + ", which will destroy all old data");
            // Upgrade the existing database to conform to the new version. Multiple
            // previous versions can be handled by comparing oldVersion and newVersion
            // values.
            // The simplest case is to drop the old table and create a new one.
            db.execSQL("DROP TABLE IF EXISTS " + PuzzleTable.TABLE_NAME);
            db.execSQL("DROP TABLE IF EXISTS " + TypeTable.TABLE_NAME);
            // Create a new one.
            onCreate(db);
        }
    }
}

//ListFragment 结合Provider的使用

package com.sudoku.jack.sudoku;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ListFragment;
import android.app.LoaderManager;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.CursorLoader;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

import com.sudoku.jack.sudoku.adapter.TyperCursorAdapter;
import com.sudoku.jack.sudoku.provider.CommonContentProvider;
import com.sudoku.jack.sudoku.util.Helper;
import com.sudoku.jack.sudoku.util.ProviderHelper;

//数独题库分类,创建此Fragment时必须要有targetFragment
public class SudokuTypeFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor>, TyperCursorAdapter.OnItemClickCallback {
    private static final int LOADER_TYPE = 2;
    private TyperCursorAdapter adapter;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_sudoku_type, container, false);
        ListView listView = (ListView) view.findViewById(android.R.id.list);
        adapter = new TyperCursorAdapter(getActivity(), null, false);//构造空的适配器
        adapter.setOnItemClickCallback(this);
        listView.setAdapter(adapter);
        listView.setEmptyView(view.findViewById(android.R.id.empty));
        return view;
    }

    @Override
    public void onResume() {
        super.onResume();
        getLoaderManager().restartLoader(LOADER_TYPE, null, this);//重启或新起一个Loader,将会调用onCreateLoader
    }

    /*@Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        Cursor cursor = (Cursor) l.getAdapter().getItem(position);
        String  typeName = cursor.getString(cursor.getColumnIndex(CommonContentProvider.TypeTable.COL_NAME));
        new ProviderHelper(getActivity()).loadSudokuFromAssetsThread(typeName);
        Intent intent = new Intent();
        intent.putExtra(Helper.TYPE_NAME, typeName);
        //回调
        if(getTargetFragment()!=null)
            getTargetFragment().onActivityResult(SudokuGameStartFragment.REQUEST_CODE_TYPE_CALLBACK, Activity.RESULT_OK, intent);
    }*/
    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return new CursorLoader(getActivity(), CommonContentProvider.TypeTable.CONTENT_URI, null, null, null, null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        adapter.swapCursor(data);
        adapter.notifyDataSetChanged();//cursor有值了填充视图
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        adapter.swapCursor(null);
    }


}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值