Julio Gómez Julio Gómez - 6 months ago 49
Android Question

Activity - Service Inconsistent data with Realm

I have problems with data stored in a Realm Database. If I change a value on the MainActivity, when I try to read it from a NotificationListenerService, the data is incorrect.

This is my model:

public class Model extends RealmObject {

String name;
boolean checked;


public Model() {}

public Model(String name, boolean checked) {
this.name = name;
this.checked = checked;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public boolean isChecked() {
return checked;
}

public void setChecked(boolean checked) {
this.checked = checked;
}

}


I populate the database from the Application class:

public class ExampleApplication extends Application{

@Override
public void onCreate() {
super.onCreate();
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder(getApplicationContext()).deleteRealmIfMigrationNeeded().build();
Realm.setDefaultConfiguration(realmConfiguration);
Realm.getDefaultInstance().beginTransaction();
Realm.getDefaultInstance().copyToRealm(new Model("Test1", true));
Realm.getDefaultInstance().copyToRealm(new Model("Test2", true));
Realm.getDefaultInstance().commitTransaction();
}
}


I have an activity with:


  • a button with a link to Notification Listener services on device settings

  • a textview that shows the state of the model (checked or not)

  • a button to change the checked value of the model



This is the code:

public class MainActivity extends AppCompatActivity {

Button btnEnableService;
Button btnChangeValue;
TextView tvStatus;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

btnEnableService = (Button) findViewById(R.id.btn_enable_service);
btnChangeValue = (Button) findViewById(R.id.btn_change_value);
tvStatus = (TextView) findViewById(R.id.tv_status);

btnEnableService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
startActivity(new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS));
}catch(ActivityNotFoundException anfe){
Toast.makeText(MainActivity.this, "Your device not supports Notification Listener Service", Toast.LENGTH_SHORT).show();
}
}
});

btnChangeValue.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean status = Realm.getDefaultInstance().where(Model.class).equalTo("name", "Test1").findFirst().isChecked();
Realm.getDefaultInstance().beginTransaction();
Realm.getDefaultInstance().where(Model.class).equalTo("name", "Test1").findFirst().setChecked(!status);
Realm.getDefaultInstance().commitTransaction();
updateView();
}
});

}

@Override
protected void onResume() {
super.onResume();
updateView();
}

private void updateView(){
boolean status = Realm.getDefaultInstance().where(Model.class).equalTo("name", "Test1").findFirst().isChecked();
tvStatus.setText("Status: " + status);
}
}


When I click on the btnChangeValue button, I change the value on Realm and the textview is updated with the new value. All OK for now.

On the other hand, I have a service to listen the device notifications. It's very simple and only shows the status value of the model on LogCat:

public class CustomNotificationListenerService extends NotificationListenerService{

@Override
public void onCreate() {
super.onCreate();
}

@Override
public void onNotificationPosted(StatusBarNotification sbn) {
super.onNotificationPosted(sbn);
boolean status = Realm.getDefaultInstance().where(Model.class).equalTo("name", "Test1").findFirst().isChecked();
Log.i("XXX", "Status: " + status);
}

@Override
public void onNotificationRemoved(StatusBarNotification sbn) {
super.onNotificationRemoved(sbn);
}
}


My problem is that the checked value of the model is inconsistent, I get different values from the MainActivity and the NotificationListenerService.

What do I'm doing wrong?

Thanks in advance!

Answer

After testing for hours, I solved my problem closing the Realm instance after every operation.

So, data is consistent and I can query from NotificationListenerService and MainActivity.

ExampleApplication

public class ExampleApplication extends Application{

    @Override
    public void onCreate() {
        super.onCreate();
        RealmConfiguration realmConfiguration = new RealmConfiguration.Builder(getApplicationContext()).deleteRealmIfMigrationNeeded().build();
        Realm.setDefaultConfiguration(realmConfiguration);
        Realm mRealm = Realm.getDefaultInstance();
        mRealm.beginTransaction();
        mRealm.copyToRealm(new Model("Test1", true));
        mRealm.copyToRealm(new Model("Test2", true));
        mRealm.commitTransaction();
        mRealm.close();
    }
}

MainActivity

...
@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    btnChangeValue.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Realm mRealm = Realm.getDefaultInstance();
            boolean status = mRealm.where(Model.class).equalTo("name", "Test1").findFirst().isChecked();
            mRealm.beginTransaction();
            mRealm.where(Model.class).equalTo("name", "Test1").findFirst().setChecked(!status);
            mRealm.commitTransaction();
            mRealm.close();
            updateView();
        }
    });
}
...

CustomNotificationListenerService

...
@Override
public void onNotificationPosted(StatusBarNotification sbn) {
    super.onNotificationPosted(sbn);
    Realm mRealm = Realm.getDefaultInstance();
    boolean status = mRealm.where(Model.class).equalTo("name", "Test1").findFirst().isChecked();
    mRealm.close();
    Log.i("XXX", "Status: " + status);
}
...

Hope it helps you.