如果我在没有关闭开放领域实例的情况下关闭我的Android应用程序会发生什么?

时间:2018-03-31 12:20:12

标签: android realm

我在Application类的主线程上保留了一个realm实例,我使用该单个实例从MainActivity执行各种数据库操作。由于我的应用程序只有一个活动,因此我会关闭活动onDestroy()中的实例。截至目前,该应用程序对我来说还不错。

不做realm.close()会有什么影响?我的数据库没有损坏或没有相同的。

另外,我读过有些情况下可能根本没有调用Activity onDestroy()。如果关闭领域如此重要,数据库可以在这种情况下产生什么影响?

public class MyApp extends Application {

    private static MyApp instance;
    private Realm realm;

    public void onCreate() {
        super.onCreate();
        Realm.init(this);
        Realm.setDefaultConfiguration(new RealmConfiguration.Builder()
                .schemaVersion(BuildConfig.VERSION_CODE)
                .migration(new RealmMigrationClass())
                .compactOnLaunch()
                .build());
        realm = Realm.getInstance(Realm.getDefaultConfiguration());
    }

    public static MyApp getInstance() {
        return instance;
    }

    public Realm getRealm() {
        return realm;
    }
}

MainActivity

public class MainActivity extends Activity {

    @Override
    protected void onDestroy() {
        MyApp.getInstance().getRealm().close();
        super.onDestroy();
    }

}

4 个答案:

答案 0 :(得分:4)

关闭领域实例非常重要,因为领域核心是用c ++编程语言编写的,并且是用本机代码编译的。我们知道c ++垃圾收集不会自动运行,我们需要手动调用垃圾收集。所以当你调用 realm.close()时,这意味着域释放本机内存意味着自由或删除指针变量,也可以执行文件描述符job.From realm.close()表示您发出命令或告诉本机c ++编译器运行垃圾收集。

答案 1 :(得分:1)

Realm实现Closeable以处理本机内存释放和文件描述符,因此在完成它们时总是关闭它们。

Realm实例是引用计数 - 如果你在一个线程中调用两次getInstance,你也需要两次调用close。

根据我个人的经验,没有关闭领域并没有引起很多问题,事实上当我尝试关闭它时,它会在应用程序进入后台时导致问题然后恢复导致由于领域崩溃实例被关闭,我不确定为什么在这种情况下没有创建一个新的域实例,可能是一个bug。

截至目前,我遵循领域文档并关闭我的领域实例,直到它们导致问题。

一般编码实践表明,任何打开的东西都应该安全关闭。

答案 2 :(得分:0)

是的,只有在应用程序的 destroy()方法上调用 close()方法时才会关闭它。记住 Realm实现Closeable 以便处理本机内存释放和文件描述符,因此在完成它们时关闭Realm实例非常重要。

有关详细信息,请访问此link.

答案 3 :(得分:0)

如果您查看Realm for Java的“ doc”(REALM_DOC),则会发现:

  

Realm实现Closeable来处理本机内存释放   和文件描述符,因此,当您   完成了他们。

     

领域实例是按引用计数的—如果您在两次调用getInstance的情况下   一个线程,您还需要调用close两次。这使您能够   实现可运行类,而不必担心哪个线程   将执行它们:只需以getInstance开头并以结束   关闭。

我个人建议您定义一个类,在其中定义您的Realm函数和一个“ Realm属性”(例如“ RealmHelper”类),然后在该类中定义: -静态领域 -静态RealmHelper实例

您将始终使用此RealmHelper静态实例对您的Realm主线程中的所有操作进行操作,在其他线程中,您将在执行操作后立即调用“ new RealmHelper()”并关闭该领域。

在MainThread中执行此操作,您只需要在应用程序关闭时关闭一个领域实例,即可在Custom定义的Application类(扩展Android应用程序)中使用“ Application.ActivityLifecycleCallbacks”接口。

您的应用程序自定义类中的示例:

/* START Override ActivityLifecycleCallbacks Methods */
    @Override
    public void onActivityCreated(Activity activity, Bundle bundle) {
    }

    @Override
    public void onActivityStarted(Activity activity) {
        // Check if your MyRealmClass instance is null or is closed, in this case 
        // re-initialize it.
        if(MyRealmClass.getInstance() == null || MyRealmClass.getInstance().getRealm().isClosed()){
            MyRealmClass.initInstance();
        }
    }

    @Override
    public void onActivityResumed(Activity activity) {

    }

    @Override
    public void onActivityPaused(Activity activity) {

    }

    @Override
    public void onActivityStopped(Activity activity) {
        if(!AppUtils.isAppOnForeground(this)){
            // Close your MyRealmClass instance
            if(MyRealmClass.getInstance() != null) {
                MyRealmClass.getInstance().close();
             MyRealmClass.getInstance().logRealmInstanceCount(LABEL_APP_IN_BACKGROUND);
                MyRealmClass.setMyInstance(null);
            }
        }
    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {

    }

    @Override
    public void onActivityDestroyed(Activity activity) {

    }
    /* END Override ActivityLifecycleCallbacks Methods */

“ isAppOnForeground”的代码(检查您的应用是否位于前台,如果不是,则表示您的应用已关闭):

public static boolean isAppOnForeground(Context context) {
        boolean ret = false;
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
        if(appProcesses != null){
            String packageName = context.getPackageName();
            for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
                if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
                    ret = true;
                }
            }
        }
        return ret;
    }

