8

I searched and found FindFirst returns null question but no one answered it. As I'm thinking I am doing something wrong, let me explain my problem with more details.

I'm working on an app that asks the user to sign in first and then lets the user use the app.

My User class looks like this:

public class User extends RealmObject {

    @PrimaryKey
    @SerializedName("uid")
    String id;
    @SerializedName("ufname")
    String firstName;
    @SerializedName("ulname")
    String lastName;
    String avatar;
    int sessions;
    int invites;
    String nextSessionTime;
    String nextSessionTitle;
    @SerializedName("lastlogin")
    String lastLogin;
    String token;

    @Override
    public String toString() {
        return new GsonBuilder().create().toJson(this, User.class);
    }

    // other setters and getters
}

I store User's object in Realm db after successful login in SigninActivity class:

@Override
public void onSignInResponse(final GeneralResponse response) {

    if (response == null) {
        Timber.e("response is null");
        return;
    }
    Timber.d(response.toString());

    if (response.isSuccess()) {
        // Store user's info including Token
        realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                realm.copyToRealmOrUpdate(response.getUser());
            }
        });

        // Goto main screen
        MainVideoActivity.startActivity(this);
        this.finish();

    } else {
        String errorMessage = response.getErrorMessages();
        super.displayMessage(errorMessage);
    }
}

Once the login is successful, app directs user to MainVideoActivity. I want to find user in realm by following code however I'm getting null.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main_video);

    // Create the Realm instance
    realm = Realm.getDefaultInstance();
    User user = realm.where(User.class).findFirst();
//        RealmResults<User> user = realm.where(User.class).findAll();
    Timber.d(user.toString());
}

user is null in both approaches.

enter image description here

However, I can see my none null user in db.

enter image description here

I'm using classpath "io.realm:realm-gradle-plugin:2.0.2"

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Hesam
  • 52,260
  • 74
  • 224
  • 365
  • 1
    If you are talking about the null values in the debug window -- that is expected. See https://realm.io/docs/java/latest/#android-studio-debugging – beeender Oct 17 '16 at 01:43
  • @beeender thanks for sharing the doc. Unfortunately my log receives `null` as well :( Its code is inside MainVideoActivity class. – Hesam Oct 17 '16 at 03:29
  • i am bit confused. From your screenshot, I can see the user has been found with `session=0, invites=0` which matches the values in the Realm browser. I think user is not null at line 47? – beeender Oct 17 '16 at 03:45
  • @beeender those are default values. As you see in debuger, `id`, `firstName` and `lastName` are all `null` while they aren't in Dev Tools screenshot. – Hesam Oct 17 '16 at 06:37
  • The `id`/`firstName`/`lastName` are supposed to be `null` in the Dev Tools screenshot, that was what i mean in the first comment. So even if you have a `Log.e(TAG, user.getFirstName()` at line 47, it will out put null in the logcat? What would happen if you put the log in `onSignInResponse()` right after the transaction executed? – beeender Oct 17 '16 at 07:09
  • @Hesam that's not null, that's a RealmProxy. The `toString()` shows you what it is. – EpicPandaForce Oct 17 '16 at 08:07
  • @EpicPandaForce So, my problem is how to get my User object back from RelamDB, This returned obj don't have firstName, lastName and Token. – Hesam Oct 23 '16 at 06:45
  • @beeender Thanks, I added following lines in my code, `Log.e(TAG, user != null ? user.getFirstName() : "user is null"); Log.e(TAG, user != null ? user.getLastName() : "user is null"); Log.e(TAG, user != null ? user.getToken() : "user is null"); Log.e(TAG, user != null ? user.toString() : "user is null");` I'm getting firstName, lastName and Token surprisingly :) however user.toString() is printing same output without those attributes. It would be awesome if you put your comments as answer and then I'll accept it. why `user.toString()` doesn't print everything? thanks – Hesam Oct 23 '16 at 06:57
  • @Hesam Realm generates a Realm Proxy class during the annotation processing for user defined `RealmObject`. It will generate a `toString()` method if there is no `toString()` method defined by user. I think your problem is you have a `toString()` method defined which will ignore `null` values. Try to remove the `toString()` method in your `User` class. – beeender Oct 24 '16 at 02:42
  • @beeender please put it as answer then I'll accept it. – Hesam Oct 24 '16 at 03:10

4 Answers4

9

There are two things here:

  1. The null values in the debug window. That is a known limitation when using Realm with debugger. Since Realm generated a Proxy class to access values, inspecting the RealmObject's field in the debugger won't go through the proxy class. See more details here

  2. The fields with null values are not printed in the toString() method. Realm annotation processor will generate a toString() method if there is no toString() method defined in the RealmObject. I think the problem here is the a User.toString() ignores null values. Try to remove the toString() method in the User class.

beeender
  • 3,555
  • 19
  • 32
  • Thanks for details. I removed `toString()` and I see `Timber.d(user.toString());` prints out some results. However, I found something else as well. The real problem is `GsonBuilder()` that I have in `toString()` method of `User` class. I deleted that and replaced it with following then I got a beautiful print. `@Override public String toString() { return new StringBuilder().append("User{") .append("id='").append(id).append('\'') .append(", firstName='").append(firstName).append('\'') ... .toString();}` – Hesam Oct 24 '16 at 06:16
1

According Realm doc Realm you can try add isNotNull() in your query like this:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main_video);

    // Create the Realm instance
    realm = Realm.getDefaultInstance();
    User user = realm.where(User.class).isNotNull("id").findFirst(); //add in this line isNotNull()
    //RealmResults<User> user = realm.where(User.class).findAll();
    Timber.d(user.toString());
}

I have not tested yet, but it should work.

rockar06
  • 454
  • 3
  • 14
  • Thanks for the help, I changed it to `.isNotNull("id")` as `isNotNull()` needs a param. However, I got same result and I got `null` :( – Hesam Oct 16 '16 at 21:08
  • You could try to use `.findAll()` and debug what is the result, if you can't see something, it should be problem in your instance for get Realm, could you post the debug result for `.findAll()`? – rockar06 Oct 17 '16 at 01:12
  • I did that way but same result I got. – Hesam Oct 23 '16 at 04:59
1

Try replacing

    realm.executeTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            realm.copyToRealmOrUpdate(response.getUser());
        }
    });

    // Goto main screen
    MainVideoActivity.startActivity(this);
    this.finish();

with

    realm.executeTransactionAsync(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            realm.copyToRealmOrUpdate(response.getUser());
        }
    }, new Realm.Transaction.OnSuccess() {
        @Override
        public void onSuccess() {
            // Goto main screen
            MainVideoActivity.startActivity(this);
            finish();
        }
    });
EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
-1

One way to workaround this is to create an unmanaged copy of the object.

Replace:

User user = realm.where(User.class).findFirst();

with

User managed_user = realm.where(User.class).findFirst();
  if(user!=null){
  User unmanaged_user = realm.copyFromRealm(managed_user)
}

Return unmanaged_user.