2

I just started learning android development and I had a problem, I’m happy to get any help.

When I click the "User exists?" Button, a request is sent to the server and the server returns either a user or null (in my case, always null, because no users are created on the server).

After clicking on the button in the observer, the following is displayed in the log:

UserResult onChanged

UserResult NOT NULL

UserResult false null

That is, everything works perfectly.

When I close the application by pressing the "Back" button, I see in the logs that onDestroy is called for activity, and onCleared is called for ViewModel.

But if I even run the application again after an hour, then the log immediately (without pressing a button) is displayed:

UserResult onChanged

UserResult NOT NULL

UserResult false null

But if after closing the application I do the cleaning of all running applications through the operating system, then nothing is displayed in the log.

Why were the ViewModel and LiveData not deleted even an hour after the application was closed? I guess I'm doing something wrong, please help me understand what my mistake is. Thank.

ViewModel

class UserViewModel extends ViewModel {

    private MutableLiveData<UserResult> userResult;
    private UserRepository userRepository;

    LiveData<UserResult> getUserResult() {
        return userResult;
    }

    UserViewModel(UserRepository userRepository) {
        this.userRepository = userRepository;
        userResult = userRepository.getUser(null);
    }

    void getUser(String username) {
        userResult = userRepository.getUser(username);
    }

    @Override
    protected void onCleared() {
        Log.d(TAG, "onCleared");
        super.onCleared();
    }
}

Repository

public class UserRepository {
    ...

    private WebServiceApi webServiceApi;

    private MutableLiveData<UserResult> data = new MutableLiveData<>();

    public MutableLiveData<UserResult> getUser(String username) {
        if (username != null) {
            webServiceApi.getUser(username).enqueue(new Callback<User>() {
                @Override
                public void onResponse(Call<User> call, Response<User> response) {
                    User user = response.body();
                    if (user == null) {
                        // first param = user, second param = userExistsFlag(true when user not null, false when user is null)
                        data.setValue(new UserResult(null, false));
                    } else {
                        data.setValue(new UserResult(user, true));
                    }
                }

                @Override
                public void onFailure(Call<User> call, Throwable t) {
                    Log.d("UserRepository", "onFailure " + t.getMessage());
                }
            });
        }

        return data;
    }
}

Activity

public class UserActivity extends AppCompatActivity {
    ...
    private UserViewModel userViewModel;


    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user);

        ...

        userViewModel.getUserResult().observe(this, new Observer<UserResult>() {
            @Override
            public void onChanged(@Nullable UserResult userResult) {
                Log.d(TAG, "UserResult onChanged");

                if (userResult == null) {
                    return;
                } else {
                    Log.d(TAG, "UserResult NOT NULL");
                    Log.d(TAG, "UserResult " + userResult.getUserExistsFlag() + " " + userResult.getUser());
                }
            }
        });
    }

    @Override
    protected void onDestroy() {
        Log.d(TAG, "onDestroy");
        super.onDestroy();
    }

}
aqellaa
  • 41
  • 6

1 Answers1

2

There isn't any mistake. This is an expected behavior. Android OS normally does not kill application processes when the user dismisses the application. There are few circumstances that OS kills the processes, but user closing the app is not one of them.

If the application is alive, this means that all singleton classes are not going to be garbage collected. Your ViewModels will be discarded, but UserRepository and all its member variables won't, if UserRepository is using singleton pattern in some way. This is probably why your MutableLiveData<UserResult> data returns a value immediately.

If you do not like this behavior, you probably shouldn't keep below line in UserRepository.

    private MutableLiveData<UserResult> data = new MutableLiveData<>();
Sanlok Lee
  • 3,404
  • 2
  • 15
  • 25
  • Thanks for your reply. When I re-launch the application, a new Activity is created, a new ViewModel and a new Repository are created, in that case how do the data from the old repository (which was not deleted by the GC) get into the new activity? The new activity contains the link to the new ViewModel, and the new ViewModel stores the link to the new Repository. Or not? Where am I wrong? I apologize if I ask stupid questions, I am new to this. – aqellaa Jul 04 '19 at 16:14
  • @aqellaa When you re-launch the application, a new Activity, a new ViewModel are created but a new Repository is probably not created. I can't tell you for sure because you haven't provided the part of the code where you initialize the Repository class, it is just an educated guess from the information provided in the question. – Sanlok Lee Jul 04 '19 at 16:23
  • My Repository is a singleton class, as you suggested. Do I understand correctly that if this is a singleton, then when I re-launch the application, it most likely is not created new? – aqellaa Jul 04 '19 at 16:31
  • Yes. The user will get the same Repository instance that was used before the user closes the app. – Sanlok Lee Jul 04 '19 at 16:35
  • Thanks for such detailed answers, you helped me a lot. – aqellaa Jul 04 '19 at 16:38