我在非Ui和ui线程中使用了领域。
将不同的线程作业排队,并通过RealmManager上的活动或片段管理ui线程作业。
始终给出此错误:
例外!消息:此Realm实例已关闭,导致 它不可用。
请帮助我!
Ui线程操作控制器:
RealmManager:
public class RealmManager {
private static String TAG = RealmManager.class.getSimpleName();
private static final ThreadLocal<Realm> localRealms = new ThreadLocal<>();
private static Monarchy monarchy;
private static Monarchy.Builder monarchyBuilder;
public static Monarchy getMonarchy() {
checkDefaultConfiguration();
if (monarchy == null) {
monarchy = new Monarchy.Builder()
.setRealmConfiguration(Realm.getDefaultConfiguration())
.build();
}
return monarchy;
}
public static Monarchy.Builder getMonarchyBuilder() {
checkDefaultConfiguration();
if (monarchyBuilder == null) {
monarchyBuilder = new Monarchy.Builder();
}
return monarchyBuilder;
}
public static Realm open() {
checkDefaultConfiguration();
Realm realm = Realm.getDefaultInstance();
if (checkRealm(realm)) {
localRealms.set(realm);
}
Mylog.i(TAG, " open Realm.getDefaultInstance() realm:" + realm + localRealms);
return realm;
}
public static Realm getLocalInstance() {
checkDefaultConfiguration();
Realm realm = localRealms.get();
Mylog.i(TAG, " getLocalInstance localRealms.get() realm:" + realm);
if (!checkRealm(realm)) {
return open();
}
return realm;
}
public static void close() {
Realm realm = localRealms.get();
Mylog.i(TAG, " close localRealms.get realm:" + realm);
close(realm);
}
public static void close(Realm realm) {
Mylog.i(TAG, " close realm:" + realm);
checkDefaultConfiguration();
if (!checkRealm(realm)) {
return;
}
realm.close();
controlLocalInstanceCount();
}
public static void checkDefaultConfiguration() {
if (Realm.getDefaultConfiguration() == null) {
new RealmEncryptionHelper().setDefaultConfiguration();
}
}
public static boolean checkRealm(Realm realm) {
return realm != null && !realm.isClosed();
}
private static void controlLocalInstanceCount() {
// noinspection ConstantConditions
Mylog.i(TAG, " controlLocalInstanceCount:" + Realm.getLocalInstanceCount(Realm.getDefaultConfiguration()));
// noinspection ConstantConditions
if (Realm.getLocalInstanceCount(Realm.getDefaultConfiguration()) <= 0) {
localRealms.set(null);
}
}
}
主要活动的使用情况:
onCreate(){
realm = RealmManager.open();
}
onDestroy(){
RealmManager.close(realm);
}
另一种线程用法:
RealmRunnable realmRunnable = new RealmRunnable() {
@Override
public void run() {
Realm mRealm = getRealm();
//realm operations for non-ui thread
}
};
getRealmController().addRealmRunnable(realmRunnable);
答案 0 :(得分:0)
private ConcurrentLinkedQueue<RealmRunnable> runnableConcurrentLinkedQueue = new ConcurrentLinkedQueue<>(); private Thread realmThread; realmThread = new Thread(new Runnable() { Realm realm; @Override public void run() { while (!realmThread.isInterrupted()) { if (runnableConcurrentLinkedQueue.isEmpty()) { synchronized (realmThreadLock) { if (runnableConcurrentLinkedQueue.isEmpty()) {
与可序列化的可运行执行管理相关的所有事情都可以用一行完成:
Executor singleThreadedExecutor = Executors.newSingleThreadedPool();
但是,这假定您发布可运行文件时,需要打开/关闭Realm。
singleThreadedExecutor.post(new Runnable() {
@Override public void run() {
try {
realmManager.openLocalInstance();
// do whatever
} finally {
realmManager.closeLocalInstance();
}
}
});
打开Realm,这当然也可以:
singleThreadedExecutor.post(new Runnable() {
@Override public void run() {
try(Realm realm = Realm.getDefaultInstance()) {
// do whatever, but you have to pass Realm around instead of `getLocalInstance()`
}
// realm is closed here
}
});
如果您希望每个可运行的生命周期都自动进行管理,以使Realm在后台线程上以realmManager.getLocalInstance()
打开,而无需您自己手动打开它,那么您需要做得更深入。请注意,我是第一次在这里编写它,因此在这方面有点理论化。
无论如何,您都需要扩展ThreadPoolExecutor
并定义protected void beforeExecute(Thread t, Runnable r)
和protected void after(Thread t, Runnable r)
。看起来像这样:
public class RealmThreadPoolExecutor extends ThreadPoolExecutor {
private final RealmManager realmManager;
public RealmThreadPoolExecutor(RealmManager realmManager) {
super(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); // from newSingleThreadedPool
this.realmManager = realmManager;
}
@Override protected void beforeExecute(Thread thread, Runnable runnable) {
super.beforeExecute(thread, runnable);
realmManager.openLocalInstance();
realmManager.getLocalInstance().refresh();
}
@Override protected void afterExecute(Thread thread, Runnable runnable) {
super.afterExecute(thread, runnable);
realmManager.closeLocalInstance();
}
}
然后,您将执行以下操作,而不是亲自管理可运行的执行:
private final Executor realmExecutor = new RealmThreadPoolExecutor(realmManager);
public void addRunnable(Runnable runnable) {
realmExecutor.execute(runnable);
}
,它应该与您所做的等效。除了代替RealmRunnable
和setRealm
之外,您将呼叫realmManager.getLocalInstance()
。
顺便说一句,get
不应该打开一个Realm,如果您需要在其中打开一个Realm,那么这意味着生命周期管理是错误的,您应该事先打开它,因此它只是隐藏了错误。
从技术上讲,您也选择使用Monarchy而不是使用自己的手动线程本地缓存(尽管我个人不确定是否同时需要两者...),这意味着您会只需在monarchy.doWithRealm(new RealmBlock() {
内执行逻辑即可以“单一方式”使用Realm。
@Override public void run() {
monarchy.doWithRealm((realm) -> {
// realm is open here
});
// realm is closed here
}
君主制不会直接公开open/close
,因为人们从不关闭领域(我知道我已经在这里住了一段时间了),所以此代码禁止他们这样做。除非他们在某个地方手动调用Realm.getDefaultInstance()
,否则Monarchy会在不需要时保持Realm关闭。 好处在这里是,如果您要进行交易,则可以这样做:
monarchy.runTransactionSync((realm) -> {
// do transaction. Realm is opened by config automatically.
});
// realm is closed here.
最重要的是,通过Monarchy,所有UI线程查询都通过LiveData公开,其中至少有1个订阅者打开了Realm,而有0个订阅者关闭了Realm-因此,在UI线程上,管理Realm生命周期您对Realm查询的订阅会自动进行。如果没有观察者,那么Realm将关闭。
LiveData<List<RealmDog>> dogs;
Observer<List<RealmDog>> observer = dogs -> {
adapter.updateData(dogs);
};
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ButterKnife.bind(this, view);
...
dogs = monarchy.findAllCopiedWithChanges(realm -> realm.where(RealmDog.class));
dogs.observeForever(observer);
}
@Override
public void onDestroyView() {
dogs.removeObserver(observer);
super.onDestroyView();
}
无论选择哪种路径,都可能只需要删除该RealmController
,就不需要它。