您的“ MyRealmClass”将如下所示:

public class MyRealmClass {

 protected Realm mRealm;
    protected static MyRealmClass mInstance;

    public MyRealmClass() {
        mRealm = Realm.getDefaultInstance();
    }

    public static MyRealmClass initInstance(){
        if(mInstance == null){
            mInstance = new MyRealmClass();
        }
        return mInstance;
    }

public static MyRealmClass getInstance(){
        return mInstance;
    }

public static void setMyInstance(MyRealmClass instance) {
        mInstance = instance;
    }

public Realm getRealm() {
        return mRealm;
    }

    public void setRealm(Realm realm){
        this.mRealm = realm;
    }

public void close() {
        if (mRealm != null) {
            try {
                mRealm.close();
            } catch(Exception e){
                onException(e);
            }
        }
    }

[...]

然后,当您使用RealmObject或在Realm中执行某些操作时,您需要检查所有Realm实例是否未关闭。如果关闭了该应用程序(因为该应用程序进入后台,然后重新启动),则需要重新初始化该领域(如果您有一个以MyRealmClass实例为属性的活动)。 BaseMyActivity中的示例:

public abstract class MyBaseActivity extends AppCompatActivity {

    protected MyRealmClass mRealmClass;

    /* START Override Lifecycle Methods */
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initMyRealmClass();
        Lyra.instance().restoreState(this, savedInstanceState);
    }

    @Override
    protected void onStart() {
        super.onStart();
        initMyRealmClass();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Lyra.instance().saveState(this, outState);
    }
    /* END Override Lifecycle Methods */

    /* START Private Methods */
    protected void initMyRealmClass(){
        if(mRealmClass == null || mRealmClass.getRealm().isClosed()){
            mRealmClass = MyRealmClass.initInstance();
        }
    }
    /* END Private Methods */

}

基本上,如果您的所有活动都需要使用Realm函数,它们都将扩展此BaseActivity。 (Lyra用于保存任何属性的状态:LYRA

记住:

如果您从RealmObject设置或获取某些属性,或者从RealmList或RealmResults获取对象,则需要从中获取对象的REALM INSTANCE处于打开状态。 否则,当您使用领域中的对象初始化变量时,需要使用此方法:(此方法应放在您的“ MyRealmClass”中)

public <T extends RealmObject> List<T> toList(RealmResults<T> results) {
            return mRealm.copyFromRealm(results);
        }

        public <T extends RealmObject> List<T> toList(RealmList<T> results) {
            return mRealm.copyFromRealm(results);
        }

        public <T extends RealmObject> T copyObjectFromRealm(T obj) {
            return mRealm.copyFromRealm(obj);
        }

    public <T extends RealmObject> RealmResults<T> findAllObject(Class<T> classObject) {
        RealmQuery<T> query = mRealm.where(classObject);
        return query.findAll();
    }

现在,如果您需要获取“ MyRealmObjectClass”对象的列表并将其添加到适配器中,则可以执行以下操作:

List<MyRealmObjectClass> myObjects = mRealmClass.toList(mRealmClass.findAllObject(MyRealmObjectClass.class))
myAdapter.addAll(myObjects);

如果您在从中获取对象的Realm实例关闭后(例如,应用程序进入后台然后重新启动之后),则在“获取”或“设置”属性时执行此操作,则不会出现异常。 但是,如果您“设置”了RealmObject的属性,则不会在REALM INSTANCE中进行设置,因此在这种情况下要更改RealmObject在Realm中的值,您需要保存该对象! 否则,如果您仍有RealmResults或RealmObject仍连接到Realm,则可以在事务内部直接更改其属性,并且它也将在Realm内部更改。 要进行领域交易,我建议您遵循第一个链接中的DOC,如果不需要在Final块中关闭领域,请启用lambda并执行以下操作:

mRealm.executeTransaction(
    realm -> {
        [do your Realm operations]
    }
)

或者您也可以这样做:

public boolean doRealmOperation(Object... params){
AtomicBoolean ret = new AtomicBoolean(false);
mRealm.executeTransaction(
    realm -> {
        try{
            [do your realm operation]
            ret.set(true);
        } catch(Exception e){
           onException(e)
           ret.set(false);
        }
    }
)
}

在这种情况下,您需要使用“ AtomicBoolean”,因为您将设置要在事务内部返回的值,但是在事务内部,该值是从事务本身之外获取的(在这种情况下,是“ ret”变量) )必须为FINAL变量。但是您不能将“ ret”定义为“ final”,然后再进行设置,因此您需要使用“ AtomicBoolean”在事务外部设置变量,然后在事务内部再次设置变量。 (您也可以通过使用临时变量获取事务内部的“真/假”值,然后使用该“临时变量”设置“ ret”变量来避免此问题。但是我个人更喜欢使用“ AtomicBoolean”类,我认为比临时变量更安全,更干净)

希望这会有所帮助, 再见,祝您编程愉快! ;)