先吐槽下:最近几周压力老大了,前面我们三个ios开发人员花了一个多月开发的应用要移植到android上,由于应用相对比较复杂,有拖拽排序、离线下载、二维码扫描,而这次,另一个ios开发人员离职,剩下的另一个还没做个android,得由我带,于是,我估计了下开发时间,大约34天,我将计划发给领导,领导却说最多给我15天,我半天没说一个字:*&%¥#%**&⋯⋯&&

哎,出来混的,不管怎样,尽量吧。

这个开发,我们四张表要操作,相对于一般的移动应用,还是比较大的,故数据库实现肯定是整个开发的第一个和至关重要的一步,于是,我整理了下面这个demo。

其实网上有很多比较不错的orm移动开发框架,相对还是比较优秀,可以节省大把的开发时间,但我个人认为,现在这个还不是很稳定,而且,在效率上,我持保守态度,移动开发上,应相对的少用反射和抽象接口,而网络上的一些第三方的框架,却抓住这个大用特用,个人觉得,不大好,另外,采用android原生的数据库实现方案,还有个极大的好处是:很容易实现产品生态系统,这个是其他的orm所不易达到的。也即,可以轻而易举地实现我们的几个应用间的数据共享和交互,URI访问即可,从而形成一个生态圈的目的,具体的,就不多说了。

这个demo是一个完整的db操作,但只给出了一个实体的db实现,不过,足以:

程序结构图:

后面的所有db操作,都会被封装到DBManager中,也即,以后应用的db操作,只需通过DBManager进行交互接口,具体的看TestDBAct中实现:

1、抽象实体基类 BasicEntity.java:

package blockcheng.android.model;import java.io.Serializable;import org.json.JSONObject;import android.content.ContentValues;import android.database.Cursor;import android.os.Parcelable;import android.provider.BaseColumns;public abstract class BasicEntity implements BaseColumns,Serializable, Parcelable{private static final long serialVersionUID = 7169909425485915669L;protected String entityName;protected String entityId;protected long lastUpdateTime;public static final String sDEFAULTSORT = "  lastUpdateTime desc";public static final String sKEY_LASTUPDATETIMEADID = "lastUpdateTime";/** * demo methods * @param obj * @return */public static BasicEntity translateJson2Object(JSONObject obj){//TODO:this method must be override by subclass.return null;}public String getEntityName() {return entityName;}public void setEntityName(String entityName) {this.entityName = entityName;}public String getEntityId() {return entityId;}public void setEntityId(String entityId) {this.entityId = entityId;}public long getLastUpdateTime() {return lastUpdateTime;}public void setLastUpdateTime(long lastUpdateTime) {this.lastUpdateTime = lastUpdateTime;}public abstract ContentValues getContentValues();/** * demo method :should be copy by subclass * @param c * @return */public static BasicEntity fromCursor(Cursor c) {return null;}@Overridepublic String toString() {return "id=" + entityId  + ", name="+ entityName + ", lastUpdateTime=" + lastUpdateTime + "";}}

2、广告实体类AdvertisementEntity.java:

package blockcheng.android.model;import java.io.Serializable;import org.json.JSONObject;import android.content.ContentValues;import android.database.Cursor;import android.os.Parcel;public class AdvertisementEntity extends BasicEntity implements Serializable{private static final long serialVersionUID = 3045767248752772598L;/** * 广告图片路径 **/private String adPic;/** * 广告类型  1主题 2 单个商品(后可扩充,客户端可根据广告类型设定广告的点击状态) **/private int adType;/** * 广告对象地址(主题ID、单个商品ID或者其他) **/private String adTarget;//'广告位置:1.banner(后扩充位置)private int adPosition;private String data;/** * demo methods * @param obj * @return */public static AdvertisementEntity translateJson2Object(JSONObject obj){//TODO:implement it later.AdvertisementEntity aEntity = new AdvertisementEntity();return aEntity;}public String getAdPic() {return adPic;}public void setAdPic(String adPic) {this.adPic = adPic;}public int getAdType() {return adType;}public void setAdType(int adType) {this.adType = adType;}public String getAdTarget() {return adTarget;}public void setAdTarget(String adTarget) {this.adTarget = adTarget;}public int getAdPosition() {return adPosition;}public void setAdPosition(int adPosition) {this.adPosition = adPosition;}public String getData() {return data;}public void setData(String data) {this.data = data;}@Overridepublic int describeContents() {// TODO Auto-generated method stubreturn 0;}/******************************************************************//*********************Database config information********************//******************************************************************/public static final String sTABLE_NAME = "AdvertisementEntity";public static final String sKEY_ADID = "adId";public static final String sKEY_ADNAME = "adName";public static final String sKEY_ADTYPE = "adType";public static final String sKEY_ADPIC = "adPic";public static final String sKEY_ADTARGET = "adTarget";/* * 要查询的全部字段 */public  static String[] ADS_PROJECTION_ALL = new String[] {"adId","adName","lastUpdateTime","adType","adPic","adTarget",};@Overridepublic void writeToParcel(Parcel dest, int flags) {// TODO Auto-generated method stub}@Overridepublic ContentValues getContentValues() {// TODO Auto-generated method stubfinal ContentValues values = new ContentValues();values.put(sKEY_ADID, getEntityId());values.put(sKEY_ADNAME, getEntityName());values.put(sKEY_ADTYPE, adType);values.put(sKEY_ADPIC, adPic);values.put(sKEY_ADTARGET, adTarget);return values;}public static AdvertisementEntity fromCursor(Cursor c) {AdvertisementEntity aEntity = new AdvertisementEntity();aEntity.entityId = c.getString(c.getColumnIndexOrThrow(sKEY_ADID));aEntity.entityName = c.getString(c.getColumnIndexOrThrow(sKEY_ADNAME));aEntity.adPic = c.getString(c.getColumnIndexOrThrow(sKEY_ADTARGET));aEntity.adType = c.getInt(c.getColumnIndexOrThrow(sKEY_ADTYPE));aEntity.lastUpdateTime = c.getLong(c.getColumnIndexOrThrow(BasicEntity.sKEY_LASTUPDATETIMEADID));return aEntity;}@Overridepublic String toString() {return "AdvertisementEntity [" + super.toString()+ "adPic= "+ adPic + ", adType=" + adType+ ", adTarget=" + adTarget + ", adPosition=" + adPosition+ ", data=" + data + "]" + super.toString();}}
3、DB的一些常量配置 DBConfig.java:

package blockcheng.android.service.database;import android.net.Uri;public interface DBConfig {public static final String DATABASE_NAME = "blockchengDB";public static final int DATABASE_VERSION = 1;public static final String DB_TAG = "blockcheng";public static final String AUTHORITY = "blockcheng.android";// content urlpublic static final Uri CONTENT_URI_AdvertisementEntity = Uri.parse("content://" +AUTHORITY+"/AdvertisementEntity");//search valuepublic static final int sSEARCH = 10;public static final int sADVERTISEMENT  = 100;public static final int sADVERTISEMENT_ID  = 101;}
4、建表类DBHelper.java:

package blockcheng.android.service.database;import blockcheng.android.model.AdvertisementEntity;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;import android.util.Log;public class DBHelper extends SQLiteOpenHelper implements DBConfig{public DBHelper(Context context) {super(context, DBConfig.DATABASE_NAME, null, DBConfig.DATABASE_VERSION);}@Overridepublic void onCreate(SQLiteDatabase db) {// TODO Auto-generated method stubStringBuffer createAdSql = new StringBuffer("CREATE TABLE'");createAdSql.append(AdvertisementEntity.sTABLE_NAME);createAdSql.append( "'('adId'  TEXT NOT NULL," );createAdSql.append( "'adName'  TEXT,");createAdSql.append("'lastUpdateTime'  real DEFAULT 0,");createAdSql.append("'adType'  INTEGER,");createAdSql.append("'adPic'  TEXT,");createAdSql.append( "'adTarget'  TEXT,");createAdSql.append( "PRIMARY KEY ('adId')" );createAdSql.append( ");");;Log.i(DBConfig.DB_TAG, "createAdSql::"+createAdSql.toString());db.execSQL(createAdSql.toString());String createIndexSql_0 = "CREATE INDEX 'id' ON '" +AdvertisementEntity.sTABLE_NAME +"' ('adId' ASC);";db.execSQL(createIndexSql_0);}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {// TODO Auto-generated method stubLog.w(DBConfig.DB_TAG, "Upgrading database from version " + oldVersion+ " to " + newVersion + ", which will destroy all old data");db.execSQL("DROP TABLE IF EXISTS " +AdvertisementEntity.sTABLE_NAME);onCreate(db);}}
5、contentProvider实现类DemoContentProvider.java:

package blockcheng.android.service.database;import java.util.HashMap;import blockcheng.android.model.AdvertisementEntity;import blockcheng.android.model.BasicEntity;import android.app.SearchManager;import android.content.ContentProvider;import android.content.ContentUris;import android.content.ContentValues;import android.content.UriMatcher;import android.database.Cursor;import android.database.SQLException;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;import android.database.sqlite.SQLiteQueryBuilder;import android.net.Uri;import android.text.TextUtils;import android.util.Log;public class DemoContentProvider extends ContentProvider {private SQLiteOpenHelper dbHelper;private static final UriMatcher URI_MATCHER;static {//TODO 需要整合下面的地址:URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);URI_MATCHER.addURI(DBConfig.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY,DBConfig.sSEARCH);URI_MATCHER.addURI(DBConfig.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY+ "/*", DBConfig.sSEARCH);//advertisement uri configURI_MATCHER.addURI(DBConfig.AUTHORITY, AdvertisementEntity.sTABLE_NAME, DBConfig.sADVERTISEMENT);URI_MATCHER.addURI(DBConfig.AUTHORITY, AdvertisementEntity.sTABLE_NAME+"/*", DBConfig.sADVERTISEMENT_ID);}// TODO: need more investigate.private static final HashMap<String, String> SUGGESTION_PROJECTION_MAP;static {SUGGESTION_PROJECTION_MAP = new HashMap<String, String>();SUGGESTION_PROJECTION_MAP.put(SearchManager.SUGGEST_COLUMN_TEXT_1,"topicName " + " AS " + SearchManager.SUGGEST_COLUMN_TEXT_1);SUGGESTION_PROJECTION_MAP.put(SearchManager.SUGGEST_COLUMN_TEXT_2,"goodName " + " AS " + SearchManager.SUGGEST_COLUMN_TEXT_2);SUGGESTION_PROJECTION_MAP.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID, AdvertisementEntity._ID + " AS "+ SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID);SUGGESTION_PROJECTION_MAP.put(AdvertisementEntity._ID, AdvertisementEntity._ID);}@Overridepublic boolean onCreate() {// TODO Auto-generated method stubdbHelper = new DBHelper(getContext());return true;}// TODO: update the manifest accordingly.public String getType(Uri uri) {switch (URI_MATCHER.match(uri)) {case DBConfig.sADVERTISEMENT:case DBConfig.sADVERTISEMENT_ID:return "vnd.android.cursor.dir/" + DBConfig.AUTHORITY + "."+ AdvertisementEntity.sTABLE_NAME;default:throw new IllegalArgumentException("Unknown URI " + uri);}}@Overridepublic Uri insert(Uri uri, ContentValues initialValues) {// TODO Auto-generated method stubLog.i(DBConfig.DB_TAG, "insert::"+uri.toString());ContentValues values;SQLiteDatabase db = dbHelper.getWritableDatabase();switch(URI_MATCHER.match(uri)){case DBConfig.sADVERTISEMENT:if (initialValues != null) {values = new ContentValues(initialValues);values.put(BasicEntity.sKEY_LASTUPDATETIMEADID, System.currentTimeMillis());} else {values = new ContentValues();}final long rowId = db.insert(AdvertisementEntity.sTABLE_NAME, AdvertisementEntity.sKEY_ADPIC, values);if (rowId > 0) {Uri insertUri = ContentUris.withAppendedId(DBConfig.CONTENT_URI_AdvertisementEntity, rowId);getContext().getContentResolver().notifyChange(uri, null);return insertUri;}throw new SQLException("Failed to insert row into " + uri);default:throw new IllegalArgumentException("Unknown URI " + uri);}}@Overridepublic int delete(Uri uri, String selection, String[] selectionArgs) {// TODO Auto-generated method stubLog.i(DBConfig.DB_TAG, "delete::"+uri.toString());SQLiteDatabase db = dbHelper.getWritableDatabase();int count;switch (URI_MATCHER.match(uri)) {case DBConfig.sADVERTISEMENT:count = db.delete(AdvertisementEntity.sTABLE_NAME, selection, selectionArgs);break;case DBConfig.sADVERTISEMENT_ID:String adId = uri.getPathSegments().get(1);count = db.delete(AdvertisementEntity.sTABLE_NAME,AdvertisementEntity.sKEY_ADID+ "="+ adId+ (!TextUtils.isEmpty(selection) ? " AND ("+ selection + ')' : ""), selectionArgs);break;default:throw new IllegalArgumentException("   Unknown URI " + uri);}getContext().getContentResolver().notifyChange(uri, null);return count;}@Overridepublic int update(Uri uri, ContentValues values, String where,String[] whereArgs) {Log.i(DBConfig.DB_TAG, "update::"+uri.toString() +": value="+values.toString());SQLiteDatabase db = dbHelper.getWritableDatabase();int count = -1;switch (URI_MATCHER.match(uri)) {case DBConfig.sADVERTISEMENT_ID:Log.i(DBConfig.DB_TAG, "update::sADVERTISEMENT_ID");String adverstisementId = uri.getPathSegments().get(1);count = db.update(AdvertisementEntity.sTABLE_NAME,values,AdvertisementEntity.sKEY_ADID+ "='"+ adverstisementId+ "'"+ (!TextUtils.isEmpty(where) ? " AND (" + where+ ')' : ""), whereArgs);break;case DBConfig.sADVERTISEMENT:Log.i(DBConfig.DB_TAG, "update::sADVERTISEMENT");String aidString = values.getAsString(AdvertisementEntity.sKEY_ADID);values.remove(AdvertisementEntity.sKEY_ADID);count = db.update(AdvertisementEntity.sTABLE_NAME,values,AdvertisementEntity.sKEY_ADID+ "='"+ aidString+ "'"+ (!TextUtils.isEmpty(where) ? " AND (" + where+ ')' : ""), whereArgs);break;default:throw new IllegalArgumentException("Unknown URI " + uri);}return count;}@Overridepublic Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {Log.i(DBConfig.DB_TAG, "query::"+uri.toString());SQLiteQueryBuilder qb = new SQLiteQueryBuilder();String orderBy;switch (URI_MATCHER.match(uri)) {case DBConfig.sADVERTISEMENT:qb.setTables(AdvertisementEntity.sTABLE_NAME);break;case DBConfig.sADVERTISEMENT_ID:qb.setTables(AdvertisementEntity.sTABLE_NAME);qb.appendWhere(AdvertisementEntity.sKEY_ADID + "='"+ uri.getPathSegments().get(1) +"'");break;default:throw new IllegalArgumentException("Unknown URI " + uri);}// If no sort order is specified use the defaultif (TextUtils.isEmpty(sortOrder)) {orderBy = BasicEntity.sDEFAULTSORT;} else {orderBy = sortOrder;}SQLiteDatabase db = dbHelper.getReadableDatabase();Cursor c = qb.query(db, projection, selection, selectionArgs, null,null, orderBy);c.setNotificationUri(getContext().getContentResolver(), uri);return c;}}
测试界面布局:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    android:padding="15dip" >    <EditText        android:id="@+id/et_condition"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:ems="10"        android:text="1"         >        <requestFocus />    </EditText>    <Button        android:id="@+id/db_button1"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:clickable="true"        android:onClick="handleEvent"        android:text="add " />    <Button        android:id="@+id/db_button2"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:clickable="true"        android:onClick="handleEvent"        android:text="delete" />    <Button        android:id="@+id/db_button3"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:clickable="true"        android:onClick="handleEvent"        android:text="update" />    <Button        android:id="@+id/db_button4"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:clickable="true"        android:onClick="handleEvent"        android:text="query" /></LinearLayout>
测试类TestDBAct.java:

package cn.helloclq.android.activity;import blockcheng.android.R;import blockcheng.android.model.AdvertisementEntity;import blockcheng.android.service.database.DBManager;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.widget.EditText;public class TestDBAct extends Activity {EditText etCondition;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.dbtest_activity);etCondition = (EditText)findViewById(R.id.et_condition);}public void handleEvent(View view){String adIdString = etCondition.getText().toString();AdvertisementEntity aEntity = new AdvertisementEntity();aEntity.setEntityId(adIdString);aEntity.setEntityName("ad"+adIdString);aEntity.setAdType(Integer.parseInt(adIdString));aEntity.setAdTarget(adIdString);//public WebTaskTest(Context context, boolean showDialog,//boolean cancelAble, String dialogLoadingStr,//WebRequestCallbackInfc cb)switch(view.getId()) {case R.id.db_button1://add DBManager.getInstance().addAdvertiseMent(getContentResolver(), aEntity);break;case R.id.db_button2://deleteDBManager.getInstance().deleteAdvertiseMentById(getContentResolver(), adIdString);break;case R.id.db_button3://updateaEntity.setEntityName("ad update"+adIdString);DBManager.getInstance().updateAdervertiseEntity(getContentResolver(), aEntity);break;case R.id.db_button4://queryDBManager.getInstance().querAllAdvertisementEntity(getContentResolver());break;}}}
运行效果图:


运行日志:

08-07 10:52:50.305: I/blockcheng(458): query::content://blockcheng.android/AdvertisementEntity/108-07 10:52:50.415: I/blockcheng(458): createAdSql::CREATE TABLE'AdvertisementEntity'('adId'  TEXT NOT NULL,'adName'  TEXT,'lastUpdateTime'  real DEFAULT 0,'adType'  INTEGER,'adPic'  TEXT,'adTarget'  TEXT,PRIMARY KEY ('adId'));08-07 10:52:50.434: I/blockcheng(458): insert::content://blockcheng.android/AdvertisementEntity08-07 10:52:50.455: I/blockcheng(458): addAdvertiseMent::AdvertisementEntity [id=1, name=ad1, lastUpdateTime=0adPic= null, adType=1, adTarget=1, adPosition=0, data=null]id=1, name=ad1, lastUpdateTime=008-07 10:53:08.567: I/blockcheng(458): query::content://blockcheng.android/AdvertisementEntity08-07 10:53:08.575: I/blockcheng(458): ad:AdvertisementEntity [id=1, name=ad1, lastUpdateTime=1375843970443adPic= 1, adType=1, adTarget=null, adPosition=0, data=null]id=1, name=ad1, lastUpdateTime=137584397044308-07 10:53:15.585: I/blockcheng(458): update::content://blockcheng.android/AdvertisementEntity: value=adTarget=1 adType=1 adPic=null adId=1 lastUpdateTime=1375843995585 adName=ad update108-07 10:53:15.585: I/blockcheng(458): update::sADVERTISEMENT08-07 10:53:17.355: I/blockcheng(458): delete::content://blockcheng.android/AdvertisementEntity/108-07 10:53:18.835: I/blockcheng(458): query::content://blockcheng.android/AdvertisementEntity

麻雀虽小,五脏俱全,加多张表的话,也是如此的,就这样吧,都写了好一会儿了。

补充manifest文件:

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="blockcheng.android"    android:versionCode="1"    android:versionName="1.0" >    <uses-sdk        android:minSdkVersion="4"        android:targetSdkVersion="17" />    <uses-permission android:name="android.permission.RECEIVE_USER_PRESENT" />    <uses-permission android:name="android.permission.INTERNET" />    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>      <uses-permission android:name="android.permission.READ_PHONE_STATE"/><uses-permission android:name="android.permission.READ_LOGS"></uses-permission>    <application        android:allowBackup="true"        android:label="@string/app_name"         >         <activity            android:name="cn.helloclq.android.activity.TestAct"            android:label="@string/app_name"            android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation"            android:screenOrientation="portrait" >        </activity>         <activity            android:name="cn.helloclq.android.activity.TestDBAct"            android:label="@string/app_name"            android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation"            android:screenOrientation="portrait" >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>        <providerandroid:exported="false"            android:authorities="blockcheng.android"            android:name="blockcheng.android.service.database.DemoContentProvider" />            </application></manifest>

更多相关文章

  1. Android逆袭!开发者收入与iOS差距正在缩小
  2. Android程序开发学习笔记系列――基础篇(附源码)
  3. Android(安卓)NDK开发:打包so库及jar包供他人使用
  4. Android(安卓)UI小贴士
  5. Lottie动画在Android和Ios开发中的应用——Android篇
  6. Android应用开发之(你必须知道的8个Android开发工具)
  7. 安卓开发笔记——从0到1
  8. 从Titlebar到Actionbar再到Toolbar
  9. 你觉得Android又凉了?那带你看下2020年Android开发的前景如何?

随机推荐

  1. 如何区分MySQL的innodb_flush_log_at_trx
  2. MySQL 日志相关知识总结
  3. Mysql桌面工具之SQLyog资源及激活使用方
  4. Mysql避免重复插入数据的4种方式
  5. MySQL覆盖索引的使用示例
  6. 如何在mysql进行查询缓存及失败的解决方
  7. mysql 实现添加时间自动添加更新时间自动
  8. mysql 使用B+树索引有哪些优势
  9. MySQL 加锁控制并发的方法
  10. MySQL 8.0.23中复制架构从节点自动故障转