【问题标题】:Have I implemented EpicPandaForce's RealmManager correctly?我是否正确实现了 EpicPandaForce 的 RealmManager?
【发布时间】:2017-12-16 06:28:16
【问题描述】:

我是 Realm(和 Android 开发)的新手,我想使用 Singleton 类来简化 Realm 数据管理,以便我的朋友更容易在我们的小组项目中使用。

EpicPandaForce 编写了一个名为 RealmManager here 的单例类,但我找不到实现它的示例,所以这是我尝试过的:

public class RealmManager {
    private static RealmManager instance;
    private final ThreadLocal<Realm> localRealm = new ThreadLocal<>();

    RealmManager(){}

    public synchronized static RealmManager getInstance(){
        if(instance == null){
            instance = new RealmManager();
        }
        return instance;
    }

    public Realm openLocalInstance() {
        Realm realm = Realm.getDefaultInstance();
        if(localRealm.get() == null) {
            localRealm.set(realm);
        }
        return realm;
    }

    public Realm getLocalInstance() {
        Realm realm = localRealm.get();
        if(realm == null) {
            throw new IllegalStateException("No open Realms were found on this thread.");
        }
        return realm;
    }

    public void closeLocalInstance() {
        Realm realm = localRealm.get();
        if(realm == null) {
            throw new IllegalStateException(
                "Cannot close a Realm that is not open.");
        }
        realm.close();
        if(Realm.getLocalInstanceCount(Realm.getDefaultConfiguration()) <= 0) {
        localRealm.set(null);
        }
    }

    public void storePreferenceDao(int userID, String rank){
        final PreferenceDao preferenceDao = new PreferenceDao();
        preferenceDao.setUserID(userID);
        preferenceDao.setRank(rank);
        openLocalInstance();
        getLocalInstance().executeTransactionAsync(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                realm.copyToRealmOrUpdate(preferenceDao);
            }
        }, new Realm.Transaction.OnSuccess(){
            @Override
            public void onSuccess(){
                System.out.println("Data is stored successfully!");
            }
        }, new Realm.Transaction.OnError(){
            @Override
            public void onError(Throwable error){
                System.out.println("There is an error in storePreferenceDao()");
            }
        });
        closeLocalInstance();
    }

所以当我的朋友想要存储一些数据时,他们可以使用:

RealmManager.getInstance().storePreferenceDao(123, "Alpaca");

这是应该如何使用的还是多余的?如何提高效率?

【问题讨论】:

  • RealmManager 类的getInstance() 设为synchronized 以保证线程安全。
  • @vinS 不,我希望在我的应用程序中实现 EpicPandaForce 的 RealmManager 类,但我在任何地方都找不到任何示例。
  • @Chithra 注意!谢谢。我现在将对其进行编辑。
  • 我重新打开了这个,因为这不是重复的......

标签: java android realm


【解决方案1】:

其实在这种情况下,该方法仍然只能从UI线程调用,并且本地实例应该在事务回调中关闭(否则不会调用onSuccess/onError)

如果可以,您可以创建一个能够在 bg 线程上执行的方法,如果已经在 bg 线程上,则可以在当前线程上执行

// method in RealmManager
public final void runTransaction(Realm.Transaction transaction) {
    runTransaction(transaction, null, null);
}

public final void runTransaction(Realm.Transaction transaction, Realm.Transaction.OnSuccess onSuccess) {
    runTransaction(transaction, onSuccess, null);
}

public final void runTransaction(Realm.Transaction transaction, Realm.Transaction.OnSuccess onSuccess, Realm.Transaction.OnError onError) {
    Realm realm = openLocalInstance();
    if(realm.isAutoRefresh()) {
        realm.executeTransactionAsync(transaction, new Realm.Transaction.OnSuccess() {
            @Override
            public void onSuccess() {
                try {
                    if(onSuccess != null) {
                        onSuccess.onSuccess();
                    }
                } finally {
                    closeLocalInstance();
                }
            }
        }, new Realm.Transaction.OnError() {
            @Override
            public void onError(Throwable e) {
                try {
                    if(onError != null) {
                        onError.onError(e);
                    }
                } finally {
                    closeLocalInstance();
                }
            }
        });
    } else {
        try {
            realm.executeTransaction(transaction);
            if(onSuccess != null) {
                onSuccess.onSuccess();
            }
        } catch(Exception e) {
            if(onError != null) {
                onError.onError(e);
            }
            throw new RuntimeException(e);
        } finally {
            closeLocalInstance();
        }
    }
}

