why room Database data loading is very long and slow - android

I use the room database for cache some data in my app.but when I run the app in the emulator or my real phone, it usually takes 5 seconds to load data from the database and show ... this is very long time ... even my data is few
Can anyone help me to resolve this?
thank you
ordeeDao.java:
#Query("SELECT * FROM tbl_orders")
List<Orders> getOrders();
and my CacheDatabase class :
#Database(entities = {Orders.class}, version = 1,exportSchema = false)
public abstract class CacheDatabase extends RoomDatabase {
private static CacheDatabase INSTANCE;
public abstract OrdersDao ordersDao();
public static CacheDatabase getInMemoryDatabase(Context context) {
if (INSTANCE == null) {
INSTANCE =
Room.databaseBuilder(context.getApplicationContext(), CacheDatabase.class, "CacheDb.sql")
.allowMainThreadQueries()
.build();
}
return INSTANCE;
}
public static void destroyInstance() {
INSTANCE = null;
}
DataBase.java:
public JSONArray getOrders(){
try {
return new JSONArray(new GsonBuilder().create().toJson(db.ordersDao().getOrders()));
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
private void SetOrdersDB() {
JSONArray ordersArray=db.getOrders();
List<MainPojo.Order> ordersList=new ArrayList<>();
for (int i=0;i<ordersArray.length();i++){
JSONObject object;
MainPojo.Order order=new MainPojo.Order();
try {
object=ordersArray.getJSONObject(i);
order.setId(object.getInt("id"));
order.setTicket_id(object.getString("ticket_id"));
order.setService(object.getString("service"));
order.setStatus(object.getString("status"));
order.setType(object.getString("type"));
order.setFromCurrency(object.getString("from_currency"));
order.setFromAmount(object.getString("from_amount"));
order.setToCurrency(object.getString("to_currency"));
order.setToAmount(object.getString("to_amount"));
order.setPayableAmount(object.getString("payable_amount"));
order.setFee(object.getString("fee"));
order.setDiscount(object.getString("discount"));
order.setPaymentMethod(object.getString("payment_method"));
order.setPaymentGateway(object.getString("payment_gateway"));
order.setPaymentRef(object.getString("payment_ref"));
order.setPayedAt(object.getString("payed_at"));
order.setExpiresAt(object.getString("expires_at"));
order.setHandledAt(object.getString("handled_at"));
order.setCreatedAt(object.getString("created_at"));
order.setUpdatedAt(object.getString("updated_at"));
order.setIcon(object.getString("icon"));
order.setAmount(object.getString("amount"));
ordersList.add(order);
}catch (Exception e){
e.getMessage();
}
}
ordersFragment=new OrdersFragment(ordersList,this);
}

Related

Room Database showing wrong data after deleting item

I am using room database in my app.The app shows books under three categories All Books,Home Books and Library Books.The app shows books data based on user selection.Everything works fine,the app shows correct category books,but when user deletes a Book from any category then the app and list refreshes, then some times app shows wrong data means if a user is viewing books under Home Books category and he deletes a book then the app shows him random books instead of showing his selected Home Books.
// This is how I am loading data:
public void loadBooks(){
if(booksType==1){
mBookViewModel.getAllBooks().observe(this, new Observer<List<Books>>() {
#Override
public void onChanged(#Nullable final List<Books>books) {
adapter.setBooks(books);
}
});
}
if(booksType==2){
mBookViewModel.getHomeBooks().observe(this, new Observer<List<Books>>() {
#Override
public void onChanged(#Nullable final List<Books>books) {
// Update the cached copy of the words in the adapter.
adapter.setBooks(books);
}
});
}
if(booksType==3){
mBookViewModel.getLibrarayBooks().observe(this, new Observer<List<Books>>() {
#Override
public void onChanged(#Nullable final List<Books>books) {
// Update the cached copy of the words in the adapter.
adapter.setBooks(books);
}
});
}
calculateSum();// calculating sum of values of a column.
}
public void calculateSum(){
double total=mBookViewModel.getBookSum();
}
// This how I am deleting a book:
public void delete(Books book){
int rowsDeleted = mBookViewModel.deleteBook(book);
loadBooks(); //have to call this method as I am doing other stuff also.Like calculating the sum of other integer fields.
// suppose user is viewing Home Books(means bookType==2) after this call instead of showing user Home Books the app shows him any random list of books.It does not happen always but after user deletes five to six books continuously and fast.
}
// My View Model:
LiveData<List<Books>> getAllBooks() {return mRepository.getAllBooks(); }
LiveData<List<Books>> getHomeBooks() {return mRepository.getHomeBooks(); }
LiveData<List<Books>> getLibraryBooks() {return mRepository.getLibraryBooks(); }
double getBookSum() {return mRepository.getBookSum(); }
// Repository:
LiveData<List<Books>> getallBooks() {
try {
return new getAllBooksAsyncTask(mBooksDao).execute().get();
} catch (ExecutionException e) {
e.printStackTrace();
return null;
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
}
private static class getAllBooksAsyncTask extends AsyncTask<Void, Void, LiveData<List<Books>>> {
private BooksDao mAsyncTaskDao;
getAllBooksAscAsyncTask(BooksDao dao) {
mAsyncTaskDao = dao;
}
#Override
protected LiveData<List<Books>> doInBackground(Void... voids) {
return mAsyncTaskDao.getAllBooks();
}
}
LiveData<List<Books>> getallBooks() {
try {
return new getAllBooksAsyncTask(mBooksDao).execute().get();
} catch (ExecutionException e) {
e.printStackTrace();
return null;
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
}
private static class getHomeBooksAsyncTask extends AsyncTask<Void, Void, LiveData<List<Books>>> {
private BooksDao mAsyncTaskDao;
getHomeBooksAscAsyncTask(BooksDao dao) {
mAsyncTaskDao = dao;
}
#Override
protected LiveData<List<Books>> doInBackground(Void... voids) {
return mAsyncTaskDao.getHomeBooks();
}
}
LiveData<List<Books>> getallBooks() {
try {
return new getAllBooksAsyncTask(mBooksDao).execute().get();
} catch (ExecutionException e) {
e.printStackTrace();
return null;
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
}
private static class getLibraryBooksAsyncTask extends AsyncTask<Void, Void, LiveData<List<Books>>> {
private BooksDao mAsyncTaskDao;
getLibraryBooksAscAsyncTask(BooksDao dao) {
mAsyncTaskDao = dao;
}
#Override
protected LiveData<List<Books>> doInBackground(Void... voids) {
return mAsyncTaskDao.getLibraryBooks();
}
}
public double getBookSum() {
try {
return new getBookSumAsyncTask(mBookDao).execute().get();
} catch (ExecutionException e) {
e.printStackTrace();
return 0;
} catch (InterruptedException e) {
e.printStackTrace();
return 0;
}
}
private static class getBookSumAsyncTask extends AsyncTask<Void, Void, Double> {
private BookDao mAsyncTaskDao;
getBookSumAsyncTask(BookDao dao) {
mAsyncTaskDao = dao;
}
#Override
protected Double doInBackground(Void... voids) {
return mAsyncTaskDao.getBookSum();
}
}
// Dao:
#Query("SELECT * FROM books WHERE type = 1 ")
LiveData<List<Books>> getAllBooks();
#Query("SELECT * FROM books WHERE type = 2 ")
LiveData<List<Books>> getHomeBooks();
#Query("SELECT * FROM books WHERE type = 3 ")
LiveData<List<Books>> getLibraryBooks();
#Query("SELECT SUM(pages) FROM books ")
double getBookSum();
// Recycler View:
#Override
public void onBindViewHolder(#NonNull booksRecyclerAdapter.BookViewHolder holder, int position) {
if (mBookss != null) {
Books current = mBooks.get(position);
String name = current.getName();
holder.nameTextView.setText(name);
}
}
void setBooks(List<Books> book){
mBooks = book;
notifyDataSetChanged();
}
#Override
public int getItemCount() {
if (mBooks != null)
return mBooks.size();
else return 0;
}
public Books getBookAtPosition (int position) {
return mBooks.get(position);
}
I have tried adding adapter.notifyDataSetChanged() and adapter.notifyItemRemoved(position); but it does not work.Also,if there is something wrong in my codes then why it does not happen always,it happens sometimes usually after deleting five or six items continuously.
Any help is highly appreciated.
After much trying I figured out that the problem was because of the adapter.The adapter was loading previously selected books list e.g. if a user first selects homeBooks and then selects allBooks and perform a delete query on any one book in allBooks list then after the delete operation instead of keeping the user on allBooks list the adapter was showing him homeBooks list. As I was using same adapter for all three cases.I think this may be a problem with Room Database .So,when I used different adapters for different cases everything worked as expected.I don't know whether this is the correct way to do it but for now it is working.So the code now becomes
public void loadBooks(){
if(booksType==1){
bookRecyclerAdapter adapter1=new bookRecyclerAdapter(this);
recyclerView.setAdapter(adapter1);
mBookViewModel.getAllBooks().observe(this, new Observer<List<Books>>() {
#Override
public void onChanged(#Nullable final List<Books>books) {
adapter1.setBooks(books);
}
});
}
if(booksType==2){
bookRecyclerAdapter adapter2=new bookRecyclerAdapter(this);
recyclerView.setAdapter(adapter2);
mBookViewModel.getHomeBooks().observe(this, new Observer<List<Books>>() {
#Override
public void onChanged(#Nullable final List<Books>books) {
// Update the cached copy of the words in the adapter.
adapter2.setBooks(books);
}
});
}
if(booksType==3){
bookRecyclerAdapter adapter3=new bookRecyclerAdapter(this);
recyclerView.setAdapter(adapter3);
mBookViewModel.getLibrarayBooks().observe(this, new Observer<List<Books>>() {
#Override
public void onChanged(#Nullable final List<Books>books) {
// Update the cached copy of the words in the adapter.
adapter3.setBooks(books);
}
});
}
calculateSum();// calculating sum of values of a column.
}

LiveData is not updating after the first call in Android Java

I'm trying to build an app to fetch list of feed from server and display in Recyclerview. I am trying out basic implementation of LiveData like this.
I have set up an observer in my Fragment as follows:
viewModel = ViewModelProviders.of(getActivity()).get(SellViewModel.class);
viewModel.getSellItemList(19).observe(this, new Observer<List<LambdaSellRequestClass>>() {
#Override
public void onChanged(#Nullable List<LambdaSellRequestClass> sellItems) {
adapter.setSellEntities(sellItems);
}
});
My SellViewModel clas like this:
public class SellViewModel extends AndroidViewModel {
private SellRepository repository;
private MutableLiveData<List<LambdaSellRequestClass>> sellItems;
public SellViewModel(#NonNull Application application) {
super(application);
repository = new SellRepository(application);
try {
if (sellItems == null) {
sellItems = new MutableLiveData<>();
sellItems.postValue(repository.getSellItemList(user_id));
}
}catch (Exception e) {
Log.d("SELLFRAGMENT", "Error: " + e.getLocalizedMessage());
}
}
public MutableLiveData<List<LambdaSellRequestClass>> getSellItemList(int userId) throws ExecutionException, InterruptedException {
return sellItems;
}
}
My SellRepository like this:
public class SellRepository {
public SellRepository(Application application) {
}
public List<LambdaSellRequestClass> getSellItemList(int userId) throws ExecutionException, InterruptedException {
return new SellRepository.GetSellItemListAsync(SellRepository.this).execute(userId).get();
}
private static class GetSellItemListAsync extends AsyncTask<Integer, Void, List<LambdaSellRequestClass>> {
List<LambdaSellRequestClass> list = new ArrayList<>();
public GetSellItemListAsync() {
}
#Override
protected List<LambdaSellRequestClass> doInBackground(Integer... integers) {
final int userID = integers[0];
list =
lambdaFunctionsCalls.getSellItemByUser_lambda(requestClass).getSellItems();
return list;
}
}
My problem is when I add new sell items to database its not update mobile app.

How to migrate unencryped realm to encrypt realm

My last release app is using not encrypted realm.
Now, I want to update to use encrypted realm.
But I don't know how to migrate unencrypted data.
Help me please~ :(
Answer by myself.
I made util class to help migration. (unecncrypted file -> encrpyted file)
public class RealmEncryptionHelper {
private static final String ENCRYPTION_FILE_PREFIX = "encrypted_";
public static Realm createEncryptedRealm(Context context, RealmConfiguration.Builder builder) {
RealmConfiguration unencryptedConfig = builder.build();
RealmConfiguration encryptedConfig = builder.name(ENCRYPTION_FILE_PREFIX + unencryptedConfig.getRealmFileName())
.encryptionKey(AppSharedPreferences.getInstance(context).getRealmEncryptionKey())
.build();
migrationIfNeeded(unencryptedConfig, encryptedConfig);
return Realm.getInstance(encryptedConfig);
}
private static void migrationIfNeeded(RealmConfiguration unencryptedConfig, RealmConfiguration encryptedConfig) {
File unencryptedFile = new File(unencryptedConfig.getPath());
File encryptedFile = new File(encryptedConfig.getPath());
Realm unencryptedRealm = null;
if (!encryptedFile.exists() && unencryptedFile.exists()) {
try {
unencryptedRealm = Realm.getInstance(unencryptedConfig);
unencryptedRealm.writeEncryptedCopyTo(encryptedFile, encryptedConfig.getEncryptionKey());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (unencryptedRealm != null) {
unencryptedRealm.close();
unencryptedFile.delete();
}
}
}
}
}
#Orlando
like this?
class EncryptionMigration implements RealmMigration {
#Override
public void migrate(DynamicRealm dynamicRealm, long oldVersion, long newVersion) {
byte[] encryptionKey = "flkajskdf............................".getBytes();
if (oldVersion == UNENCRYPT_VERSION) {
try {
dynamicRealm.writeEncryptedCopyTo(new File(dynamicRealm.getPath()), encryptionKey);
} catch (IOException e) {
e.printStackTrace();
}
}
}

Android Database in AsyncTask in Fragment

I have a DbHelper Class which extends SQLiteOpenHelper.
I do Some Download and update the Database inside an Asynctask.
Inside an activity i got no problem and code works fine,
but when i use the ASynctask class inside a fragment problems occurs.
usually wherever i use a context an Exception happened, Especially with dbHelper.ClearDB()
Error:
DB Read ERROR:java.lang.NullPointerException:
Attempt to invoke virtual method 'java.util.ArrayList x.database.DBHelper.getAllItems()' on a null object reference
Here's the code :
public class StaggeredFragment extends Fragment
{
private DBHelper dbHelper;
private SharedPreferences preferences;
private ArrayList<DisItem> savedData;
private final String LINK1 = "myLink";
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
dbHelper = new DBHelper(getActivity().getApplicationContext());
preferences = getActivity().getSharedPreferences("pid", Context.MODE_PRIVATE);
new LoaderAsyncTask("ALL").execute();
}
class LoaderAsyncTask extends AsyncTask<Void, Void, Boolean> {
String brand;
LoaderAsyncTask(String brand) {
this.brand = brand;
}
#Override
protected Boolean doInBackground(Void... params) {
Log.d(TAG,"RUnning");
String fetched;
InputStream is = null;
//Store Current Data before Sync
try {
savedData = dbHelper.getAllItems();
}catch (Exception e)
{
Log.d(TAG,"DB Read ERROR:"+e.toString());
return false;
}
try {
dbHelper.ClearDB();
}catch (Exception e)
{
Log.d(TAG,"DB Clear ERROR:"+e.toString());
return false;
}
// Open connection to server for html
try {
is = urlStream(LINK1);
} catch (Exception e) {
Log.e(TAG, "HTTP Error " + e.toString());
return false;
}
// Fetch HTML Data
try {
fetched = readIt(is);
// Log.d("fetched", fetched);
} catch (Exception e) {
Log.e(TAG, "Buffer Error " + e.toString());
return false;
}
// Parsing JSON
try {
if (!fetched.isEmpty())
InitialsJson(fetched);
}catch (JSONException e) {
Log.e(TAG, "JSON Error " + e.toString());
return false;
}
return true;
}
#Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
if(!aBoolean)
RestoreData();
}
}
private void InitialsJson(String fetched) throws JSONException
{
JSONObject jsonObject = new JSONObject(fetched);
if (jsonObject.getInt("success") == 1) {
JSONArray array = jsonObject.getJSONArray("data");
for (int i = 0; i<array.length() ; i++) {
JSONObject object = array.getJSONObject(i);
DisItem disItem = new DisItem();
disItem.setPid(object.getString("pid"));
disItem.setLiked(preferences.getBoolean(String.valueOf(disItem.getPid()), false));
Log.d(TAG, disItem.toString());
dbHelper.insert(disItem);
}
}
}
This is Databace getallItems function
public ArrayList<DisItem> getAllItems()
{
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery("select * from " + DIS_TABLE_NAME + "", null);
ArrayList<DisItem> arrayList = new ArrayList<>();
cursor.moveToFirst();
while (! cursor.isAfterLast())
{
DisItem disItem = new DisItem(cursor);
arrayList.add(disItem);
cursor.moveToNext();
}
return arrayList;
}
I tried your code with same scenario in a small JUnit Test and it shows me that you have not initialized your ArrayList<DisItem> correctely in getAllItems() method may be thats why you are getting nullPointerException that is
Replace
ArrayList<DisItem> arrayList = new ArrayList<>();
With
ArrayList<DisItem> arrayList = new ArrayList<DisItem>();'
I corrected this thing and run the test again with some dummy values and it showed me correct result like:
public class Test
{
private ArrayList<DisItem> savedData;
#org.junit.Test
public void test() throws Exception
{
savedData = getAllData();
for(int a = 0; a < savedData.size(); a++){
System.out.println("ArrayList Data A= " + savedData.get(a).getA() + " B = " + savedData.get(a).getB());
}
}
}
private ArrayList<DisItem> getAllData()
{
ArrayList<DisItem> arrayList = new ArrayList<DisItem>();
DisItem disItem = new DisItem();
disItem.setA("AAAAAA");
disItem.setB("BBBB");
arrayList.add(disItem);
return arrayList;
}
private class DisItem
{
String a, b;
public void setA(String a)
{
this.a = a;
}
public void setB(String b)
{
this.b = b;
}
public String getA()
{
return this.a;
}
public String getB()
{
return this.b;
}
}
Output:
ArrayList Data A= AAAAAA B = BBBB
you cant access more than one SharedPreferences or SQLiteOpenHelper in Parallel.

db4o on Android 3.0+ Issue

I'm having an issue with db4o on Android 3.0+ because it turns out that on the creation of the db4o database, it uses some of the network apis by default. (I stumbled upon this post: http://mavistechchannel.wordpress.com/2011/11/18/db4o-at-honeycomb-and-ice-cream-sandwich/ about it)
However, I've attempted to make the db creation requests async, but I think I'm running into an issue of calling the db before it's fully created as it locks the DB. (And I now get a locking error) Is there any way I can do this synchronous? or, at a minimum wait until it's been finished? Here's my db4o helper:
public class Db4oHelperAsync implements Constants{
private static final String USE_INTERNAL_MEMORY_FOR_DATABASE = "USE_INTERNAL_MEMORY_FOR_DATABASE";
private static ObjectContainer oc = null;
private Context context;
/**
* #param ctx
*/
public Db4oHelperAsync(Context ctx) {
context = ctx;
}
/**
* Create, open and close the database
*/
public ObjectContainer db() {
if (oc == null || oc.ext().isClosed()) {
if (Utilities.getPreferences(context).getBoolean(USE_INTERNAL_MEMORY_FOR_DATABASE, true)) {
new GetDbFromInternalMemory().execute();
} else {
new GetDbFromSDCard().execute();
}
return oc;
} else {
return oc;
}
}
/**
* Configure the behavior of the database
*/
private EmbeddedConfiguration dbConfig() throws IOException {
EmbeddedConfiguration configuration = Db4oEmbedded.newConfiguration();
configuration.common().objectClass(PersistentObjectWithCascadeOnDelete.class).objectField("name").indexed(true);
configuration.common().objectClass(PersistentObjectWithCascadeOnDelete.class).cascadeOnUpdate(true);
configuration.common().objectClass(PersistentObjectWithCascadeOnDelete.class).cascadeOnActivate(true);
configuration.common().objectClass(PersistentObjectWithCascadeOnDelete.class).cascadeOnDelete(true);
configuration.common().objectClass(PersistentObjectWithoutCascadeOnDelete.class).objectField("name").indexed(true);
configuration.common().objectClass(PersistentObjectWithoutCascadeOnDelete.class).cascadeOnUpdate(true);
configuration.common().objectClass(PersistentObjectWithoutCascadeOnDelete.class).cascadeOnActivate(true);
return configuration;
}
/**
* Returns the path for the database location
*/
private String db4oDBFullPathInternal(Context ctx) {
return ctx.getDir("data", 0) + "/" + "testapp.db4o";
}
private String db4oDBFullPathSdCard(Context ctx) {
File path = new File(Environment.getExternalStorageDirectory(), ".testapp");
if (!path.exists()) {
path.mkdir();
}
return path + "/" + "testapp.db4o";
}
/**
* Closes the database
*/
public void close() {
if (oc != null)
oc.close();
}
private class GetDbFromInternalMemory extends AsyncTask<Void, Void, ObjectContainer>{
#Override
protected ObjectContainer doInBackground(Void... params) {
try {
ObjectContainer obj = Db4oEmbedded.openFile(dbConfig(), db4oDBFullPathInternal(context));
CLog.v("USING INTERNAL MEMORY FOR DATABASE");
return obj;
} catch (Exception ie) {
ie.printStackTrace();
CLog.e(Db4oHelper.class.getName(), ie.toString());
return null;
}
}
#Override
protected void onPostExecute(ObjectContainer result)
{
oc = result;
}
}
private class GetDbFromSDCard extends AsyncTask<Void, Void, ObjectContainer>{
#Override
protected ObjectContainer doInBackground(Void... params) {
try {
ObjectContainer obj = Db4oEmbedded.openFile(dbConfig(), db4oDBFullPathSdCard(context));
CLog.v("USING SDCARD FOR DATABASE");
SharedPreferences.Editor edit = Utilities.getPreferencesEditor(context);
edit.putBoolean(USE_INTERNAL_MEMORY_FOR_DATABASE, true);
edit.commit();
return obj;
} catch (Exception ie) {
ie.printStackTrace();
CLog.e(Db4oHelper.class.getName(), ie.toString());
return null;
}
}
#Override
protected void onPostExecute(ObjectContainer result)
{
oc = result;
}
}
}
Update: This db4o bug has been fixed. If you get the newest 8.1 bits the error should not occur and the workaround is obsolute:
You get a file-locked exception when trying to get the database? Right.
Well the issue is that you are not waiting for the async task to finish and just start a new one in case the Db4oHelperAsync.oc is null. You basically have to wait until the initialization has finished and only then use the Db4oHelperAsync.oc variable. So your in Java synchronization land.
For example you can do this: Synchronize the Db4oHelperAsync.oc access. When requesting the database wait until the variable is set. Now unfortunately I don't know the exact behavior of the async task. My guess is that it will run the .onPostExecute() method back on the main activity. That also means that you cannot just wait for it, because it would mean that you block the Activity-Thread and .onPostExecute() will never be executed.
Here's my draft of what I would try to do. I never executed nor compiled it. And it probably has synchronization issues. For example when the initialization fail it will just hang your applicaition on the .db() call, because it waits forever. So be very careful and try to improve it:
public class Db4oHelperAsync implements Constants{
private static final String USE_INTERNAL_MEMORY_FOR_DATABASE = "USE_INTERNAL_MEMORY_FOR_DATABASE";
private static ObjectContainer oc = null;
private static final Object lock = new Object();
private Context context;
/**
* #param ctx
*/
public Db4oHelperAsync(Context ctx) {
context = ctx;
}
/**
* Create, open and close the database
*/
public ObjectContainer db() {
synchronized(lock){
if (oc == null || oc.ext().isClosed()) {
if (Utilities.getPreferences(context).getBoolean(USE_INTERNAL_MEMORY_FOR_DATABASE, true)) {
new GetDbFromInternalMemory().start();
} else {
new GetDbFromSDCard().start();
}
while(oc==null){
this.wait()
}
return oc;
} else {
return oc;
}
}
}
/**
* Configure the behavior of the database
*/
private EmbeddedConfiguration dbConfig() throws IOException {
EmbeddedConfiguration configuration = Db4oEmbedded.newConfiguration();
configuration.common().objectClass(PersistentObjectWithCascadeOnDelete.class).objectField("name").indexed(true);
configuration.common().objectClass(PersistentObjectWithCascadeOnDelete.class).cascadeOnUpdate(true);
configuration.common().objectClass(PersistentObjectWithCascadeOnDelete.class).cascadeOnActivate(true);
configuration.common().objectClass(PersistentObjectWithCascadeOnDelete.class).cascadeOnDelete(true);
configuration.common().objectClass(PersistentObjectWithoutCascadeOnDelete.class).objectField("name").indexed(true);
configuration.common().objectClass(PersistentObjectWithoutCascadeOnDelete.class).cascadeOnUpdate(true);
configuration.common().objectClass(PersistentObjectWithoutCascadeOnDelete.class).cascadeOnActivate(true);
return configuration;
}
/**
* Returns the path for the database location
*/
private String db4oDBFullPathInternal(Context ctx) {
return ctx.getDir("data", 0) + "/" + "testapp.db4o";
}
private String db4oDBFullPathSdCard(Context ctx) {
File path = new File(Environment.getExternalStorageDirectory(), ".testapp");
if (!path.exists()) {
path.mkdir();
}
return path + "/" + "testapp.db4o";
}
/**
* Closes the database
*/
public void close() {
synchronized(lock){
if (oc != null)
oc.close();
}
}
private class GetDbFromInternalMemory extends Thread{
#Override
protected void run() {
try {
ObjectContainer obj = Db4oEmbedded.openFile(dbConfig(), db4oDBFullPathInternal(context));
CLog.v("USING INTERNAL MEMORY FOR DATABASE");
synchronized(Db4oHelperAsync.lock){
Db4oHelperAsync.oc = obj;
Db4oHelperAsync.lock.notifyAll()
}
} catch (Exception ie) {
ie.printStackTrace();
CLog.e(Db4oHelper.class.getName(), ie.toString());
}
}
}
private class GetDbFromSDCard extends Thread{
#Override
protected void run() {
try {
ObjectContainer obj = Db4oEmbedded.openFile(dbConfig(), db4oDBFullPathSdCard(context));
CLog.v("USING SDCARD FOR DATABASE");
SharedPreferences.Editor edit = Utilities.getPreferencesEditor(context);
edit.putBoolean(USE_INTERNAL_MEMORY_FOR_DATABASE, true);
edit.commit();
synchronized(Db4oHelperAsync.lock){
Db4oHelperAsync.oc = obj;
Db4oHelperAsync.lock.notifyAll()
}
} catch (Exception ie) {
ie.printStackTrace();
CLog.e(Db4oHelper.class.getName(), ie.toString());
}
}
}
}
P.S. Added this problem as a bug to db4o: http://tracker.db4o.com/browse/COR-2269
Thanks for posting this issue, this is a serious fun-spoiler on Android.
When a new db4o database file is created, db4o generates it's unique internal signature by calling java.net.InetAddress.getLocalHost().getHostName(). Exceptions are not caught in this call. We will find a workaround for Android and post back here and to our forums when this is fixed.
Update Feb 9 2012:
The issue has been fixed and new builds are online.
http://community.versant.com/Blogs/db4o/tabid/197/entryid/1057/Default.aspx

Categories

Resources