【问题标题】:Replacing global variable and synchronized block with realm用领域替换全局变量和同步块
【发布时间】:2017-04-19 10:13:47
【问题描述】:

我重新表述了这个问题,以免让人们对我真正在做什么感到困惑。原始问题中使用的示例过于简化。

我的项目是基于客户端/服务器的。安卓应用程序是客户端。为了适当地简化这种情况,我们可以考虑一下我有两个意图/活动和一个后台线程。活动 A 是登录。 Activity B 是应用程序的其余部分所在的位置。后台线程是socket线程,需要一直保持到用户退出应用,或者网络连接中断。

实现了一个状态机来处理应用程序状态,所有活动和套接字线程都需要这个状态机。

Singleton 很容易满足我的设计要求,但是会有很多同步阻塞和等待语句。我想知道是否可以使用领域来实现相同的目标


原始问题

我是 Realm Java (Android) 开发的新手。在我当前的代码中,我有一堆全局变量,并在几个 AsyncTask 或后台线程中使用它们。

我将在这里使用一些代码来演示我的示例

//Class holding global variable
public class GlobalInfo{
    public static String info;
}

//Class changing the global variable
class A{
    void doSomething(){
        String info = GlobalInfo.info;
        info = "start";
        synchronized(info){                
            ...... //do something
            info = "done";
            info.notifyAll();
        }
    }
}

//background thread waiting for info to be "done". Neglecting the class holding it
void doSomethingAfterDone(){
    String info = GlobalInfo.info;
    synchronized(info){                
        while(!info.Equals("done")){
            info.wait();
        }
        //do something
    }
}

假设在调用doSomethingAfterDone() 时,方法doSomething() 仍在运行。因此,doSomethingAfterDone() 将在退出while 循环之前等待doSomething() 通知。

是否可以使用 Realm 来替换它们?例如,使用领域事务+等待更改的侦听器,而不是在全局变量上应用同步块并等待其通知?

我发现Realm.waitForChange() 会阻止执行,直到对其进行更改。但是,是否所有适用于注册或复制到领域的对象的所有更改都针对此语句返回 true,而不管更改了什么?

我知道我可以在意图之间传递字符串,但我想知道领域是否可以完成这项工作。

【问题讨论】:

  • 嗯,你绝对可以用对 Realm 的写入来替换对全局 String 的写入,然后监听 Realm 中的变化。很长一段时间以来,除了检查进程死亡之外,我还没有一个全局变量。就个人而言,我看不到您需要不断循环并侦听全局变量的“守护线程”——当您将done 设置为true 时,您可以运行该任务。
  • 您发布的代码示例并没有真正使用 Realm,但是如果 info 是 RealmObject 您正在设置某个字段,那么我肯定会使用 RealmChangeListener。侦听器将触发当前相同类型对象的所有更改,但在您继续之前是否应该“完成”有效应该很容易检查。
  • @Joe 我认为如果套接字线程是设置为自动更新的活套线程,这在理论上是可能的。但是我从来没有真正尝试过设置一个循环器并在没有打开的活动时终止它。您最好的选择是研究 HandlerThread。
  • 非常感谢@EpicPandaForce

标签: android concurrency realm synchronized


【解决方案1】:

好吧,您通常根本不需要全局变量。您可以在后台线程上写入 Realm,并在 UI 线程上监听变化。

//Class holding global variable
//public class GlobalInfo{
    //public static String info;
//}

//Class changing the global variable
class A{
    void doSomething(){
        //String info = GlobalInfo.info;
        //info = "start";
        //synchronized(info){                
        try(Realm realm = Realm.getDefaultInstance()) {
            realm.executeTransaction(new Realm.Transaction() { // assuming background thread
                @Override
                public void execute(Realm realm) {
                    //!! do something with Realm
                }
            });
        }
        new Thread(new Runnable() { // could be merged to this background thread
            @Override
            public void run() {
               doSomethingAfterDone();
            }
        }).start();
            //info = "done";
            //info.notifyAll();
        //}
    }
}

//background thread waiting for info to be "done". Neglecting the class holding it
void doSomethingAfterDone(){
    //String info = GlobalInfo.info;
    //synchronized(info){                
        //while(!info.Equals("done")){
        //    info.wait();
        //}
        try(Realm realm = Realm.getDefaultInstance()) {
            realm.executeTransaction(new Realm.Transaction() {
                @Override
                public void execute(Realm realm) {
                    //do something
                }
            });
        }
    //}
}

【讨论】:

  • 感谢您的回复,但我认为您写的不是我的意思。 doSomethingAfterDone 在一个完全独立的类和线程中。两个线程都引用相同的 stringz 并且它们根据不同的状态更新/侦听相同的字符串。考虑一个异步任务线程和一个后台线程,以及一个状态机:用户单击某物,因此异步任务得到通知,更新状态并等待。后台线程获取新状态,执行一些逻辑并再次更改状态。然后通知异步任务后台线程完成,并更新 GUI
  • 我知道如果后台线程是从同一个 GUI 或异步任务线程启动的,我可以通过这个状态机,但是如果我在切换到新的意图/活动时仍然需要后台线程怎么办,并且新的 GUI 线程也需要这个状态机?
  • 虽然有可能,但我也认为这听起来有些过度设计。
  • 我更新了我的问题,请您看看好吗?谢谢。
猜你喜欢
  • 2018-10-20
  • 1970-01-01
  • 2023-03-19
  • 2011-01-18
  • 1970-01-01
  • 1970-01-01
  • 2016-10-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多