1

私は GreenDAO ORM を使用して Android アプリケーションを作成しており、その上に一般化されたクラッド サービス レイヤーがあります。DaoMaster と SQLiteDatabase への静的参照を保持するこの単一のファイルがあります。

public class DATABASE {
    private static final String TAG = "DATABASE";
    private static SQLiteDatabase db;
    private static DaoMaster.DevOpenHelper helper;
    private static DaoMaster master;

    public static void Initialize(Context context){
        GetHelper(context);
        GetDatabase();
        GetMaster();
    }

    private static DaoMaster.DevOpenHelper GetHelper(Context context){
        if(helper == null){
            Log.d(TAG, "Helper = null");
            helper =  new DaoMaster.DevOpenHelper(context, Constants.DATABASE_NAME, null);
        }
        return helper;
    }

    private static SQLiteDatabase GetDatabase(){
        if(db == null){
            Log.d(TAG, "Database = null");
            db = helper.getWritableDatabase();
        }
        return db;
    }

    private static DaoMaster GetMaster(){
        GetDatabase();
        if(master == null){
            Log.d(TAG, "Master = null");
            master = new DaoMaster(db);
        }
        return master;
    }

    public static DaoSession GetSession(){
        GetMaster();
        return master.newSession();
    }

    public static void CloseDatabase(){
        try{
            helper.close();
            db = null;
            master = null;
        } catch(Exception e){
            Log.d(TAG, "Failed to close database");
        }
    }
}

アプリを起動したら、DATABASE.Initialize() を呼び出し、メインのアクティビティが破棄されたら、DATABASE.CloseDatabase() を呼び出します。アプリが最初に起動すると、最初の同期が実行され、取得されたエンティティがそれぞれの Crud サービス インスタンスを介して送信されます。これは、それぞれの DAO を処理して、エンティティをこのデータベースに永続化します。

public class CrudService<T> {
    private Class<?> _dtoType;
    private Class<T> _entityType;
    private AbstractDao<T, ?> dao;
    private Method _updateMethod;
    private DaoSession session;

    public CrudService(Class<T> entityType){
        _entityType = entityType;
        _dtoType = DtoMapping.getDtoType(entityType); //This gets a dto for the specified entityType via a HashMap - ie: blah -> blahDto

        if(_dtoType != null){
            try {
                _updateMethod = _entityType.getMethod("update", _dtoType); //This finds blah.java's update method that takes in a blahDto as a param - it must be there or you catch
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }

        session = DATABASE.GetSession();
        dao = (AbstractDao<T,?>) session.getDao(entityType);
    }

    public void Insert(T t){
        dao.insertInTx(t);
    }

    public void InsertOrReplace(T t){
        dao.insertOrReplaceInTx(t);
    }

    public void Update(T t){
        dao.update(t);
    }

    public void Delete(T t){
        dao.deleteInTx(t);
    }
    (etc)
}

ただし、定期的な同期では、アプリが実行されていないときでも、このデータベースにアクセスする必要があります。いくつかの同期はかなり頻繁に実行されます。同期が実行されると、同期から呼び出されるクラスで DATABASE.Initialize() を呼び出しますが、最初の Crud サービス クエリに到達すると、次のエラーが発生します。

01-24 18:10:55.304: WARN/System.err(7068): java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/data/com.example.app/databases/database
01-24 18:10:55.304: WARN/System.err(7068): at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55)
01-24 18:10:55.304: WARN/System.err(7068): at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1310)
01-24 18:10:55.304: WARN/System.err(7068): at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1253)
01-24 18:10:55.304: WARN/System.err(7068): at de.greenrobot.dao.Query.unique(Query.java:131)
(the rest is where the crud service attempts to query the database and originates in the sync service - omitted for certain reasons)

誰かが私が間違っていることを理解するのを手伝ってくれるなら、それは大歓迎です。私は基本的に2つのことを知る必要があります:

1) DATABASE.java の変数は静的であるため、GC が実行されるまでキャッシュされます。GC またはおそらく finalize() を呼び出すことができますか? それとも、CloseDatabase() でそれらを null に設定する必要がありますか?

2) 同期はデータベースに依存しているため、データベースを閉じることもできますか? 閉じないと、リークが発生しませんか?

前もって感謝します。

編集:私は周りを見回して、静的変数が実際にはGCが実行されるまで持続することを学びました。というわけで、#1 を書き換えました。

EDIT 2:その後、DATABASE.java とその Initialize メソッドへの呼び出しを更新して、アプリケーション コンテキストを使用するようにしましたが、問題が解決したようです。同期が再実行されると、最初のcrudサービスクエリでNullPointerExceptionが発生します。

編集 3: null ポインター例外が修正されました。誤って新しいデータベースを開いてしまい、そこにエンティティが存在しませんでした。

4

1 に答える 1

1

DaoSession オブジェクトを Application スコープに保持することを検討する必要があります。それは物事を単純化します。

greendao の OpenHelper コンストラクターに正しいコンテキストを渡す

https://stackoverflow.com/a/14430803/551269

PS .: CrudService は DaoSession に少し似ています。

于 2013-01-25T20:30:51.117 に答える