diff --git a/realm/realm-library/src/main/java/io/realm/BaseRealm.java b/realm/realm-library/src/main/java/io/realm/BaseRealm.java index e09226f3f6..6cde35a435 100644 --- a/realm/realm-library/src/main/java/io/realm/BaseRealm.java +++ b/realm/realm-library/src/main/java/io/realm/BaseRealm.java @@ -37,6 +37,7 @@ import io.realm.internal.Table; import io.realm.internal.UncheckedRow; import io.realm.internal.Util; +import io.realm.internal.android.ContextWrapper; import io.realm.internal.async.RealmThreadPoolExecutor; import io.realm.log.RealmLog; import io.realm.internal.ObjectServerFacade; @@ -60,8 +61,8 @@ abstract class BaseRealm implements Closeable { private static final String NOT_IN_TRANSACTION_MESSAGE = "Changing Realm data can only be done from inside a transaction."; - // Thread pool for all async operations (Query & transaction) - volatile static Context applicationContext; + // Android ContextWrapper. Must be initialized by calling `Realm.init()` before calling any other API's. + volatile static ContextWrapper contextWrapper; // Thread pool for all async operations (Query & transaction) static final RealmThreadPoolExecutor asyncTaskExecutor = RealmThreadPoolExecutor.newDefaultExecutor(); diff --git a/realm/realm-library/src/main/java/io/realm/Realm.java b/realm/realm-library/src/main/java/io/realm/Realm.java index a6a6844345..5f093dcd5e 100644 --- a/realm/realm-library/src/main/java/io/realm/Realm.java +++ b/realm/realm-library/src/main/java/io/realm/Realm.java @@ -21,7 +21,6 @@ import android.content.Context; import android.os.Build; import android.util.JsonReader; -import android.util.Log; import org.json.JSONArray; import org.json.JSONException; @@ -57,6 +56,7 @@ import io.realm.internal.RealmProxyMediator; import io.realm.internal.SharedRealm; import io.realm.internal.Table; +import io.realm.internal.android.ContextWrapper; import io.realm.internal.async.RealmAsyncTaskImpl; import io.realm.log.RealmLog; import rx.Observable; @@ -182,15 +182,16 @@ public Observable asObservable() { * @see #getDefaultInstance() */ public static synchronized void init(Context context) { - if (BaseRealm.applicationContext == null) { + if (BaseRealm.contextWrapper == null) { if (context == null) { throw new IllegalArgumentException("Non-null context required."); } RealmCore.loadLibrary(context); - defaultConfiguration = new RealmConfiguration.Builder(context).build(); + ContextWrapper wrapper = new ContextWrapper(context); + defaultConfiguration = new RealmConfiguration.Builder(wrapper).build(); ObjectServerFacade.getSyncFacadeIfPossible().init(context); - BaseRealm.applicationContext = context.getApplicationContext(); - SharedRealm.initialize(new File(context.getFilesDir(), ".realm.temp")); + BaseRealm.contextWrapper = wrapper; + SharedRealm.initialize(new File(wrapper.getDefaultRealmFileDirectory(), ".realm.temp")); } } diff --git a/realm/realm-library/src/main/java/io/realm/RealmConfiguration.java b/realm/realm-library/src/main/java/io/realm/RealmConfiguration.java index 06775f7abc..08de79cc96 100644 --- a/realm/realm-library/src/main/java/io/realm/RealmConfiguration.java +++ b/realm/realm-library/src/main/java/io/realm/RealmConfiguration.java @@ -16,7 +16,6 @@ package io.realm; -import android.content.Context; import android.text.TextUtils; import java.io.File; @@ -32,9 +31,9 @@ import io.realm.annotations.RealmModule; import io.realm.exceptions.RealmException; import io.realm.exceptions.RealmFileException; -import io.realm.internal.RealmCore; import io.realm.internal.RealmProxyMediator; import io.realm.internal.SharedRealm; +import io.realm.internal.android.ContextWrapper; import io.realm.internal.modules.CompositeMediator; import io.realm.internal.modules.FilterableMediator; import io.realm.rx.RealmObservableFactory; @@ -187,7 +186,8 @@ boolean hasAssetFile() { * @throws IOException if copying the file fails. */ InputStream getAssetFile() throws IOException { - return BaseRealm.applicationContext.getAssets().open(assetFilePath); + return BaseRealm.contextWrapper.getAsset(assetFilePath); + } /** @@ -391,20 +391,19 @@ public static class Builder { * change depending on vendor implementations of Android. */ public Builder() { - this(BaseRealm.applicationContext); + this(BaseRealm.contextWrapper); } - Builder(Context context) { + Builder(ContextWrapper context) { if (context == null) { throw new IllegalStateException("Call `Realm.init(Context)` before creating a RealmConfiguration"); } - RealmCore.loadLibrary(context); initializeBuilder(context); } // Setup builder in its initial state - private void initializeBuilder(Context context) { - this.directory = context.getFilesDir(); + private void initializeBuilder(ContextWrapper context) { + this.directory = context.getDefaultRealmFileDirectory(); this.fileName = Realm.DEFAULT_REALM_NAME; this.key = null; this.schemaVersion = 0; diff --git a/realm/realm-library/src/main/java/io/realm/internal/android/ContextWrapper.java b/realm/realm-library/src/main/java/io/realm/internal/android/ContextWrapper.java new file mode 100644 index 0000000000..8e47313f7b --- /dev/null +++ b/realm/realm-library/src/main/java/io/realm/internal/android/ContextWrapper.java @@ -0,0 +1,56 @@ +/* + * Copyright 2016 Realm Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.realm.internal.android; + +import android.content.Context; +import android.content.res.AssetManager; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +/** + * This class wraps the Android Context class by extracting all relevant information from the context. + * This means we only need the Context when {@link io.realm.Realm#init(Context)} is called, but we don't + * need to hold onto it. + * + * This should also make Realm play nicer with Instant Run. + */ +public class ContextWrapper { + + private final AssetManager assetManager; + private File filesDir; + + public ContextWrapper(Context applicationContext) { + assetManager = applicationContext.getAssets(); + filesDir = applicationContext.getFilesDir(); + } + + /** + * Returns the default location for Realm files. + */ + public File getDefaultRealmFileDirectory() { + return filesDir; + } + + /** + * Returns an asset specified by a given path. + * On Android this path is assumed to be a path under the {@code assets} folder. + */ + public InputStream getAsset(String assetFilePath) throws IOException { + return assetManager.open(assetFilePath); + } +} diff --git a/realm/realm-library/src/objectServer/java/io/realm/SyncConfiguration.java b/realm/realm-library/src/objectServer/java/io/realm/SyncConfiguration.java index 07583eb63d..085edd909f 100644 --- a/realm/realm-library/src/objectServer/java/io/realm/SyncConfiguration.java +++ b/realm/realm-library/src/objectServer/java/io/realm/SyncConfiguration.java @@ -16,8 +16,6 @@ package io.realm; -import android.content.Context; - import java.io.File; import java.io.UnsupportedEncodingException; import java.net.URI; @@ -34,6 +32,7 @@ import io.realm.exceptions.RealmException; import io.realm.internal.RealmProxyMediator; import io.realm.internal.SharedRealm; +import io.realm.internal.android.ContextWrapper; import io.realm.internal.syncpolicy.AutomaticSyncPolicy; import io.realm.internal.syncpolicy.SyncPolicy; import io.realm.rx.RealmObservableFactory; @@ -277,14 +276,14 @@ public static final class Builder { * @see SyncUser#isValid() */ public Builder(SyncUser user, String uri) { - this(BaseRealm.applicationContext, user, uri); + this(BaseRealm.contextWrapper, user, uri); } - Builder(Context context, SyncUser user, String url) { + Builder(ContextWrapper context, SyncUser user, String url) { if (context == null) { throw new IllegalStateException("Call `Realm.init(Context)` before creating a SyncConfiguration"); } - this.defaultFolder = new File(context.getFilesDir(), "realm-object-server"); + this.defaultFolder = new File(context.getDefaultRealmFileDirectory(), "realm-object-server"); if (Realm.getDefaultModule() != null) { this.modules.add(Realm.getDefaultModule()); }