Changes in the database from a background thread is displayed only after restart the application. Why? How to fix?
public class UILApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
RealmConfiguration config = new RealmConfiguration.Builder(this).build();
Realm.setDefaultConfiguration(config);
}
In the background is next code inserting to DB:
public void setFollows(List<JSONObject> follows) {
Realm realm = Realm.getDefaultInstance();
List<Follow> finalFollows = new RealmList<>();
try {
for(JSONObject follow:follows){
finalFollows.add(new Follow(follow.getLong("id"),follow.getString("username"), follow.getString("profile_picture"), follow.getString("full_name")));
}
List<Follow> goneFollows = getGoneFollows(finalFollows);
List<Follow> newFollows = getNewFollows(finalFollows);
realm.beginTransaction();
if(goneFollows != null && !goneFollows.isEmpty()){
goneFollows = realm.copyToRealmOrUpdate(goneFollows);
L.d("getHistoryForUpdate goneFollows");
History history = getHistoryForUpdate();
history.getRemoveFollows().clear();
history.getRemoveFollows().addAll(goneFollows);
}
if(newFollows != null && !newFollows.isEmpty()){
newFollows = realm.copyToRealmOrUpdate(newFollows);
L.d("getHistoryForUpdate newFollows");
History history = getHistoryForUpdate();
history.getNewFollows().clear();
history.getNewFollows().addAll(newFollows);
}
finalFollows = realm.copyToRealmOrUpdate(finalFollows);
getFollows().clear();
getFollows().addAll(finalFollows);
realm.commitTransaction();
realm.close();
} catch (JSONException e) {
e.printStackTrace();
}
}
public History getHistoryForUpdate(){
Realm realm = Realm.getDefaultInstance();
String today = DateHandler.getOnlyDate();
History history = realm.where(History.class).equalTo("createDate", today).findFirst();
if(history == null){
L.d("getHistoryForUpdate new");
realm.beginTransaction();
history = new History();
history = realm.copyToRealm(history);
history.setCreateDate(today);
getHistoryList().add(history);
realm.commitTransaction();
}
L.d("getHistoryForUpdate");
realm.close();
return history;
}
In Fragment trying to enter new data but I get only after you restart the application
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
realm = Realm.getDefaultInstance();
favorite = realm.where(Favorite.class).equalTo("id", Long.parseLong(userId))
.findFirst();
RealmList<History> historyList = favorite.getHistoryList();
...
}
Inside background thread are all well written and have access to the data at once, but to get the data from the application, it must be restarted
<receiver
android:name=".core.receivers.Alarm"
android:process=":remote" />
Success came after removal of the second attribute
Related
Basically I'm trying to check if an object exists before trying to use it, if not, I'm adding it beforehand then trying to use it.
If it doesn't exist, it gets added correctly but it's still not found by the application afterwards unless I reopen the app
Everything works as intended, however, if the object is there to begin with
private class ExerciseViewPageAdapter extends FragmentPagerAdapter {
Realm realm;
ExerciseViewPageAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int pos) {
realm = Realm.getDefaultInstance();
String exercise_name = getIntent().getExtras().getString("exercise_name");
boolean found_exercise = realm.where(Exercise.class).equalTo("name", exercise_name).findAll().size() > 0;
if (!found_exercise) {
CompositeDisposable disposable = new CompositeDisposable();
ExerciseClient client = new ExerciseClient(getApplicationContext());
disposable.add(client.getExerciseByName(exercise_name)
.subscribeOn(Schedulers.io())
.subscribe(
this::getExercisesSuccess,
this::getExercisesError
)
);
}
final ArrayList<Exercise> exercise = new ArrayList<>();
exercise.add(realm.where(Exercise.class).equalTo("name", exercise_name).findFirst());
if (exercise.get(0) != null) {
switch (pos) {
//returning new fragments depending on position
}
}
//if exercise.get(0) doesn't exist at first, even tho I added it afterwards it's still null here unless I reopen the app or let it crash
finish();
realm.close();
return null;
}
private void getExercisesError(Throwable throwable) {
}
private void getExercisesSuccess(Exercise exercise) {
try (Realm r = Realm.getDefaultInstance()) {
r.executeTransaction(realm -> {
realm.insertOrUpdate(exercise);
});
}
}
#Override
public int getCount() {
return 3;
}
}
Edit: TL;DR: the problem is that the object is being seen by the realm.where()... after inserting an object prior to it only after reopening the app
You called api, it's will run on background so the code next to wrote on api call will execute. So your activity will close automatically.
call your validation on your api success getting failed
private void getExercisesSuccess(Exercise exercise) {
try (Realm r = Realm.getDefaultInstance()) {
r.beginTransaction();
realm.insertOrUpdate(exercise);
r.commitTransaction();
//checking records are in realm
final ArrayList<Exercise> exercise = new ArrayList<>();
exercise.add(realm.where(Exercise.class).equalTo("name", exercise_name).findFirst());
if (exercise.get(0) != null) {
switch (pos) {
//returning new fragments depending on position
}
}
//if exercise.get(0) doesn't exist at first, even tho I added it afterwards it's still null here unless I reopen the app or let it crash
finish();
realm.close();
}catch(Exception e){}
}
And remove below lines from your getItem()
final ArrayList<Exercise> exercise = new ArrayList<>();
exercise.add(realm.where(Exercise.class).equalTo("name", exercise_name).findFirst());
if (exercise.get(0) != null) {
switch (pos) {
//returning new fragments depending on position
}
}
//if exercise.get(0) doesn't exist at first, even tho I added it afterwards it's still null here unless I reopen the app or let it crash
finish();
realm.close();
I'm using Realms as a database in Android app. Works fine, but I've added a new label in my user model and I'm getting the error that I need to migrate my schema:
java.lang.RuntimeException: Unable to create application com.apelucy.apelucy.app.base.MyApplication: io.realm.exceptions.RealmMigrationNeededException: Migration is required due to the following errors:
- Property 'User.testRealm' has been added.
How can I do the migration? I've found other solutions here but I can't implement them in my code. I can't use a solution of delete and install the app. I now that work in development, but I need to update the app in production.
My UserRespository class:
public class UserRepository {
private static UserRepository sInstance = null;
private Context mContext = null;
public static UserRepository getInstance(Context context) {
if (sInstance == null) {
sInstance = new UserRepository();
sInstance.mContext = context;
}
return sInstance;
}
// DATABASE Methods
public void storeUser(final User user) {
AppSingleton.getInstance().setUser(user);
Realm realm = null;
try {
realm = Realm.getDefaultInstance();
realm.executeTransaction(realm1 -> realm1.insertOrUpdate(user));
} finally {
if (realm != null) {
realm.close();
}
}
}
public User retrieveUser() {
Realm realm = null;
User user = null;
try {
realm = Realm.getDefaultInstance();
User userRealmResult = realm.where(User.class)
.findFirst();
if (userRealmResult != null) {
user = realm.copyFromRealm(userRealmResult);
}
} finally {
if (realm != null) {
realm.close();
}
}
return user;
}
public void clearUser() {
// Clear Database objects
Realm realm = null;
try {
realm = Realm.getDefaultInstance();
realm.executeTransaction(realm1 -> realm1.delete(User.class));
} finally {
if (realm != null) {
realm.close();
}
}
}
}
Init realm in my Application:
Realm.init(this);
My model change:
#SerializedName("test")
#Expose
private String testRealm;
Migrations allow you to modify the schema of the application, which means that it lets you add, remove, rename tables/fields in the Realm schema. If you change a RealmModel class, then you must write the migration that will map the existing Realm file to reflect the new model classes.
RealmConfiguration config = new RealmConfiguration.Builder()
.schemaVersion(1)
.migration(new MyMigration())
.build();
Realm.setDefaultConfiguration(config);
The default schema version is 0.
Migrations are fairly straightforward:
you must increment the schema version, so Realm knows you want to increment the schema's version to a specific number
you must supply a migration that will handle the change from one version to another
Migrations describe the operations to do when you need to go from one schema version to another:
public class MyMigration implements RealmMigration {
#Override
public void migrate(final DynamicRealm realm, long oldVersion, long newVersion) {
RealmSchema schema = realm.getSchema();
// Migrate from version 0 to version 1
if (oldVersion == 0) {
RealmObjectSchema userSchema = schema.get("User");
userSchema.addField("testRealm", String.class);
oldVersion++;
}
if (oldVersion == 1) { // ...
// ...
}
}
#Override
public int hashCode() { return MyMigration.class.hashCode(); }
#Override
public boolean equals(Object object) { return object != null && object instanceof MyMigration; }
}
Add this in your Application file. This will Realm to delete everything if you add a new table to a column.
RealmConfiguration config = new RealmConfiguration.Builder().name("dbname.realm")
.deleteRealmIfMigrationNeeded()
.build();
Realm.setDefaultConfiguration(config);
I'm trying to write data on one service and accessing it from another service.
The data I'm getting from another service is not updated, it's old copy.
Restarting the app sometimes gets updated data.
The services are both normal Service extended, so UI thread only.
And I'm not keeping any realm instances open anywhere in the app.
How do I ensure it's always new and updated one?
Writing -
data is detached using realm.copyFromRealm(...)
try (Realm realm = Realm.getDefaultInstance()) {
if (realm != null) {
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(#NonNull Realm realm) {
data.setValue("New value ...");
realm.insertOrUpdate(data);
}
});
}
}
Reading -
Data data = null;
try (Realm realm = Realm.getDefaultInstance()) {
if (realm != null) {
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(#NonNull Realm realm) {
data = realm.copyFromRealm(realm.where(Data.class).equalTo("Id", id).findFirst());
}
});
}
}
Data -
public class Data {
...
private String Value;
public String getValue() { return Value; }
public void setValue(String v) { Value = v; }
...
}
Edit -
I ended up merging both services into one, which works for now. But I'll look forward if anyone can provide some tips or has a similar problem.
How do I ensure it's always new and updated one?
Don't use copyFromRealm(). and use RealmResults field variable + RealmChangeListener
RealmResults<T> results;
RealmChangeListener<RealmResults<T>> listener = new RealmChangeListener<...>() {
#Override public void onChange(RealmResults<T> results) {
...
}
}
public void something() {
results = realm.where(...).findAll*();
results.addChangeListener(
What is the best practice for using the Realm instance? In my code everywhere where I am using the realm instance, after I am done with the realm instance I close it there itself, yet I often run into this issue.
For example,
Realm realm = null;
try {
realm = Realm.getDefaultInstance();
realm.executeTransaction(realm1 -> {
if(realmUser != null) {
// do some realm database related operation here
}
});
} finally {
if(realm != null) {
realm.close(); // close immediately after use
}
}
In, my case here is where this error occurs:-
static void setUserEmailVerifiedToRealm(){
User realmUser = getUserFromRealm();
Realm realm = null;
try {
realm = Realm.getDefaultInstance();
realm.executeTransaction(realm1 -> { // Exception
if(realmUser != null) {
realmUser.setEmailVerified(true);
Log.d("xxx", "Email verified");
}
});
} finally {
if(realm != null) {
realm.close();
}
}
}
public static User getUserFromRealm(){
Realm realm = null;
final User[] user = new User[1];
try {
realm = Realm.getDefaultInstance();
realm.executeTransaction(realm1 -> {
user[0] = realm1.where(User.class).findFirst();
});
} finally {
if(realm != null) {
realm.close();
}
}
return user[0];
}
I am not able to understand how to fix this issue, any pointer will be really appreciated.
How can I maintain a single Realm Instance throughout the complete lifecycle of the App and also close it.
I can achieve maintaining the instance using a singleton class, but then how do I close it when the app is closed?
Also, is it safe to not close Realm Instance once opened?
I tend to use a singleton RealmManager for the UI thread, and for background threads I open/close the Realm using a try-with-sources block.
So for UI thread:
public class RealmManager {
private static final String TAG = "RealmManager";
static Realm realm;
static RealmConfiguration realmConfiguration;
public static void initializeRealmConfig(Context appContext) {
if(realmConfiguration == null) {
Log.d(TAG, "Initializing Realm configuration.");
setRealmConfiguration(new RealmConfiguration.Builder(appContext).initialData(new RealmInitialData())
.deleteRealmIfMigrationNeeded()
.inMemory()
.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()) {
Log.w(TAG, "Unexpected open Realm found.");
realm.close();
}
}
Log.d(TAG, "Incrementing Activity Count [0]: opening Realm.");
realm = Realm.getDefaultInstance();
}
activityCount++;
Log.d(TAG, "Increment: Count [" + activityCount + "]");
}
public static void decrementCount() {
activityCount--;
Log.d(TAG, "Decrement: Count [" + activityCount + "]");
if(activityCount <= 0) {
Log.d(TAG, "Decrementing Activity Count: closing Realm.");
activityCount = 0;
realm.close();
if(Realm.compactRealm(realmConfiguration)) {
Log.d(TAG, "Realm compacted successfully.");
}
realm = null;
}
}
}
And for background thread:
try(Realm realm = Realm.getDefaultInstance()) {
// ...
}
Why don't you create a wrapping class for your realm instance (may be a singleton) and then add a few methods to it, so that instead of closing realm each time you can just call your own method and close the used instance as soon as you're finished? Something like this.
public class WrappingRealm {
public static WrappingRealm getInstance() {
//create your singleton here. Be aware of synchronization issues
}
private Realm getRealm() {
return Realm.getDefaultInstance();
}
public void save(RealmModel obj) {
Realm currentRealm = getRealm();
currentRealm.executeTransaction {
//Do your stuff
}
currentRealm.close();
}
}