一、杂谈

本文结构:
1、杂谈。
2、上代码,阉割版的demo。
3、总结一下封装的思想。

本文旨在回味几年前的技术,同时对封装功底进行夯实。毕竟最近一段时间都没有写代码。封装的思路,要清晰,明白,明白的是这个思路,这个想法,而不是照抄。

好久没更新CSDN了,因为最近有点懵懵的,周末也不知道在干啥,没打错字,不是萌萌的,是真懵懵的。

之前找工作阶段的时候,面试过一家公司,叫xx拼车,名字也是蹭滴滴的热度,整了个滴答。O(∩_∩)O哈哈~。人事是个挺漂亮的年轻小姐姐,所以说这家公司不错。

面试这家公司的时候,原定是组长面我,因为我和另一个人一起来的,他先答完了题(by phone),所以经理去面他了,然后找了个人来面我。这个人是个员工,一个有强烈竞争感的员工。

问了我上家公司采用的一些技术,其中涉及到数据库部分的,我答,用的是ContentProvider。接下来他的反应令我懵逼了。

它以一种嘲笑的语气,半笑着问我,ContentProvider不是用来数据共享的吗,怎么能操作数据库呢?

我(⊙o⊙)…了一下。然后回答,ContentProvider数据共享的时候,不也是操作了数据库吗?那么他一定可以操作自己的数据库啊。

他很执着的说,ContentProvider是用来共享数据的,不是操作数据的啊。

我(⊙o⊙)…了一下。然后说可以的,是可以的,我可以给你说说。

然后他又重复的说了上一句,ContentProvider是用来共享数据的,不是操作数据的啊。

我心里想,尼玛,这么一根筋吗,你就当做共享了自己的数据行不?我说,ContentProvider可以共享,也可以操作数据库,插入查找删除啥的都有,都可以的。

我刚想给他详细的说一下,代码怎么实现,但这时候突然间,他好像魔怔了一般,选择性失聪并且复读。一直在重复着那一句话,“ContentProvider怎么操作数据库,ContentProvider怎么操作数据库,ContentProvider怎么操作数据库”,令我无从插嘴。恨自己交流能力太弱。

这时候我想到了,在山的那边,雪的那边,有一个男精灵,他名字叫欧阳锋,他执着又聪明。

一个练功练魔怔了的男人,他俩此时的状态居然像极,因为对于心法中有地方想不明白,就走火入魔了。

最后我还是简单说了一下ContentProvider操作数据的过程,然后我们进行了下一话题。

面试完毕之后,我觉得我很有戏,因为我说到了一个他不会的知识点,虐了一下面试官,一般这种情况,面试官都会录取你的。

故事的结局很意外。他们说我们在考虑一下之后,就一直考虑到了现在,大概已经有三四个月了吧,而我早就入职别的公司了。

我到现在还挺愧疚的,我要不要告诉他们我已经入职了啊,要不然他们还在考虑可怎么办啊。

哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈。


之前公司数据库操作用的SQLiteOpenHelper和ContentProvider,现在入职的公司,是OrmLite和ContentProvider一起用的。是的都是比较老的框架。

毕竟这两个项目,一个六年了,一个N(N<=4)年了。
(6年前的Android项目你见过吗?古董)

简单说一下吧,ContentProvider操作数据库的好处,那就是定义统一的接口,以接口的形式访问表啥的。不管你表结构怎么改,我这不用改,挺方便是吧。但是,据我个人所知,现在类似与GreenDao这种框架的流行,对数据操作的优化以及编程时也不用自己写多少,所以ContentProvider没有多少公司再用了。

有用的,要么是项目很久都没有被重构,要么是做项目的程序员所掌握的技能很久都没有被重构。

牛逼吹完了,上上代码,这里以SQLiteOpenHelper为例,回顾一下几年前主流的数据库操作。(老程序员可以哭了,现在还有菜鸟学你们之前的用法)

卧槽,写到这发现有点不对啊。别人都是学新的技术,新技术一出,就像疯狗一样去学,生怕屎凉了,哦不,是新技术过时了(没办法,Android技术更新太快),为啥我越学越往回学了啊?

二、SQLiteOpenHelper

SQLiteOpenHelper略。

打我啊。

三、BaseContentProvider

先写个ContentProvider,实现了先。内部定义SQLIteOpenHelper。

