一次ContentProvider踩坑之旅
来源:互联网 发布:three.js 导入obj模型 编辑:程序博客网 时间:2024/05/21 10:02
最近产品中有这样一个需求,有多个进程,在系统开机时通过ContentProvider去查询另外一个进程的数据库,获取一个公共字段。
在实际开发中,有四个进程分别去执行这个操作,但是发现第一个或者前两个进程总是出现开机查询失败对情形。报错信息如下:
07-16 07:08:32.435: E/AndroidRuntime(1869): java.lang.NullPointerException07-16 07:08:32.435: E/AndroidRuntime(1869): at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:224)07-16 07:08:32.435: E/AndroidRuntime(1869): at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)07-16 07:08:32.435: E/AndroidRuntime(1869): at com.example.neuronsdk.DatabaseHandler.open(DatabaseHandler.java:59)07-16 07:08:32.435: E/AndroidRuntime(1869): at com.example.neuronsdk.DatabaseHandler.addEvent(DatabaseHandler.java:72)07-16 07:08:32.435: E/AndroidRuntime(1869): at com.example.neuronsdk.NeuronActivity.onClick(NeuronActivity.java:28)07-16 07:08:32.435: E/AndroidRuntime(1869): at com.example.test_application.MainActivity$1.onClick(MainActivity.java:47)07-16 07:08:32.435: E/AndroidRuntime(1869): at android.view.View.performClick(View.java:4438)07-16 07:08:32.435: E/AndroidRuntime(1869): at android.view.View$PerformClick.run(View.java:18422)07-16 07:08:32.435: E/AndroidRuntime(1869): at android.os.Handler.handleCallback(Handler.java:733)07-16 07:08:32.435: E/AndroidRuntime(1869): at android.os.Handler.dispatchMessage(Handler.java:95)07-16 07:08:32.435: E/AndroidRuntime(1869): at android.os.Looper.loop(Looper.java:136)07-16 07:08:32.435: E/AndroidRuntime(1869): at android.app.ActivityThread.main(ActivityThread.java:5017)07-16 07:08:32.435: E/AndroidRuntime(1869): at java.lang.reflect.Method.invokeNative(Native Method)07-16 07:08:32.435: E/AndroidRuntime(1869): at java.lang.reflect.Method.invoke(Method.java:515)07-16 07:08:32.435: E/AndroidRuntime(1869): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)07-16 07:08:32.435: E/AndroidRuntime(1869): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)07-16 07:08:32.435: E/AndroidRuntime(1869): at dalvik.system.NativeStart.main(Native Method)
根据这个报错信息,很容易的就能将错误信息定位在SQLiteOpenHelper类中的getDatabaseLocked方法中:
private SQLiteDatabase getDatabaseLocked(boolean writable) { //省略代码 ``` db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ? //省略代码 ``` }
很明显初始化数据库帮助类时context为空了。由于数据库所在的进程也是一个单独的进程,当时就想,是不是查询数据库的时候数据库进程还没有完全起来,导致context为空呢?但是心里也犯嘀咕,因为明显方法已经走到ContentProvider查询方法中了,代表这数据库进程(ContentProvider进程)已经起来了。那就只剩下一个种可能了,就是数据库帮助类初始化时,传入的context为空了。
可是自始至终,我写负责的代码部分,都没有给数据库帮助类传入过context,自然的,去查看封装好的数据库帮助类的工具类,见到如下代码:
public abstract class SingleDBHelper extends BaseDBHelper { //省略代码 ``` public SingleDBHelper() { this((Context)null); } public SingleDBHelper(Context context) { if(context == null) { this.mDBHelper = SQLiteDBHelper.getSQLiteDBHelper(BaseApplication.getContext(), this.getDBController()); } else { this.mDBHelper = SQLiteDBHelper.getSQLiteDBHelper(context, this.getDBController());} //省略代码 ```}
可以看到,两个构造方法,如果使用无参构造,时间上在拿数据库时使用的是通过BaseApplication.getContext()得到的context,而我在查询数据库时恰是使用的无参构造,恍然大悟。
ContentProvider和Application都有getContext方法,但是这个连个方法,在各自的onCreat方法被调用之前,得到的都是null。而ContentProvider是一个通过Binder提供跨进程数据共享的组件,当ContentProvider所在的进程启动时,ContentProvider会同时启动并发布到AMS中,而这个时候,ContentProvider的onCreate方法,会先于Application的onCreate方法。也就是说,在其他进程通过ContentProvider查询数据库的时候,数据库进程起来了,ContentProvider的onCreate方法被调用,但此时Application的onCreate方法可能还没有被调用,于是通过ContentProvider增删改查方法操作数据库时,就会报上面提到的错误。
总结:虽然ContentProvider的getContext方法,和Application的getContext方法,得到的context是一个context,但是由于ContentProvider和Application的onCreate方法有一个先后顺序的问题,导致ContentProvider的getContext不为null了,但是Application的getContex方法却处于可能为空的状态。因此,初始化数据库时,能保证使用ContentProvider的contex,就能避免两者onCreate方法执行时机带来的空指针异常。
- 一次ContentProvider踩坑之旅
- 记一次SQL踩坑之旅
- Android复习之旅--ContentProvider
- 记一次DatePicker坑爹之旅
- gitbook 一次安装之旅
- android 系统之ContentProvider
- Android开发之ContentProvider
- Android之ContentProvider
- Android之ContentProvider
- Android之ContentProvider总结
- Android之ContentProvider总结
- Android之ContentProvider总结
- Android之ContentProvider总结
- ContentProvider 之文件储存
- Android之ContentProvider
- Android之ContentProvider详解
- Android之ContentProvider
- Android之ContentProvider总结
- 9月英语总结--日积月累
- 前端之bootstrap-常用类名
- 【模板】高精度阶乘
- 出差累成狗
- SpringCloud(第 016 篇)电影微服务,定制Feign,一个Feign功能禁用Hystrix,另一个Feign功能启用Hystrix
- 一次ContentProvider踩坑之旅
- 关于安卓APP底栏点击第一次选中当前Fragment第二次点击更新当前页面的问题(思路)
- Git常用命令
- ACM-ICPC国际大学生程序设计竞赛北京赛区(2017)网络赛 A.Visiting Peking University
- robot framework 接口自动化测试
- HBase分析之概念
- 怎么理解二阶偏导与凸函数的Hessian矩阵是半正定的?
- SpringCloud(第 017 篇)电影微服务接入Feign,添加 fallbackFactory 属性来触发请求进行容灾降级
- Jenkins基础入门-13-Jenkins构建监视器-CatLight