您的位置:首页 > 移动开发 > Android开发

Android ContentProvider使用样例

2015-08-24 15:30 477 查看
需要在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);
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: