Android ContentProvider使用样例
2015-08-24 15:30
477 查看
需要在AndroidMainfest.xml中添加组件provider:
在ContentProvider维护着一个SqliteOpenHelper类,随应用启动时调用onCreate()方法一次来进行初始化,之后不再调用该方法。onCreate()方法中实例化Sqlite数据库时传入数据库版本号,当新的版本号大于旧的版本号时,数据库将会调用onUpgrade()方法进行升级,里面实现自己的升级逻辑,通常是drop表再重建表。
//ListFragment 结合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); } }
相关文章推荐
- Android自定义Dialog
- android 学习 广播机制的使用
- Android 自定义控件 优雅实现元素间的分割线 (支持3.0以下)
- Android平台aac谷歌软解框架和流程、解码库学习
- Android 通知栏Notification的整合 全面学习 (一个DEMO让你完全了解它)
- Android时区及语言代码
- android: AAC文件解析
- Android欢迎界面的创建方法
- Android Job框架:Trigger
- Android ELF文件格式
- 百度地图Android SDK报错:Error inflating class com.baidu.mapapi.map.MapView
- Android 监听屏幕锁屏,用户解锁
- GitHub 优秀的 Android 开源项目 - listview相关
- 关于Android最佳性能实践——分析内存的使用情况学习笔记
- Design Support Library 轻松打造酷炫Android5.0风格
- Android应用程序组件(五)
- Android倒计时的实现代码
- Android中dp,px,sp概念梳理以及如何做到屏幕适配
- Android开发之AlarmManager的用法详解
- Android:禁止ScrollView在子控件的布局改变时自动滚动的的方法