如果您添加此方法,那么您现在可以执行一个事务,该事务将在可能的情况下通过async 事务方法在后台线程上执行,如果不在循环线程上则使用synchronous 事务方法(f.ex.后台线程)

你现在可以这样做

public void storePreferenceDao(int userID, String rank) {
    final PreferenceDao preferenceDao = new PreferenceDao();
    preferenceDao.setUserID(userID);
    preferenceDao.setRank(rank);
    runTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            realm.copyToRealmOrUpdate(preferenceDao);
        }
    }, new Realm.Transaction.OnSuccess(){
        @Override
        public void onSuccess(){
            System.out.println("Data is stored successfully!");
        }
    }, new Realm.Transaction.OnError(){
        @Override
        public void onError(Throwable error){
            System.out.println("There is an error in storePreferenceDao()");
        }
    });
}

或者只是

public void storePreferenceDao(int userID, String rank) {
    final PreferenceDao preferenceDao = new PreferenceDao();
    preferenceDao.setUserID(userID);
    preferenceDao.setRank(rank);
    runInTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            realm.copyToRealmOrUpdate(preferenceDao);
        }
    });
}

你知道,我一直觉得我应该在该示例中添加一个 runTransaction() 方法。不过,是否应该默认使用executeTransactionAsync(如果可以的话)还有待商榷。

【讨论】:

  • 非常感谢!只是一个问题,storePreferenceDao(int, String) 还会在 RealmManager 类中吗?
  • 您可以,或者您可以将其放入由 RealmManager 创建的自己的类中(并将自身作为构造函数参数提供),类似于 Room 的做法。或者您可以将其设为单例并将 RealmManager 作为构造函数参数,这就是我对 DI 所做的事情
  • 谢谢!我现在要在 RealmManager 中编写所有代码。
  • 另外你在storePreferenceDao() 中使用了runInTransaction() 而不是你给我的runTransaction()
  • 这是一个错字。
【解决方案2】:

一个简单的单例示例,

public class MySingleton {
private static MySingleton sMySingleton;

//private constructor.
private MySingleton() {
    if (sMySingleton != null){
        throw new RuntimeException("Use getInstance() for the instance");
    }
} 

public synchronized static MySingleton getInstance() {
    if (sMySingleton == null){ 
        sMySingleton = new MySingleton();
    }
    return sMySingleton;
}
}

希望对你有帮助!

【讨论】:

    【解决方案3】:

    这可能不是最好的答案,但这里是我如何在我的应用程序中使用领域

    public class BaseActivity extends AppCompatActivity {
    public Realm realm;
      @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_base);
            realm = Realm.getDefaultInstance();
        }
    
    }
    

    根据你的使用在其他Activity中扩展BaseActivity

    public class MainActivity extends BaseActivity {
    
           @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //Here you can directly access realm object and perform your task
            realm.where()//just example
        }
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if(realm!=null)
               realm.close();
           //Don't forget to close realm object
        }
    
    }
    

    我并不是说这是最好的方法,但它是最好的方法之一。使用这种方式,我可以轻松管理我的领域类,并可以减少与领域相关的错误。对于片段,您可以制作 BaseFragment 并在其他片段中扩展它。

    希望这会对您有所帮助...如果您有其他更好的方法,请告诉我

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-02
      • 2021-09-25
      • 1970-01-01
      • 1970-01-01
      • 2012-03-04
      • 2021-12-11
      • 2019-09-08
      • 1970-01-01
      相关资源
      最近更新 更多