/*** ContentProvider基础类.**/
public abstract class BaseContentProvider extends ContentProvider {//略一堆常量private SQLiteOpenHelper mOpenHelper;/*** 子类应该通过本方法设置SQLiteOpenHelper** @param helper*/public void setSQLiteOpenHelper(SQLiteOpenHelper helper) {mOpenHelper = helper;}//未完。。。。。。

然后重写COntentProvider中的一些方法,例如增删改查的方法。这里用到一个类,SqlArguments ,这个是自己封装的,Android SDK没有,别问我你怎么找不到。
就是根据传来的uri以及其他参数,来返回不同的参数。。。对参数的一个封装,就是查询时需要的表名,以及其他条件。

重写getType:

//就是根据uri返回个表名@Overridepublic String getType(Uri uri) {SqlArguments args = new SqlArguments(uri, null, null);if (TextUtils.isEmpty(args.where)) {return "xx.xx.xx/" + args.table;} else {return "yy.yy.yy/" + args.table;}}

重写查询,这里有个setNotificationUri的方法,这个方法就是在数据库改了之后,通知我们注册的观察者,这个观察这是在cursorAdapter中注册的,想详细了解这里的话,自行百度吧。这里上链接会处于审核中,而一直不过关的。有病。

@Overridepublic Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,String sortOrder) {SqlArguments args = new SqlArguments(uri, selection, selectionArgs);SQLiteQueryBuilder qb = new SQLiteQueryBuilder();qb.setTables(args.table);SQLiteDatabase db = null;Cursor result = null;try {db = mOpenHelper.getWritableDatabase();// .getReadableDatabase();result = qb.query(db, projection, args.where, args.args, null, null, sortOrder);if (result != null) {result.setNotificationUri(getContext().getContentResolver(), uri);}} catch (SQLiteDiskIOException e) {Log.i(TAG, "query : " + e.toString());if (result != null) {result.close();result = null;}}return result;}

再写个插入,批量插入。这里用到了数据库的事务,要插一起插,完事的先等着,没完事的插完了一起拔。(o)/~

@Overridepublic int bulkInsert(Uri uri, ContentValues[] values) {SqlArguments args = new SqlArguments(uri);SQLiteDatabase db = mOpenHelper.getWritableDatabase();db.beginTransaction();try {int numValues = values.length;for (int i = 0; i < numValues; i++) {if (db.insert(args.table, null, values[i]) < 0)return 0;}db.setTransactionSuccessful();} finally {db.endTransaction();}sendNotify(uri);return values.length;}
//通知一下子观察者,数据库变了。
private void sendNotify(Uri uri) {String notify = uri.getQueryParameter(PARAMETER_NOTIFY);if (notify == null || "true".equals(notify)) {getContext().getContentResolver().notifyChange(uri, null);}}

更新和删除就不写了,和插入差不多。返回int类型,更新了几条,删除了几条。

这样,一个BaseContentProvider就写好了。然后写一个类,继承我们的BaseContentProvider就好了。

四、封装思想及过程

上学那时候,学什么课程都要做个学生信息管理系统。后来我腻了,老子来学计算机是打算做游戏的,天天做个破管理系统干毛啊?

后来老师一想,恩,就让我做了个跟游戏有关的玩家信息管理系统。。。

OMG,后来拷贝代码的时候,没改名,玩家有一个表叫做课程表。交作业的时候,老师问我,玩家为什么要有课程?

我答,这是本游戏的特色,玩家除了玩游戏以外还可以学习。我天猫的是一本正经的那种表情和语气当着全班同学的面回答的啊。回答完自己都憋不住笑。同学们都说我是个弱智。

所以这里创建的表还是Course

然后说一下封装的思想。封装,就是将一系列操作,打包,暴露给外部使用的时候,十分简单。而正因为这种封装的封闭性,所以我们封装的一定要严谨,一定要不能出错。层层判断是必须的,现在你拿出任何一个知名的APP出来,你看他的源代码,都是判断的十分严谨,恨不得所有地方都写上if。对数据的来源,不信任,不关心,这是Java的一个封装最基本的思想,哪怕你知道数据的来源可靠。如果代码里这种判断都没有,那么这个代码一定是个垃圾。

划重点:对数据的来源,不信任且不关心,哪怕你知道这数据是从哪来的,并且传的是什么,那也要加上判断。

CourseContentProvider

/*** Created by WenCh on 2017/11/5.*/public class CourseContentProvider extends BaseContentProvider {public static final int DATABASE_VERSION = Constants.DATABASE_VERSION;public static final String DATABASE_NAME = "netease_vopen.db";public static final String AUTHORITY = Constants.DATABASE_AUTHORITY;public static final Uri BASE_URI = Uri.parse("content://" + AUTHORITY);public static final String TABLE_All_DTTA = "t_vopen_all_data";@Overridepublic boolean onCreate() {setSQLiteOpenHelper(new com.contentprovidertest.CourseHelper(getContext()));return true;}public static class CourseHelper {/**===================数据库字段==================*//**课程id*/public static final String COURSE_ID = "course_id";/**课程名称*/public static final String COURSE_NAME = "course_name";/**课程tag*/public static final String COURSE_TAG = "course_tag";/**===================数据库字段==================*/public static Uri getUri() {return Uri.parse("content://" + CourseContentProvider.AUTHORITY + "/"+ TABLE_All_DTTA);}}
}//这里也可以写上其他表的Helper,我就不写了,略了,略略略

DBApi

/*** Created by WenCh on 2017/11/5.*/public class DBApi {public static final int DB_OPERATION_FAILED = -1;/************************************************************** table name :TABLE_All_DTTA = "t_vopen_all_data"*************************************************************///该表数据字段public static class DBCourseInfo {public String mCourseId;public String mCourseName;public String mCourseTag;}/*** 向表所有数据表中插入一项** @param context 不瞎都知道* @param course  不傻都知道* @return 不是沙比都知道* @deprecated ^_^*/public static Uri insertCourse(Context context, DBCourseInfo course) {if (null == course) {return null;}ContentValues initialValues = new ContentValues();if (!("判断一下相应的条件," +"比如说数据库里有其他字段,这个字段是标识的type," +"因为数据库里有很多表,所以根据这个type来判断是哪个表,否可能插入错误," +"这里是demo,就不写了").isEmpty())initialValues.put(CourseContentProvider.CourseHelper.COURSE_TAG, course.mCourseTag);return context.getContentResolver().insert(CourseContentProvider.CourseHelper.getUri(), initialValues);}
}//这里也可以像其他表插入,比如插入学生。。。。
//insertStudent,可以这样命名,然后调用的CourseContentProvider中
//的别的Helper,比如StudentHelper。懂了吗?

懂了

DBUtils

这个类里,可以写一些对对条件的判断,对数据库的操作,调用DBApi。来实现更强大的功能。

/*** Created by WenCh on 2017/11/5.* <p>* 该类用来处理数据库操作后的封装*/public class DBUtils {private static final String TAG = "DBUtils";/*** 查询与某一门课程相似的课程列表。** @param context* @param info* @return*/public static Cursor getRelativeCourses(Context context, BeanCourse info) {String[] projection = new String[]{CourseContentProvider.CourseHelper.COURSE_CONTENT, "_id"};StringBuilder selectionBuilder = new StringBuilder();List<String> selectionArgsList = new ArrayList<String>();//不包括自己selectionBuilder.append(CourseContentProvider.CourseHelper.COURSE_ID + "<> ?");selectionArgsList.add(info.plid);//有相同的tagString tags = info.tags;if (!TextUtils.isEmpty(tags)) {selectionBuilder.append(" AND ");String[] tagTokens = tags.split(",");selectionBuilder.append("(");for (int i = 0; i < tagTokens.length; i++) {String tag = tagTokens[i];selectionBuilder.append(CourseContentProvider.CourseHelper.COURSE_TAG + " LIKE ? " + " OR ");selectionArgsList.add("%" + tag + "%");}selectionBuilder.setLength(selectionBuilder.length() - 4);selectionBuilder.append(")");}String selection = null;if (selectionBuilder.length() > 0) {selection = selectionBuilder.toString();}String[] selectionArgs = null;if (selectionArgsList.size() > 0) {selectionArgs = selectionArgsList.toArray(new String[0]);}String sortOrder = CourseContentProvider.CourseHelper.COURSE_NAME + " DESC";return DBApi.queryCourse(context, projection, selection, selectionArgs, sortOrder);}
}//这里也可以加上其他方法,例如,模糊插入,判断表里有没有,有就更新,没有就插入等等。

怎么样,经过这一层层封装,是不是可以完成很强大的功能?而逻辑还是清晰的?如果你什么都写一个类里,那么你一定特别乱。

五、封装思想总结

BaseContentProvider完成一些ContentProvider的操作。实现。

CourseContentProvider继承自BaseContentProvider,内部含有很多表的Helper,Helper包含一些字段,uri等。

DBApi是完成对相应的表的数据库操作,注意,是相应的表的。可以insertStudent,也可以insertCourse。调用CourseContentProvider以及其各种Helper。

DBUtils则是通过DBApi来完成更强大的功能,模糊查询,模糊插入等。当然了,最基本的插入啥的一定会有的。

周末愉快。卧槽,写完这博客已经0:12了。。。。。。

周一愉快。

ContentProvider操作数据库—一项古老的Android技术相关推荐

  1. Android备考01 黑马76期-day03 操作数据库

    数据库创建以及原始方式操作数据库 activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/a ...

  2. Android学习---通过内容提供者(ContentProvider)操作另外一个应用私有数据库的内容...

    一.什么是ContentProvider? ContentProvider直译过来就是内容提供者,主要作用就是A应用提供接口给B应用调用数据,和之前介绍的sharedPreference和直接开放文件 ...

  3. Android 第十二课 使用LitePal操作数据库(记得阅读最后面的注意事项哦)

    一.LitePal简介 1.(新建项目LitePalTest) 正式接触第一个开源库---LitePal LitePal是一款开源的Android 数据库框架,它采用了对象关系映射(ORM)的模式. ...

  4. Android初学之十七:使用LitePal操作数据库

    一.LitePal简介 LitePal是一款开源的Android数据库框架,它采用了对象关系映射(ORM)的模式,并将我们平时开发最常用到的一些数据库功能进行了封装,使得不用编写一行SQL语句就可以完 ...

  5. Android 使用ORMLite 操作数据库

    参考:http://blog.csdn.net/cjjky/article/details/7096987 ormlite 方法查询:http://ormlite.com/javadoc/ormlit ...

  6. Android Studio中通过SQLiteDatabase类操作数据库

    SQLite是一款轻型的数据库,主要用在嵌入式系统,它占用的资源非常低.SQLite不依赖第三方软件,也不需要安装.数据库中的信息都包含在一个文件中,这个文件可以自由地复制到其它目录或其它机器上. 在 ...

  7. 使用一个ContentProvider操作多张表

    使用一个ContentProvider操作多张表 在我们开发过程中,通常使用ContentProvider来操作数据.查询数据库中的一张表的数据我们创建一个ContentProvider提供操作,需要 ...

  8. 使用LitePal操作数据库(CRUD增删改查) 项目已上传GitHub

    GitHub项目地址: https://github.com/Skymqq/LitePalSave.git LitePal是一款开源的Android数据库框架,它采用了对象关系映射(ORM)映射的模式 ...

  9. 安卓案例:利用SQLiteOpenHelper操作数据库及表

    安卓案例:利用SQLiteOpenHelper操作数据库及表 一.运行效果 二.涉及知识点 1.利用SQLiteOpenHelper类创建与升级数据库 这个类是一个抽象类,我们必须继承该类创建一个子类 ...

最新文章

  1. WPF自学入门(十一)WPF MVVM模式Command命令 WPF自学入门(十)WPF MVVM简单介绍...
  2. python3 执行系统命令
  3. 在 Ubuntu 16.04 上安装 LEMP 环境之图文向导
  4. 7-7 汉密尔顿回路 (25 分)(C语言实现)
  5. android预览界面编译出错,Android O预览findViewById编译错误
  6. hdu-1003 Max Sum
  7. SQL Server里的闩锁介绍
  8. dig命令的介绍与使用
  9. 投影仪与计算机连接方式,电脑与接投影仪、显示器的连接和设置方法
  10. 外贸建站教程,WordPress外贸自建站流程,会打字即可学会
  11. matlab 张德风,Matlab图形界面图像的旋转、平移和缩放
  12. Hexo写博客时的图片问题
  13. Excel快捷键(字母+数字)大全
  14. Linux权限的理解
  15. 三维地下管线系统(skyline)
  16. Geospatial-地理空间
  17. Android 手机录制wav格式音频文件实现
  18. gin post 数据参数_gin请求参数处理
  19. simon手册翻译_part1
  20. 用HALL 库配置GPIO以及相关寄存器

热门文章

  1. 如何善用产品设计的三个层级
  2. 认识计算机学情分析方案,知学情 研教法 夯基础 重效果-------计算机应用工程系召开2014级学情分析会...
  3. openmv4系列2----镜头讨论
  4. Java实现鲜花销售系统
  5. python可以做鲁棒优化吗_XPROG: 简单实用的鲁棒优化(RO, DRO)编程语言
  6. 【前端】你好,我叫TypeScript 02──变量与接口
  7. 关于QCustomPlot的rescaleAxes()和setRange()函数
  8. Downie 4 for Mac(最好用的视频下载软件)v4.3.5直装版
  9. 用JS脚本实现批量插入MongoDB数据
  10. IIS配置WCF服务