java.lang.RuntimeException:Unable to create application com.taoche.qctt.app.App: io.objectbox.exception.DbException: Could not create directory: /data/data/com.taoche.qctt/files/objectbox/objectbox
android.app.ActivityThread.handleBindApplication(ActivityThread.java:4886)
......
Caused by:
io.objectbox.exception.DbException:Could not create directory: /data/data/com.taoche.qctt/files/objectbox/objectbox
io.objectbox.BoxStore.<init>(BoxStore.java:178)
io.objectbox.BoxStoreBuilder.build(BoxStoreBuilder.java:243)
com.taoche.qctt.app.App.onCreate(App.java:64)
android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1012)
android.app.ActivityThread.handleBindApplication(ActivityThread.java:4862)
android.app.ActivityThread.access$1700(ActivityThread.java:169)
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1528)
android.os.Handler.dispatchMessage(Handler.java:102)
android.os.Looper.loop(Looper.java:159)
android.app.ActivityThread.main(ActivityThread.java:5671)
java.lang.reflect.Method.invoke(Native Method)
java.lang.reflect.Method.invoke(Method.java:372)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:964)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:759)


@AndSync Thanks for reporting. Can you identify any pattern here? E.g. specific Android versions, devices? Are those plain Android? How many percent of users are affected?
It happened on all kinds of devices,I only found one thing in common,They almost happened when the app is run in background,and the same as issure #230
@AndSync Can you please post the code how you build BoxStore? Are you using any directory configuration in BoxStoreBuilder?
in Application
public class App extends Application {
private static Context context;
private static BoxStore boxStore;
private static HashSet<String> newsReadSet = new HashSet<>();
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
//dex 拆分
MultiDex.install(base);
context = base;
}
@Override
public void onCreate() {
super.onCreate();
boxStore = MyObjectBox.builder().androidContext(App.this).build();
putNewsReadSet();
}
public static Context getContext() {
return context;
}
public static HashSet<String> getNewsReadSet() {
return newsReadSet;
}
private void putNewsReadSet() {
if (newsReadSet.isEmpty()) {
List<NewsReadEntity> list = NewsDbHelper.getNewsReadList();
for (int i = 0; i < list.size(); i++) {
newsReadSet.add(list.get(i).getNews_id());
}
}
}
public static BoxStore getBoxStore() {
return boxStore;
}
in NewsDbHelper
public class NewsDbHelper {
public static void insertNewsRead(String newsId) {
App.getNewsReadSet().add(newsId);
Box box = App.getBoxStore().boxFor(NewsReadEntity.class);
Query<NewsReadEntity> query = box.query().equal(NewsReadEntity_.news_id, newsId).build();
NewsReadEntity entity = query.findFirst();
if (entity == null) {
entity = new NewsReadEntity();
entity.setNews_id(newsId);
} else {
entity.setSave_time(System.currentTimeMillis());
}
box.put(entity);
}
public static boolean hasRead(String newsId) {
return App.getNewsReadSet().contains(newsId);
}
public static List<NewsReadEntity> getNewsReadList() {
clearNewsReadCache();
Box box = App.getBoxStore().boxFor(NewsReadEntity.class);
Query query = box.query().orderDesc(NewsReadEntity_.save_time).build();
return query.find();
}
public static void clearNewsReadCache() {
Box box = App.getBoxStore().boxFor(NewsReadEntity.class);
int maxNum = 512;
long count = box.count();
if (count > maxNum) {
Query query = box.query().orderDesc(NewsReadEntity_.save_time).build();
box.remove(query.find(maxNum, count - maxNum));
}
}
}
in NewsReadEntity
@Entity
public class NewsReadEntity {
@Id
private long id;
@Index
private long save_time = System.currentTimeMillis();//保存时间用于查找
private String news_id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getNews_id() {
return news_id;
}
public void setNews_id(String news_id) {
this.news_id = news_id;
}
public long getSave_time() {
return save_time;
}
public void setSave_time(long save_time) {
this.save_time = save_time;
}
}
PS.: Please also check the code - I have honestly no idea how a mkdirs call could fail give its preconditions.
This might give a clue: https://stackoverflow.com/questions/19110816/mkdirs-on-application-internal-memory-fails-on-android
However, given that you use androidContext(..) - I have no explanation how it could possibly go beyond that line.
We researched this today (checking Android source code etc.) but came to no final conclusion. We hope you can provide some additional information.
If it is OK to use a new database file (your users would loose the data previously stored in the initial file), you could try the following; instead of
boxStore = MyObjectBox.builder().androidContext(App.this).build();
try this
File alternativeDir = getDir("objectbox", 0);
boxStore = MyObjectBox.builder().directory(alternative).build();
No guarantees here, but the result may be insightful.
@AndSync We would really appreciate some insights from your side. Thank you!
@greenrobot I am sorry to answer your questions late
1、The affected users is about 10% .
2、The exceptions occur multiple times.
3、Yes I have multiple process.I have said in issue #230 .I said I used JPush in my app。You know in China we can't use the GCM ,so there are many kinds of push sdk like JPush ,The basic principle is the process of keeping alive and apps can pull each other。
4、It is not easy to reproduce, but I really inadvertently seen.
5、Of course all of them are made in china.I don't konw there are differences regaring file handling.
I will try your suggestion . and about #230 I think the two issues can merge together .I should what for some days then perorate.
In addition I find other bugs ,they all have the same pointer of the line of code. like
1、io.objectbox.exception.DbMaxReadersExceededException
Could not begin transaction (maximum of read transactions reached)
com.taoche.qctt.app.App.onCreate(App.java:64)
2、 io.objectbox.exception.DbException
Another BoxStore is still open for this directory: /data/data/com.taoche.qctt/files/objectbox/objectbox. Hint: for most apps it's recommended to keep a BoxStore for the app's life time.
com.taoche.qctt.app.App.onCreate(App.java:64)
Thanks for your input - I will get back to you soon. Meanwhile, please also check out ObjectBox 1.2, which also includes some additional safe guards for Android file directory bugs.
@greenrobot I met the same bug when use the 1.2.1 version, here is the log :
Caused by: io.objectbox.exception.DbException: Another BoxStore is still open for this directory: /data/data/com.android.test/files/objectbox/objectbox. Hint: for most apps it's recommended to keep a BoxStore for the app's life time.
at io.objectbox.BoxStore.verifyNotAlreadyOpen(BoxStore.java:242)
at io.objectbox.BoxStore.<init>(BoxStore.java:188)
at io.objectbox.BoxStoreBuilder.build(BoxStoreBuilder.java:270)
at com.android.test.data.database.BloodPressureDB.<init>(BloodPressureDB.java:24)
at com.android.test.data.di.DataModule.bloodPressureDB(DataModule.java:42)
at com.android.test.data.di.DataModule_BloodPressureDBFactory.get(DataModule_BloodPressureDBFactory.java:25)
at com.android.test.data.di.DataModule_BloodPressureDBFactory.get(DataModule_BloodPressureDBFactory.java:10)
at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
at com.android.test.data.di.DataModule_DataRepositoryFactory.get(DataModule_DataRepositoryFactory.java:40)
at com.android.test.data.di.DataModule_DataRepositoryFactory.get(DataModule_DataRepositoryFactory.java:12)
at com.android.test.data.di.DataModule_BloodPressureFormVMFactory.get(DataModule_BloodPressureFormVMFactory.java:33)
at com.android.test.data.di.DataModule_BloodPressureFormVMFactory.get(DataModule_BloodPressureFormVMFactory.java:11)
at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
at com.android.test.TheApplication_MembersInjector.injectMembers(TheApplication_MembersInjector.java:81)
at com.android.test.TheApplication_MembersInjector.injectMembers(TheApplication_MembersInjector.java:14)
at com.android.test.common.di.DaggerApplicationComponent.inject(DaggerApplicationComponent.java:438)
@liujinchaoDS I assume you create multiple BoxStore instances while your app is running. This would require to explicitly close them after usage. To quote the error message: "for most apps it's recommended to keep a BoxStore for the app's life time". Have a single BoxStore instance your app and it becomes much easier.
@AndSync Sorry, I forgot to come back to you. DbMaxReadersExceededException and DbException "Another BoxStore is still open" may hint at a problematic interaction between your app and your code. Is there really just one instance of BoxStore in your app?
Anything else you found out the last days?
@greenrobot We've released a new version with ObjectBox 1.2.0 and this bug report was not received again ,and the same as issure #230
I put the code into main process like tihs
@Override
public void onCreate() {
super.onCreate();
if (isMainProcess()) {
//多通道推送
MultiPushAgent.init(context);
//友盟统计
UmengAgent.init(this);
//Bugly配置
initCrashReport();
//检测内存泄漏
LeakCanary.install(this);
//已读新闻
boxStore = MyObjectBox.builder().androidContext(this).build();
putNewsReadSet();
}
}
private boolean isMainProcess() {
ActivityManager am = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE));
List<ActivityManager.RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();
String mainProcessName = getPackageName();
int myPid = android.os.Process.myPid();
for (ActivityManager.RunningAppProcessInfo info : processInfos) {
if (info.pid == myPid && mainProcessName.equals(info.processName)) {
return true;
}
}
return false;
}
I think this is the key to solving the problem,because @liujinchaoDS met the same bug when use the 1.2.1 version
@AndSync Thank you very much for your letting us know. This is very valuable information.
So we have to investigate multi process support #193 in more detail.
We'll make multi process stable in #193 so closing this now.
Most helpful comment
@greenrobot We've released a new version with ObjectBox 1.2.0 and this bug report was not received again ,and the same as issure #230
I put the code into main process like tihs
I think this is the key to solving the problem,because @liujinchaoDS met the same bug when use the 1.2.1 version