非UI线程的领域用法

时间:2018-07-18 18:11:40

标签: android multithreading realm

我在非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);

1 个答案:

答案 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);
}

,它应该与您所做的等效。除了代替RealmRunnablesetRealm之外,您将呼叫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线程上,管理R​​ealm生命周期您对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,就不需要它。