db4o на Android 3.0+ выпуск - PullRequest
       5

db4o на Android 3.0+ выпуск

3 голосов
/ 20 декабря 2011

У меня проблема с db4o на Android 3.0+, потому что оказывается, что при создании базы данных db4o она использует некоторые сетевые apis по умолчанию. (Я наткнулся на этот пост: http://mavistechchannel.wordpress.com/2011/11/18/db4o-at-honeycomb-and-ice-cream-sandwich/ об этом)

Однако я попытался сделать запросы на создание базы данных асинхронными, но я думаю, что столкнулся с проблемой вызова базы данных до того, как она будет полностью создана, поскольку она блокирует базу данных. (И теперь я получаю ошибку блокировки) Есть ли способ сделать это синхронно? или, как минимум, подождать, пока он не закончится? Вот мой помощник db4o:

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;
    }
}
}

Ответы [ 2 ]

2 голосов
/ 21 декабря 2011

Обновление: эта ошибка db4o была исправлена ​​. Если вы получите новейшие 8,1 битов, ошибка не должна возникать, и обходной путь является абсолютным:

Вы получаете исключение, заблокированное файлом, при попытке получить базу данных? Право.

Ну, проблема в том, что вы не ждете завершения асинхронной задачи и просто запускаете новую, если Db4oHelperAsync.oc имеет значение null. В основном вам нужно подождать, пока инициализация не закончится, и только затем использовать переменную Db4oHelperAsync.oc. Таким образом, ваша земля синхронизации Java.

Например, вы можете сделать это: Синхронизировать доступ Db4oHelperAsync.oc. При запросе базы данных подождите, пока переменная не будет установлена. Сейчас, к сожалению, я не знаю точное поведение асинхронной задачи. Я предполагаю, что он запустит метод .onPostExecute () обратно к основному действию. Это также означает, что вы не можете просто ждать этого, потому что это будет означать, что вы блокируете Activity-Thread, и .onPostExecute () никогда не будет выполняться.

Вот мой набросок того, что я бы попытался сделать. Я никогда не выполнял и не компилировал это. И это, вероятно, имеет проблемы с синхронизацией. Например, если инициализация не удалась, она просто повесит ваше приложение на вызов .db (), потому что оно ждет вечно. Так что будьте очень осторожны и постарайтесь улучшить это:

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. Добавил эту проблему как ошибку в db4o: http://tracker.db4o.com/browse/COR-2269

1 голос
/ 05 января 2012

Спасибо за сообщение об этой проблеме, это серьезный спойлер на Android. Когда создается новый файл базы данных db4o, db4o генерирует свою уникальную внутреннюю подпись, вызывая java.net.InetAddress.getLocalHost (). GetHostName (). Исключения не фиксируются в этом вызове. Мы найдем обходной путь для Android и опубликуем здесь и на наших форумах, когда это будет исправлено.

Обновление 9 февраля 2012 г .: Проблема была исправлена, и новые сборки находятся в сети. http://community.versant.com/Blogs/db4o/tabid/197/entryid/1057/Default.aspx

...