Закройте все локальные экземпляры Realm

У меня проблема с закрытым экземпляром Realm. Я использую ThreadPoolExecutor для многопоточности, и каждый поток использует собственный экземпляр Realm. Я вызываю Realm.getDefaultInstance() перед каждой операцией с Realm. И каждый раз, когда я обращаюсь к Realm, я получаю старые данные, потому что каждый раз я обращаюсь к Realm из разных потоков.

Я просмотрел источники Realm и увидел 33 локальных ссылки на Realm. Когда я вызываю Realm.getDefaultInstance().close(), а затем проверяю, закрыт ли объект, я получаю false. Но сейчас у меня 32 ссылки. Как я могу закрыть все экземпляры Realm, которые сбрасывают кеш памяти и извлекают фактические данные?


person Nikolay Kucheriaviy    schedule 19.04.2017    source источник
comment
Я вызываю Realm.getDefaultInstance() перед каждой операцией почему? Вероятно, вам следует сделать это только один раз в потоке. Когда я вызываю Realm.getDefaultInstance().close(), а затем проверяю, что объект закрыт, я получаю false. что не закрывает текущую область. Вы действительно должны прочитать документацию, чтобы понять, как управлять жизненным циклом области.   -  person Tim    schedule 19.04.2017
comment
Поскольку каждый экземпляр Realm, полученный с помощью Realm.getDefaultInstance(), должен быть связан с realm.close(), прочтите realm.io/docs/java/latest/   -  person EpicPandaForce    schedule 19.04.2017
comment
Хорошо, но я проверяю хэш-код для объекта Realm, который используется в одном потоке, каждый экземпляр, полученный после Realm.getDefaultInstance(), имеет одинаковый хэш-код. Почему Realm возвращает новый локальный экземпляр после getDefaultInstance(), а не глобальный экземпляр для текущего потока? Мне нужно закрыть каждый локальный экземпляр Realm? Я могу как-то закрыть все локальные экземпляры?   -  person Nikolay Kucheriaviy    schedule 19.04.2017
comment
Конечно, чтобы легко разрешить открытие Realms в onCreate() и закрытие их в onDestroy() для потока пользовательского интерфейса. Если бы вы закрыли какое-либо действие и все области в потоке пользовательского интерфейса были признаны недействительными, это было бы очень плохо, не так ли? :п   -  person EpicPandaForce    schedule 19.04.2017
comment
I need close every local instance of Realm? это обычно легко, потому что каждый фоновый поток должен иметь только 1 локальный экземпляр, полученный с помощью try(Realm realm = Realm.getDefaultInstance()) { ... }, упаковывающий время жизни потока, и передаваемый методам в качестве аргумента.   -  person EpicPandaForce    schedule 19.04.2017
comment
Ах, отслеживание ваших собственных локальных экземпляров потока тоже работает.   -  person EpicPandaForce    schedule 19.04.2017
comment
Если вы нашли решение, опубликуйте его как ответ!   -  person Tim    schedule 19.04.2017
comment
У меня более сложная структура, каждый метод, который работал с Realm, вызывает Realm.getDefaultInstance(), и когда я проверил количество локальных ссылок с помощью Realm.getLocalInstanceCount(...), я получил 33 ссылки, но только 3 глобальных экземпляра, потому что мой пул потоков имеет 3 потока, это правильно (количество глобальных экземпляров).   -  person Nikolay Kucheriaviy    schedule 19.04.2017
comment
@TimCastelijns хорошо.   -  person Nikolay Kucheriaviy    schedule 19.04.2017


Ответы (1)


Я решил свою проблему, написал RealmManager, вместо Realm.getDefaultInstance() использую RealmManager.getInstance(). Больше не нужно звонить realm.close() после каждого Realm.getDefaultInstance()

RealmManager:

import android.util.LongSparseArray;

import io.realm.Realm;

public class RealmManager {
    private volatile static LongSparseArray<Realm> THREAD_INSTANCES = new LongSparseArray<>();

    public static Realm getInstance() {
        final long threadId = Thread.currentThread().getId();

        if (THREAD_INSTANCES.indexOfKey(threadId) >= 0) {
            Realm instance = THREAD_INSTANCES.get(threadId);

            if (instance == null || instance.isClosed()) {
                instance = Realm.getDefaultInstance();

                THREAD_INSTANCES.put(threadId, instance);
            }

            return instance;
        } else {
            Realm instance = Realm.getDefaultInstance();
            THREAD_INSTANCES.put(threadId, instance);

            return instance;
        }
    }

    public static void closeInstance() {
        long threadId = Thread.currentThread().getId();

        if (THREAD_INSTANCES.indexOfKey(threadId) >= 0) {
            Realm instance = THREAD_INSTANCES.get(threadId);

            if (instance == null || instance.isClosed()) {
                THREAD_INSTANCES.remove(threadId);
            } else {
                instance.close();
                instance = null;

                THREAD_INSTANCES.remove(threadId);
            }
        }
    }
}

Мой исполнитель работы:

public class JobExecutor implements Executor {
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
    private final java.util.concurrent.ExecutorService mThreadPoolExecutor;
    private final DiskDataSource mDiskDataSource;

    public JobExecutor(DiskDataSource diskDataSource) {
        mDiskDataSource = diskDataSource;
        mThreadPoolExecutor = Executors.newFixedThreadPool(CORE_POOL_SIZE, new JobThreadFactory());
    }

    @Override
    public void execute(@NonNull Runnable runnable) {
        mThreadPoolExecutor.execute(new RealmRunnable(mDiskDataSource, runnable));
    }

    private static class JobThreadFactory implements ThreadFactory {
        private static final String THREAD_NAME = "android_";
        private int counter = 0;
        @Override
        public Thread newThread(@NonNull Runnable runnable) {
            return new Thread(runnable, THREAD_NAME + counter++);
        }
    }
}

RealmRunnable:

public class RealmRunnable implements Runnable {
    private Runnable mOrigRunnable;
    private DiskDataSource mDiskDataSource;

    public RealmRunnable(DiskDataSource diskDataSource, Runnable origRunnable) {
        mDiskDataSource = diskDataSource;
        mOrigRunnable = origRunnable;
    }

    @Override
    public void run() {
        try {
            mOrigRunnable.run();
        } finally {
            mDiskDataSource.closeDatabaseInstance();
        }
    }
}

Внутри DiskDataSource я использую RealmManager

person Nikolay Kucheriaviy    schedule 19.04.2017