Android中的全局领域实例

时间:2017-10-24 19:21:18

标签: android realm

(我已经看过其他帖子,但他们有点过时,主要是引用领域1.x)

一直在寻找在我们的应用程序中建立领域的最佳方式。我们目前到处都是,并希望集中我们的领域实例。

在这个链接(https://medium.com/@Zhuinden/basics-of-realm-a-guide-to-using-realm-1-2-0-634471c0fe8f)中,我发现我认为这是一个伟大的全球实施,但我有2个问题:

1。这仍然适用于当前版本的域(目前为4.1)吗?

2。保留片段的目的是什么?可以在没有片段的情况下完成吗?

提前致谢!

以下链接中的相关部分:

  

- 制作全球Realm实例

     

我在我的活动中设置了一个保留的片段,它会增加当前活动的>活动计数。打开   领域如果计数器从0变为1.如果计数器关闭领域   从1到0。

import android.content.Context;
import android.util.Log;

import io.realm.Realm;
import io.realm.RealmConfiguration;

/**
 * Created by Zhuinden on 2016.08.16..
 */
public class RealmManager {
    static Realm realm;

    static RealmConfiguration realmConfiguration;

    public static void initializeRealmConfig(Context appContext) {
        if(realmConfiguration == null) {
            setRealmConfiguration(new RealmConfiguration.Builder(appContext)
                    .deleteRealmIfMigrationNeeded()
                    .build());
        }
    }

    public static void setRealmConfiguration(RealmConfiguration realmConfiguration) {
        RealmManager.realmConfiguration = realmConfiguration;
        Realm.setDefaultConfiguration(realmConfiguration);
    }

    private static int activityCount = 0;

    public static Realm getRealm() {
        return realm;
    }

    public static void incrementCount() {
        if(activityCount == 0) {
            if(realm != null) {
                if(!realm.isClosed()) {
                    realm.close();
                }
            }
            realm = Realm.getDefaultInstance();
        }
        activityCount++;
    }

    public static void decrementCount() {
        activityCount--;
        if(activityCount <= 0) {
            activityCount = 0;
            realm.close();
            Realm.compactRealm(realmConfiguration);
            realm = null;
        }
    }
}
  

setRealmConfiguration()方法是可以替换的   使用配置的测试测试的默认配置   inMemory()境界。如果您使用此功能,则可以轻松计算活动   使用保留片段的引用!

public class BooksScopeListener extends Fragment { // could go to base class
    public BooksScopeListener() {
        setRetainInstance(true);
        RealmManager.incrementCount();
    }

    @Override
    public void onDestroy() {
        RealmManager.decrementCount();
        super.onDestroy();
    }
}

public class BooksActivity extends AppCompatActivity {
    Realm realm;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        RealmManager.initializeRealmConfig(getApplicationContext()); // could go to base class
        super.onCreate(savedInstanceState);
        BooksScopeListener fragment = (BooksScopeListener) getSupportFragmentManager().findFragmentByTag("SCOPE_LISTENER"); // could go to base class
        if(fragment == null) {
            fragment = new BooksScopeListener();
            getSupportFragmentManager().beginTransaction().add(fragment, "SCOPE_LISTENER").commit();
        }
        //get realm instance
        realm = RealmManager.getRealm();
  

Ta-dah,现在您可以随意访问RealmManager.getRealm()   UI线程。或者只是@Inject从一个模块。 (别忘了   每个活动或片段的范围方法也有效,我更喜欢   这个是因为我在@Subcomponents上使用了@Singleton组件。

1 个答案:

答案 0 :(得分:2)

我在大约一年前写过那篇文章,虽然这为 UI线程创建了一个全局Realm,但你无法在任何线程上使用它。如果你在后台线程上打开/关闭Realm,你仍然需要传递Realm作为方法参数。

  
      
  1. 这是否仍然适用于当前版本的领域(目前为4.1)?
  2.   

领域生命周期管理仍然是您需要做的事情,即使对于4.1.0也是如此,就像在1.2.0中一样。这是一件从未改变过的事情:)

  
      
  1. 保留片段的目的是什么?可以在没有片段的情况下完成吗?
  2.   

添加保留的片段,这样您就不会因为旋转屏幕而关闭/重新打开Realm;最近你可以使用ViewModel的构造函数+ onCleared()方法执行此操作。

我刚刚发现保留的片段是最值得信赖的监听生命周期的方式,而不会改变生命周期回调的配置变化。

本文中显示的RealmManager仅负责UI线程上的自动生命周期管理。如果在UI线程上使用,它仍然可以正常工作。事实上,无论如何,对于UI线程,这仍然是我在下面的例子中打开/关闭的地方。

如果你想要跨线程的Realm的单例管理器类,一个起点就是使用下面的类(一点概念证明,因为我还没有在生产中使用它,但是嘿):

public class RealmManager {
    private final ThreadLocal<Realm> localRealms = new ThreadLocal<>();


    /**
     * Opens a reference-counted local Realm instance.
     *
     * @return the open Realm instance
     */
    public Realm open() {
        checkDefaultConfiguration();
        Realm realm = Realm.getDefaultInstance(); 
        if(localRealms.get() == null) {
            localRealms.set(realm);
        }
        return realm;
    }

    /**
     * Returns the local Realm instance without adding to the reference count.
     *
     * @return the local Realm instance
     * @throws IllegalStateException when no Realm is open
     */
    public Realm get() {
        Realm realm = localRealms.get();
        if(realm == null) {
            throw new IllegalStateException(
                    "No open Realms were found on this thread.");
        }
        return realm;
    }

    /**
     * Closes local Realm instance, decrementing the reference count.
     *
     * @throws IllegalStateException if there is no open Realm.
     */
    public void close() {
        checkDefaultConfiguration();
        Realm realm = localRealms.get();
        if(realm == null) {
            throw new IllegalStateException(
                    "Cannot close a Realm that is not open.");
        }
        realm.close();
        // noinspection ConstantConditions
        if(Realm.getLocalInstanceCount(Realm.getDefaultConfiguration()) <= 0) {
            localRealms.set(null);
        }
    }
}

这种方式实际上可以使用RealmManager类作为@Provides @Singleton RealmManager realmManager()提供的单一入口点,并从open()分离get(),从而允许您使用开放给定线程的Realm实例(如果它已经打开),没有永远无法关闭它的风险(因为在没有Realm.getDefaultInstance()对的情况下调用close())。

然后对于后台线程,您将使用

try {
    realmManager.open();
    ...
} finally {
    realmManager.close();
}

在其他方法中你可以做到

Realm realm = realmManager.get();

对于UI线程,您可以像往常一样使用保留的片段(或Activity / Fragment onCreate() / onDestroy()),但也使用open/close

通过这种方式,您可以在一个地方管理Realm生命周期,但仍然将Realm作为线程局部变量传递,而不是全局传递(由于Realm实例是线程限制的,因此无法工作)。