MainActivity
public class MainActivity extends ListActivity {private TextView tv_info;private EditText editText;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);List<String> mData = new ArrayList<String>(Arrays.asList("获取所有数据", "插入", "删除", "查找", "更新"));ListAdapter mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mData);editText = new EditText(this);editText.setHint("请输入要增删改查数据的Name");editText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);editText.setPadding(0, 30, 0, 30);editText.setGravity(Gravity.CENTER);getListView().addFooterView(editText);tv_info = new TextView(this);// 将内容显示在TextView中tv_info.setTextColor(Color.BLUE);tv_info.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);tv_info.setPadding(20, 10, 20, 10);getListView().addFooterView(tv_info);setListAdapter(mAdapter);}@Overrideprotected void onListItemClick(ListView l, View v, int position, long id) {PersonDao2 dao = new PersonDao2(this);String content = editText.getText().toString().trim();switch (position) {case 0:ArrayList<Person> list = dao.findAll();tv_info.setText(list.toString());break;case 1:tv_info.setText(dao.add(content, new Random().nextInt(10) + "") + "");break;case 2:tv_info.setText(dao.delete(content) + "");break;case 3:tv_info.setText(dao.find(content) + "");break;case 4:tv_info.setText(dao.update(content, "呵呵") + "");break;}}}
ContentProvider
/** 提供一些public的方法,让其他应用访问自己私有的文件。我们很少会自己来定义ContentProvider,因为我们很多时候都不希望自己应用的数据暴露给*/public class MyContentProvider extends ContentProvider {private SQLiteDatabase db;private static final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);// 参数表示匹配不成功时的返回值,这里为-1// 主机名称public static final String authority = "com.bqt.contentprovider.person";// 定义一些静态全局常量public static final int QUERY = 0;public static final int INSERT = 1;public static final int DELETE = 2;public static final int UPDATE = 3;// 给匹配器添加一些【匹配规则】,放在静态代码块中的作用:随类加载而优先加载,且只加载一次static {// 参数: authority 主机名 ,path 路径名, code 匹配码,匹配成功时的返回值matcher.addURI(authority, "query", QUERY);// 可以使用限定符*和#。* may be used as a wild card for any text, and # may be used as a wild card for numbers.matcher.addURI(authority, "insert", INSERT);//即Uri格式为【content://com.bqt.contentprovider.person/insert】matcher.addURI(authority, "delete", DELETE);matcher.addURI(authority, "update", UPDATE);}@Overridepublic boolean onCreate() {MySQLiteOpenHelper helper = new MySQLiteOpenHelper(getContext());db = helper.getWritableDatabase();return true;//true if the provider was successfully loaded, false otherwise}@Overridepublic Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {if (matcher.match(uri) == QUERY) {//表名,要查询的列名数组,选择条件,选择条件对应的参数,分组,分组条件,排序Cursor cursor = db.query(MySQLiteOpenHelper.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);return cursor;//Returns:A Cursor object, which is positioned before the first entry.} else return null;}@Overridepublic int delete(Uri uri, String selection, String[] selectionArgs) {if (matcher.match(uri) == DELETE) {return db.delete(MySQLiteOpenHelper.TABLE_NAME, selection, selectionArgs);//Returns: the number of rows affected if a whereClause is passed in, 0 otherwise. To remove all rows and get a count pass "1" as the whereClause} else throw new IllegalArgumentException("非法uri");}@Overridepublic Uri insert(Uri uri, ContentValues values) {if (matcher.match(uri) == INSERT) {long id = db.insert(MySQLiteOpenHelper.TABLE_NAME, null, values);//Returns: the row ID of the newly inserted row, or -1 if an error occurredreturn ContentUris.withAppendedId(uri, id);//a new URI with the given ID appended to the end of the path} else throw new IllegalArgumentException("非法uri");}@Overridepublic int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {if (matcher.match(uri) == UPDATE) {return db.update(MySQLiteOpenHelper.TABLE_NAME, values, selection, selectionArgs);//Returns:the number of rows affected} else throw new IllegalArgumentException("非法uri");}@Override/**MIME类型*/public String getType(Uri uri) {return "";//a MIME type string, or null if there is no type.}}
SQLiteOpenHelper
/** 数据库【创建】或【打开】辅助类 */public class MySQLiteOpenHelper extends SQLiteOpenHelper {public static final String DB_NAME = "person.db";public static int DB_VERSION = 2;//所有的表名及SQL語句都放到一個單獨的類中,这里图方便放到了这里public static final String TABLE_NAME = "person";public static final String CREATE_TABLE = "create table if not exists " + TABLE_NAME + " (id integer primary key autoincrement," + "name varchar,"+ "number varchar)";public MySQLiteOpenHelper(Context context) {super(context, DB_NAME, null, DB_VERSION);}@Overridepublic void onCreate(SQLiteDatabase db) {db.execSQL(CREATE_TABLE);// db.execSQL(DBConstants.CREATE_PHOTO_TABLE);// db.execSQL(DBConstants.CREATE_DOWNLOAD_TABLE);// db.execSQL(DBConstants.CREATE_USER_TABLE);// db.execSQL(DBConstants.CREATE_GIFTS_TABLE);// db.execSQL(DBConstants.CREATE_ZIP_TABLE);}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {db.execSQL("drop table if exists " + TABLE_NAME);// db.execSQL("drop table if exists " + DBConstants.DB_PHOTO_TABLE);// db.execSQL("drop table if exists " + DBConstants.DB_DOWNLOAD_TABLE);// db.execSQL("drop table if exists " + DBConstants.DB_USER_TABLE);// db.execSQL("drop table if exists " + DBConstants.DB_GIFTS_TABLE);// db.execSQL("drop table if exists " + DBConstants.DB_ZIP_TABLE);onCreate(db);}}
DAO1
/** DAO(Data Access Object) 数据访问对象,是一个面向对象的数据库接口,夹在业务逻辑与数据库资源中间。相当于是数据库的【工具类】*/public class PersonDao {private MySQLiteOpenHelper helper;public PersonDao(Context context) {helper = new MySQLiteOpenHelper(context);}public ArrayList<Person> findAll() {SQLiteDatabase db = helper.getWritableDatabase();ArrayList<Person> persons = new ArrayList<Person>();Cursor cursor = db.rawQuery("select * from person", null);//Returns:A Cursor object, which is positioned before the first entry.while (cursor.moveToNext()) {int id = cursor.getInt(cursor.getColumnIndex("id"));//获取指定列的值String name = cursor.getString(cursor.getColumnIndex("name"));String number = cursor.getString(cursor.getColumnIndex("number"));Person p = new Person(id, name, number);persons.add(p);}cursor.close();db.close();return persons;}public boolean find(String name) {SQLiteDatabase db = helper.getWritableDatabase();Cursor cursor = db.rawQuery("select * from person where name=?", new String[] { name });boolean result = cursor.moveToNext();//结果集最初始时是指向表的最前面的,moveToNext时指向的才是【第一条】数据cursor.close();db.close();return result;}public void add(String name, String number) {SQLiteDatabase db = helper.getWritableDatabase();db.execSQL("insert into person(name,number) values(?,?)", new Object[] { name, number });//Returns: the row ID of the newly inserted row, or -1 if an error occurreddb.close();}public void update(String name, String newNumber) {SQLiteDatabase db = helper.getWritableDatabase();db.execSQL("update person set number=? where name=?", new Object[] { newNumber, name });//Returns:the number of rows affecteddb.close();}public void delete(String name) {SQLiteDatabase db = helper.getWritableDatabase();db.execSQL("delete from person where name=?", new Object[] { name });//Returns: the number of rows affected if a whereClause is passed in, 0 otherwise. To remove all rows and get a count pass "1" as the whereClausedb.close();}}
DAO2
public class PersonDao2 {private MySQLiteOpenHelper helper;public PersonDao2(Context context) {helper = new MySQLiteOpenHelper(context);}public ArrayList<Person> findAll() {SQLiteDatabase db = helper.getWritableDatabase();//数据库不作为成员变量的原因:1、使用完要及时关闭;2、关闭后必须重新通过helper打开。//java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/data/com.bqt.contentprovider/databases/person.dbArrayList<Person> persons = new ArrayList<Person>();Cursor cursor = db.query("person", new String[] { "name", "number", "id" }, null, null, null, null, null);while (cursor.moveToNext()) {int id = cursor.getInt(cursor.getColumnIndex("id"));String name = cursor.getString(cursor.getColumnIndex("name"));String number = cursor.getString(cursor.getColumnIndex("number"));persons.add(new Person(id, name, number));}cursor.close();db.close();return persons;}public boolean find(String name) {SQLiteDatabase db = helper.getWritableDatabase();Cursor cursor = db.query("person", null, "name=?", new String[] { name }, null, null, null);//要查询的表名,要查询的列名的数组(null代表所有列),选择条件(即WHERE语句,可以使用占位符 String[])//选择条件中占位符的值(数组类型),分组语句(groupBy),having条件语句,排序语句(orderBy)boolean result = cursor.moveToNext();//Returns:whether the move succeeded.cursor.close();db.close();return result;}public long add(String name, String number) {SQLiteDatabase db = helper.getWritableDatabase();ContentValues values = new ContentValues();// 其实是一个map集合,里面保存的是每条记录的"键值对"信息values.put("name", name);values.put("number", number);long id = db.insert("person", null, values);//返回新添加行的行号db.close();return id;}public int update(String name, String newNumber) {SQLiteDatabase db = helper.getWritableDatabase();ContentValues values = new ContentValues();values.put("number", newNumber);int number = db.update("person", values, "name=?", new String[] { name });// 返回修改的行的【个数】db.close();return number;}public int delete(String name) {SQLiteDatabase db = helper.getWritableDatabase();int number = db.delete("person", "name=?", new String[] { name });//返回删除行的行号db.close();return number;}}
Bean
public class Person {public int id;public String name;public String number;public Person(int id, String name, String number) {this.id = id;this.name = name;this.number = number;}@Overridepublic String toString() {return "id=" + id + ", name=" + name + ", number=" + number + "\n";}}
数据库表及SQL语句常量
/** 所有的数据库的表名及SQL語句都放到这個單獨的類中 */public class DBConstants {/***************************************************** 上传图片表****************************************************/public static final String DB_PHOTO_TABLE = "upload_photo";public static final String CREATE_PHOTO_TABLE = "create table if not exists "+DB_PHOTO_TABLE+" (id integer primary key autoincrement," +"phAlbtmId varchar,"+"photoUrl varchar," +"uploadState varchar)";public static final String INSERT_INTO_TAB_PHOTO = "INSERT INTO "+ DB_PHOTO_TABLE +" VALUES(null,?,?,?)";/***************************************************** 下载表****************************************************/public static final String DB_DOWNLOAD_TABLE = "download_table";public static final String CREATE_DOWNLOAD_TABLE = "create table " + DB_DOWNLOAD_TABLE +" (_id integer primary key autoincrement, " +"gameId integer, " +"gameName text, " +"gamePackage text, " +"status integer, " +"totalSize integer, " +"hasRead integer, " +"downloadUrl text, " +"filePath text, " +"imgUrl text" +")";public static final String INSERT_INTO_TAB_DOWNLOAD = "INSERT INTO "+ DB_DOWNLOAD_TABLE +" VALUES(null,?,?,?,?,?,?,?,?,?)";/***************************************************** 用户账号表****************************************************/public static final String DB_USER_TABLE = "user_table";public static final String CREATE_USER_TABLE = "CREATE TABLE IF NOT EXISTS "+ DB_USER_TABLE+ "(id INTEGER PRIMARY KEY AUTOINCREMENT,"+ " userId text,"+ " userAccount text,"+ " userPwd text,"+ " avatarUrl text,"+ "chargeStatus INTEGER,"+ "showDialogState INTEGER)";public static final String INSERT_INTO_TAB_USER = "INSERT INTO "+ DB_USER_TABLE +" VALUES(null,?,?,?,?,?,?)";/************************************************************** 座驾信息记录表start*************************************************************/public static final String DB_CAR_DOWNLOAD_RECORD = "car_download_record";public static final String DB_CAR_TABLE = "user_car_table";public static final String CREATE_CAR_TABLE = "CREATE TABLE IF NOT EXISTS "+ DB_CAR_TABLE+ "(id INTEGER PRIMARY KEY AUTOINCREMENT,"+ "carId varchar,"+ "carType varchar,"+ "carName varchar,"+"carSound,"+ "carPrice varchar,"+"carUrl varchar,"+"carIsShock varchar)";public static final String INSERT_INTO_TAB_CAR = "INSERT INTO "+ DB_CAR_TABLE +" VALUES(null,?,?,?,?,?,?,?)";/************************************************************** 座驾信息记录表end*************************************************************//***************************************************** zip下载表****************************************************/public static final String DB_ZIP_TABLE = "zip_downLoad_table";public static final String CREATE_ZIP_TABLE = "CREATE TABLE IF NOT EXISTS "+ DB_ZIP_TABLE+ "(id INTEGER PRIMARY KEY AUTOINCREMENT,"+ " curSize INT8,"+ " totalSize INT8,"+ " downLoadUrl text,"+ " zipName text,"+ "versionCode INTEGER)";public static final String INSERT_INTO_TAB_ZIP = "INSERT INTO "+ DB_ZIP_TABLE +" VALUES(null,?,?,?,?,?)";/***************************************************** 记录礼物信息表****************************************************/public static final String DB_GIFTS_TABLE = "gifts_table";public static final String CREATE_GIFTS_TABLE = "CREATE TABLE IF NOT EXISTS "+ DB_GIFTS_TABLE+ "(id INTEGER PRIMARY KEY AUTOINCREMENT,"+ "versionCode INTEGER,"+ "giftType INTEGER,"+ "giftId INTEGER,"+ "giftName text,"+ "giftPrice INTEGER,"+ "giftImgUrl text,"+ "giftAnimIntervals text,"+ "giftAnimCount INTEGER,"+ "animType INTEGER,"+ "animValue INTEGER,"+ "animAudio text)";public static final String INSERT_INTO_TAB_GIFTS = "INSERT INTO "+ DB_GIFTS_TABLE +" VALUES(null,?,?,?,?,?,?,?,?,?,?,?)";}
AndroidTestCase
/** 测试类。使用方法:在【outline】中对要测试的【方法右键】--> Run As --> Android JUnit Test */public class MyAndroidTestCase extends AndroidTestCase {Context context = getContext();//不能把PersonSQLiteOpenHelper或PersonDao抽出为对象的成员public SQLiteDatabase testGetDB() {return new MySQLiteOpenHelper(getContext()).getWritableDatabase();}public void testAdd() {Log.i("bqt", "" + (context == null));//true。PersonDao2不作为成员,因为成员变量初始化时getContext返回的还是null。PersonDao2 dao2 = new PersonDao2(getContext());for (int i = 0; i < 10; i++) {dao2.add("包青天" + i, "" + i);dao2.add("白乾涛" + i, "" + i);}}public void testFind() {assertEquals(true, new PersonDao2(getContext()).find("包青天1"));}public void testUpdate() {new PersonDao2(getContext()).update("包青天4", "包青天44444");}public void testDelete() {new PersonDao2(getContext()).delete("包青天5");}public void testFindAll() {ArrayList<Person> persons = new PersonDao2(getContext()).findAll();for (Person person : persons) {System.out.println(person);}}// 测试事务。当版本号增加时,测试是否成功public void testTransaction() {MySQLiteOpenHelper helper = new MySQLiteOpenHelper(getContext());SQLiteDatabase db = helper.getWritableDatabase();db.beginTransaction();// 开启事务try {db.execSQL("update person set account = account + 1000 where name=?", new Object[] { "包青天6" });// int i = 1 / 0;//执行到这里后抛出一个异常,后面的没有执行到,事务失败db.execSQL("update person set account = account - 1000 where name=?", new Object[] { "包青天7" });db.setTransactionSuccessful();//若执行到这里,证明已成功执行上面的SQL语句,所以"标记"事务已成功} catch (Exception e) {e.printStackTrace();} finally {db.endTransaction();// 结束事务}}}
清单文件
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.bqt.contentprovider"android:versionCode="1"android:versionName="1.0" ><uses-sdkandroid:minSdkVersion="8"android:targetSdkVersion="21" /><!-- 增加instrumentation标签,并指定包名 --><instrumentationandroid:name="android.test.InstrumentationTestRunner"android:targetPackage="com.bqt.contentprovider" /><!-- 内容提供者定义的权限。android:protectionLevel 代表了权限等级normal:低风险权限,只要申请了就可以使用(在AndroidManifest.xml中添加<uses-permission>标签),安装时不需要用户确认;dangerous:高风险权限,安装时需要用户的确认才可使用;signature:只有当申请权限的应用程序的数字签名与声明此权限的应用程序的数字签名相同时(如果是申请系统权限,则需要与系统签名相同),才能将权限授给它;signatureOrSystem:签名相同,或者申请权限的应用为系统应用(在system image中)。 --><permissionandroid:name="com.bqt.permission"android:protectionLevel="normal" /><applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><!-- 增加uses-library标签 --><uses-library android:name="android.test.runner" /><activityandroid:name="com.bqt.contentprovider.MainActivity"android:label="@string/app_name" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><!-- 属性依次为:全限定类名,用于匹配的URI,是否共享数据,访问时需要具备的权限 --><providerandroid:name=".MyContentProvider"android:authorities="com.bqt.contentprovider.person"android:exported="true"android:permission="com.bqt.permission" /></application></manifest>