2011-12-20 6 views
3

db4o 데이터베이스를 만들 때 기본적으로 일부 네트워크 API가 사용되므로 Android 3.0 이상에서 db4o에 문제가 있습니다. (나는이 게시물을 우연히 발견했다 : http://mavistechchannel.wordpress.com/2011/11/18/db4o-at-honeycomb-and-ice-cream-sandwich/ 그것에 대해)Android 3.0 이상의 db4o 문제

그러나 나는 db 생성 요청을 비동기 적으로 만들려고 시도했다. 그러나 완전히 잠기기 전에 db를 호출하는 문제에 부딪혔다. 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 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

업데이트 :이 db4o bug has been fixed 여기 내 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

+0

도움을 주셔서 감사합니다. 정확히 이것을 따르지는 않았지만 충분히 가깝습니다. 이것은 조금 실망 스럽습니다.하지만 잘해야합니다. – Hosemeyer

1

이 문제를 게시 해 주셔서 감사합니다. 이것은 Android의 진지한 재미입니다. 새로운 db4o 데이터베이스 파일이 생성되면 db4o는 java.net.InetAddress.getLocalHost(). getHostName()을 호출하여 고유 한 내부 서명을 생성합니다. 이 호출에서는 예외가 발견되지 않습니다. 이 문제가 해결되면 Android에 대한 해결 방법을 찾고 여기 및 포럼에 게시합니다.

업데이트 : 2012 년 2 월 9 일 : 이 문제는 해결되었으며 새 빌드는 온라인 상태입니다. http://community.versant.com/Blogs/db4o/tabid/197/entryid/1057/Default.aspx