代码之家  ›  专栏  ›  技术社区  ›  propoLis

非ui线程的领域使用

  •  0
  • propoLis  · 技术社区  · 7 年前

    我已经在非ui和ui线程中使用了realm。

    不同的线程作业被排队,ui线程作业在创建ondestroy并使用realmanager时从活动或片段进行管理。

    总是出现此错误:

    例外!消息:此领域实例已关闭,使 它不可用。

    请帮帮我!

    UI线程操作控制器:

    管理器:

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

    main上的活动用法:

    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 回复  |  直到 7 年前
        1
  •  0
  •   EpicPandaForce Jigar Joshi    7 年前
        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();
    

    然而,这将假设每当您发布runnable时,您需要打开/关闭领域。

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

    如果您希望每个可运行的自动生命周期管理,以便域使用 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 ,你会打电话给 realmanager.getLocalInstance() 是的。

    顺便说一句, get 不应该打开一个领域,如果你需要在那里打开一个领域,那么这意味着生命周期管理是错误的,你应该已经打开它之前,所以它只是隐藏错误。


    严格地说你 选择使用君主制而不是使用您自己的手动线程本地缓存(虽然我个人不确定您是否同时需要这两个…),这意味着您将以“单一方式”使用realm,只需在 monarchy.doWithRealm(new RealmBlock() { 是的。

    @Override public void run() {
        monarchy.doWithRealm((realm) -> {
            // realm is open here
        });
        // realm is closed here
    }
    

    君主制不会暴露 open/close 直接因为人们 永不关闭王国 (我知道,我在这里已经有一段时间了)所以这个街区不允许他们这么做。除非他们手动呼叫 Realm.getDefaultInstance() 在某些地方,君主制会在不需要的时候关闭王国。这个 利益 如果您想要交易,请执行以下操作:

    monarchy.runTransactionSync((realm) -> {
        // do transaction. Realm is opened by config automatically.
    });
    // realm is closed here.
    

    最重要的是,通过君主制,ui线程查询都通过livedata公开,其中至少有一个订阅者打开领域,而有0个订阅者关闭领域——因此在ui线程上,领域生命周期由您对领域查询的订阅自动管理。如果没有观察者,那么领域是关闭的。

    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 ,你不需要它。