LiveData not updating when data changes












1














I'm using LiveData to fetch data from a server and observe it. My onChanged() method just gets called the first time, and does not get called when data in the server gets updated.



UserFragment:



UserViewModel userViewModel = ViewModelProviders.of(this).get(UserViewModel.class);
userViewModel.getUser().observe(this, new Observer<User>() {
@Override
public void onChanged(User user) {
//Set UI
}
});


UserViewModel:



public class UserViewModel extends AndroidViewModel {
private LiveData<User> user;

public UserViewModel(Application application) {
super(application);
user = UserRepository.getInstance().fetchUser();
}

public LiveData<User> getUser() {
return user;
}
}


UserRepository:



public class UserRepository {    
private ApiService apiService;
private static UserRepository userRepository;

private UserRepository() {
apiService = RestClient.getClient().create(ApiService.class);
}

public synchronized static UserRepository getInstance() {
if (userRepository == null) userRepository = new UserRepository();
return userRepository;
}

public LiveData<User> fetchUser() {
final MutableLiveData<User> data = new MutableLiveData<>();
Call<User> call = apiService.getUser();
call.enqueue(new Callback<User>() {
@Override
public void onResponse(@NonNull Call<User> call, @NonNull Response<User> response) {
if (response.body() != null) {
data.postValue(response.body());
}
}

@Override
public void onFailure(@NonNull Call<User> call, @NonNull Throwable t) {
data.postValue(null);
t.printStackTrace();
}
});
return data;
}
}









share|improve this question






















  • Are you getting a proper response from the server in Retrofit?
    – Ümañg ßürmån
    Nov 21 '18 at 7:12










  • @Ümañgßürmån Yes
    – Saurabh Thorat
    Nov 21 '18 at 7:13










  • You'll need to set value to LiveData when you want to notify observers.
    – Jeel Vankhede
    Nov 21 '18 at 7:16










  • @JeelVankhede I already tried data.setValue(response.body()), but that didn't work
    – Saurabh Thorat
    Nov 21 '18 at 7:17










  • May be your API is executing prior to your observation of LiveData, try delaying your API call to check that.
    – Jeel Vankhede
    Nov 21 '18 at 7:20
















1














I'm using LiveData to fetch data from a server and observe it. My onChanged() method just gets called the first time, and does not get called when data in the server gets updated.



UserFragment:



UserViewModel userViewModel = ViewModelProviders.of(this).get(UserViewModel.class);
userViewModel.getUser().observe(this, new Observer<User>() {
@Override
public void onChanged(User user) {
//Set UI
}
});


UserViewModel:



public class UserViewModel extends AndroidViewModel {
private LiveData<User> user;

public UserViewModel(Application application) {
super(application);
user = UserRepository.getInstance().fetchUser();
}

public LiveData<User> getUser() {
return user;
}
}


UserRepository:



public class UserRepository {    
private ApiService apiService;
private static UserRepository userRepository;

private UserRepository() {
apiService = RestClient.getClient().create(ApiService.class);
}

public synchronized static UserRepository getInstance() {
if (userRepository == null) userRepository = new UserRepository();
return userRepository;
}

public LiveData<User> fetchUser() {
final MutableLiveData<User> data = new MutableLiveData<>();
Call<User> call = apiService.getUser();
call.enqueue(new Callback<User>() {
@Override
public void onResponse(@NonNull Call<User> call, @NonNull Response<User> response) {
if (response.body() != null) {
data.postValue(response.body());
}
}

@Override
public void onFailure(@NonNull Call<User> call, @NonNull Throwable t) {
data.postValue(null);
t.printStackTrace();
}
});
return data;
}
}









share|improve this question






















  • Are you getting a proper response from the server in Retrofit?
    – Ümañg ßürmån
    Nov 21 '18 at 7:12










  • @Ümañgßürmån Yes
    – Saurabh Thorat
    Nov 21 '18 at 7:13










  • You'll need to set value to LiveData when you want to notify observers.
    – Jeel Vankhede
    Nov 21 '18 at 7:16










  • @JeelVankhede I already tried data.setValue(response.body()), but that didn't work
    – Saurabh Thorat
    Nov 21 '18 at 7:17










  • May be your API is executing prior to your observation of LiveData, try delaying your API call to check that.
    – Jeel Vankhede
    Nov 21 '18 at 7:20














1












1








1







I'm using LiveData to fetch data from a server and observe it. My onChanged() method just gets called the first time, and does not get called when data in the server gets updated.



UserFragment:



UserViewModel userViewModel = ViewModelProviders.of(this).get(UserViewModel.class);
userViewModel.getUser().observe(this, new Observer<User>() {
@Override
public void onChanged(User user) {
//Set UI
}
});


UserViewModel:



public class UserViewModel extends AndroidViewModel {
private LiveData<User> user;

public UserViewModel(Application application) {
super(application);
user = UserRepository.getInstance().fetchUser();
}

public LiveData<User> getUser() {
return user;
}
}


UserRepository:



public class UserRepository {    
private ApiService apiService;
private static UserRepository userRepository;

private UserRepository() {
apiService = RestClient.getClient().create(ApiService.class);
}

public synchronized static UserRepository getInstance() {
if (userRepository == null) userRepository = new UserRepository();
return userRepository;
}

public LiveData<User> fetchUser() {
final MutableLiveData<User> data = new MutableLiveData<>();
Call<User> call = apiService.getUser();
call.enqueue(new Callback<User>() {
@Override
public void onResponse(@NonNull Call<User> call, @NonNull Response<User> response) {
if (response.body() != null) {
data.postValue(response.body());
}
}

@Override
public void onFailure(@NonNull Call<User> call, @NonNull Throwable t) {
data.postValue(null);
t.printStackTrace();
}
});
return data;
}
}









share|improve this question













I'm using LiveData to fetch data from a server and observe it. My onChanged() method just gets called the first time, and does not get called when data in the server gets updated.



UserFragment:



UserViewModel userViewModel = ViewModelProviders.of(this).get(UserViewModel.class);
userViewModel.getUser().observe(this, new Observer<User>() {
@Override
public void onChanged(User user) {
//Set UI
}
});


UserViewModel:



public class UserViewModel extends AndroidViewModel {
private LiveData<User> user;

public UserViewModel(Application application) {
super(application);
user = UserRepository.getInstance().fetchUser();
}

public LiveData<User> getUser() {
return user;
}
}


UserRepository:



public class UserRepository {    
private ApiService apiService;
private static UserRepository userRepository;

private UserRepository() {
apiService = RestClient.getClient().create(ApiService.class);
}

public synchronized static UserRepository getInstance() {
if (userRepository == null) userRepository = new UserRepository();
return userRepository;
}

public LiveData<User> fetchUser() {
final MutableLiveData<User> data = new MutableLiveData<>();
Call<User> call = apiService.getUser();
call.enqueue(new Callback<User>() {
@Override
public void onResponse(@NonNull Call<User> call, @NonNull Response<User> response) {
if (response.body() != null) {
data.postValue(response.body());
}
}

@Override
public void onFailure(@NonNull Call<User> call, @NonNull Throwable t) {
data.postValue(null);
t.printStackTrace();
}
});
return data;
}
}






java android android-architecture-components android-livedata android-viewmodel






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 21 '18 at 7:05









Saurabh ThoratSaurabh Thorat

3,02811226




3,02811226












  • Are you getting a proper response from the server in Retrofit?
    – Ümañg ßürmån
    Nov 21 '18 at 7:12










  • @Ümañgßürmån Yes
    – Saurabh Thorat
    Nov 21 '18 at 7:13










  • You'll need to set value to LiveData when you want to notify observers.
    – Jeel Vankhede
    Nov 21 '18 at 7:16










  • @JeelVankhede I already tried data.setValue(response.body()), but that didn't work
    – Saurabh Thorat
    Nov 21 '18 at 7:17










  • May be your API is executing prior to your observation of LiveData, try delaying your API call to check that.
    – Jeel Vankhede
    Nov 21 '18 at 7:20


















  • Are you getting a proper response from the server in Retrofit?
    – Ümañg ßürmån
    Nov 21 '18 at 7:12










  • @Ümañgßürmån Yes
    – Saurabh Thorat
    Nov 21 '18 at 7:13










  • You'll need to set value to LiveData when you want to notify observers.
    – Jeel Vankhede
    Nov 21 '18 at 7:16










  • @JeelVankhede I already tried data.setValue(response.body()), but that didn't work
    – Saurabh Thorat
    Nov 21 '18 at 7:17










  • May be your API is executing prior to your observation of LiveData, try delaying your API call to check that.
    – Jeel Vankhede
    Nov 21 '18 at 7:20
















Are you getting a proper response from the server in Retrofit?
– Ümañg ßürmån
Nov 21 '18 at 7:12




Are you getting a proper response from the server in Retrofit?
– Ümañg ßürmån
Nov 21 '18 at 7:12












@Ümañgßürmån Yes
– Saurabh Thorat
Nov 21 '18 at 7:13




@Ümañgßürmån Yes
– Saurabh Thorat
Nov 21 '18 at 7:13












You'll need to set value to LiveData when you want to notify observers.
– Jeel Vankhede
Nov 21 '18 at 7:16




You'll need to set value to LiveData when you want to notify observers.
– Jeel Vankhede
Nov 21 '18 at 7:16












@JeelVankhede I already tried data.setValue(response.body()), but that didn't work
– Saurabh Thorat
Nov 21 '18 at 7:17




@JeelVankhede I already tried data.setValue(response.body()), but that didn't work
– Saurabh Thorat
Nov 21 '18 at 7:17












May be your API is executing prior to your observation of LiveData, try delaying your API call to check that.
– Jeel Vankhede
Nov 21 '18 at 7:20




May be your API is executing prior to your observation of LiveData, try delaying your API call to check that.
– Jeel Vankhede
Nov 21 '18 at 7:20












1 Answer
1






active

oldest

votes


















1














The issue is that fetchUser creates a new LiveData<> every time you call it.



This means that your first one will never receive an update.



Please take a look at these...



Repository



public class UserRepository {    
private ApiService apiService;
private static UserRepository userRepository;

private UserRepository() {
apiService = RestClient.getClient().create(ApiService.class);
}

public synchronized static UserRepository getInstance() {
if (userRepository == null) userRepository = new UserRepository();
return userRepository;
}

// Your example code
public LiveData<User> fetchUser() {
// Your problem lies here. Every time you fetch user data, you create a new LiveData.
// Instead, fetch user should update the data on a pre-existing LiveData.
final MutableLiveData<User> data = new MutableLiveData<>();
Call<User> call = apiService.getUser();
call.enqueue(new Callback<User>() {
@Override
public void onResponse(@NonNull Call<User> call, @NonNull Response<User> response) {
if (response.body() != null) {
data.postValue(response.body());
}
}

@Override
public void onFailure(@NonNull Call<User> call, @NonNull Throwable t) {
data.postValue(null);
t.printStackTrace();
}
});
return data;
}

// My alterations below:
private MutableLiveData<User> userLiveData = new MutableLiveData<>();

public LiveData<User> getUser() {
return userLiveData;
}

public LiveData<User> fetchUser2() {
Call<User> call = apiService.getUser();
call.enqueue(new Callback<User>() {
@Override
public void onResponse(@NonNull Call<User> call, @NonNull Response<User> response) {
if (response.body() != null) {
userLiveData.postValue(response.body());
}
// TODO: Consider a fallback response to the LiveData here, in the case that bad data is returned. Perhaps null?
}

@Override
public void onFailure(@NonNull Call<User> call, @NonNull Throwable t) {
userLiveData.postValue(null);
t.printStackTrace();
}
});
return userLiveData;
}
}


ViewModel



I would also change this slightly. Instead of observing fetch, I would observe the LiveData directly.



user = UserRepository.getInstance().getUser();


Later, you can request updated data from the server at any point.



UserRepository.getInstance().fetchUser2();


You could also call fetchUser2() on the first construction of UserRepository. Then only updates would call fetchUser2() directly.



private UserRepository() {
apiService = RestClient.getClient().create(ApiService.class);
fetchUser2();
}


Fragment



Also, in your Fragment, do not observe on this. Instead use getViewLifecycleOwner()



userViewModel.getUser().observe(getViewLifecycleOwner(), new Observer<User>() {
@Override
public void onChanged(User user) {
//Set UI
}
});





share|improve this answer























  • would you mind to explain what's the difference of using this vs getViewLifecycleOwner() ?
    – jackycflau
    Nov 21 '18 at 8:04








  • 1




    It changes what the LiveData binds to. The problem is that Fragment lives much longer than you might expect. This can lead to observing the same LiveData multiple times. getViewLifecycleOwner() will actually bind to the lifecycle of the fragments View. So when the view hierarchy is destroyed, the LiveData observers will be unbound too.
    – Knossos
    Nov 21 '18 at 8:23










  • For a more official explanation, there is also this link from the docs: developer.android.com/reference/androidx/fragment/app/…
    – Knossos
    Nov 21 '18 at 8:23










  • It still doesn't update. And with this code, even after the fragment is destroyed and finished, it still shows the old data.
    – Saurabh Thorat
    Nov 21 '18 at 8:37












  • You might consider adding logs to the code in all places. Log in your repository under fetchUser2() to ensure that the LiveData is being transmitted to, for example. So log in fetchUser2() directly, in onResponse() and in onFailure(). Double check that you aren't still using fetchUser() in your code, if you just copy and pasted.
    – Knossos
    Nov 21 '18 at 8:45











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53406859%2flivedata-not-updating-when-data-changes%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














The issue is that fetchUser creates a new LiveData<> every time you call it.



This means that your first one will never receive an update.



Please take a look at these...



Repository



public class UserRepository {    
private ApiService apiService;
private static UserRepository userRepository;

private UserRepository() {
apiService = RestClient.getClient().create(ApiService.class);
}

public synchronized static UserRepository getInstance() {
if (userRepository == null) userRepository = new UserRepository();
return userRepository;
}

// Your example code
public LiveData<User> fetchUser() {
// Your problem lies here. Every time you fetch user data, you create a new LiveData.
// Instead, fetch user should update the data on a pre-existing LiveData.
final MutableLiveData<User> data = new MutableLiveData<>();
Call<User> call = apiService.getUser();
call.enqueue(new Callback<User>() {
@Override
public void onResponse(@NonNull Call<User> call, @NonNull Response<User> response) {
if (response.body() != null) {
data.postValue(response.body());
}
}

@Override
public void onFailure(@NonNull Call<User> call, @NonNull Throwable t) {
data.postValue(null);
t.printStackTrace();
}
});
return data;
}

// My alterations below:
private MutableLiveData<User> userLiveData = new MutableLiveData<>();

public LiveData<User> getUser() {
return userLiveData;
}

public LiveData<User> fetchUser2() {
Call<User> call = apiService.getUser();
call.enqueue(new Callback<User>() {
@Override
public void onResponse(@NonNull Call<User> call, @NonNull Response<User> response) {
if (response.body() != null) {
userLiveData.postValue(response.body());
}
// TODO: Consider a fallback response to the LiveData here, in the case that bad data is returned. Perhaps null?
}

@Override
public void onFailure(@NonNull Call<User> call, @NonNull Throwable t) {
userLiveData.postValue(null);
t.printStackTrace();
}
});
return userLiveData;
}
}


ViewModel



I would also change this slightly. Instead of observing fetch, I would observe the LiveData directly.



user = UserRepository.getInstance().getUser();


Later, you can request updated data from the server at any point.



UserRepository.getInstance().fetchUser2();


You could also call fetchUser2() on the first construction of UserRepository. Then only updates would call fetchUser2() directly.



private UserRepository() {
apiService = RestClient.getClient().create(ApiService.class);
fetchUser2();
}


Fragment



Also, in your Fragment, do not observe on this. Instead use getViewLifecycleOwner()



userViewModel.getUser().observe(getViewLifecycleOwner(), new Observer<User>() {
@Override
public void onChanged(User user) {
//Set UI
}
});





share|improve this answer























  • would you mind to explain what's the difference of using this vs getViewLifecycleOwner() ?
    – jackycflau
    Nov 21 '18 at 8:04








  • 1




    It changes what the LiveData binds to. The problem is that Fragment lives much longer than you might expect. This can lead to observing the same LiveData multiple times. getViewLifecycleOwner() will actually bind to the lifecycle of the fragments View. So when the view hierarchy is destroyed, the LiveData observers will be unbound too.
    – Knossos
    Nov 21 '18 at 8:23










  • For a more official explanation, there is also this link from the docs: developer.android.com/reference/androidx/fragment/app/…
    – Knossos
    Nov 21 '18 at 8:23










  • It still doesn't update. And with this code, even after the fragment is destroyed and finished, it still shows the old data.
    – Saurabh Thorat
    Nov 21 '18 at 8:37












  • You might consider adding logs to the code in all places. Log in your repository under fetchUser2() to ensure that the LiveData is being transmitted to, for example. So log in fetchUser2() directly, in onResponse() and in onFailure(). Double check that you aren't still using fetchUser() in your code, if you just copy and pasted.
    – Knossos
    Nov 21 '18 at 8:45
















1














The issue is that fetchUser creates a new LiveData<> every time you call it.



This means that your first one will never receive an update.



Please take a look at these...



Repository



public class UserRepository {    
private ApiService apiService;
private static UserRepository userRepository;

private UserRepository() {
apiService = RestClient.getClient().create(ApiService.class);
}

public synchronized static UserRepository getInstance() {
if (userRepository == null) userRepository = new UserRepository();
return userRepository;
}

// Your example code
public LiveData<User> fetchUser() {
// Your problem lies here. Every time you fetch user data, you create a new LiveData.
// Instead, fetch user should update the data on a pre-existing LiveData.
final MutableLiveData<User> data = new MutableLiveData<>();
Call<User> call = apiService.getUser();
call.enqueue(new Callback<User>() {
@Override
public void onResponse(@NonNull Call<User> call, @NonNull Response<User> response) {
if (response.body() != null) {
data.postValue(response.body());
}
}

@Override
public void onFailure(@NonNull Call<User> call, @NonNull Throwable t) {
data.postValue(null);
t.printStackTrace();
}
});
return data;
}

// My alterations below:
private MutableLiveData<User> userLiveData = new MutableLiveData<>();

public LiveData<User> getUser() {
return userLiveData;
}

public LiveData<User> fetchUser2() {
Call<User> call = apiService.getUser();
call.enqueue(new Callback<User>() {
@Override
public void onResponse(@NonNull Call<User> call, @NonNull Response<User> response) {
if (response.body() != null) {
userLiveData.postValue(response.body());
}
// TODO: Consider a fallback response to the LiveData here, in the case that bad data is returned. Perhaps null?
}

@Override
public void onFailure(@NonNull Call<User> call, @NonNull Throwable t) {
userLiveData.postValue(null);
t.printStackTrace();
}
});
return userLiveData;
}
}


ViewModel



I would also change this slightly. Instead of observing fetch, I would observe the LiveData directly.



user = UserRepository.getInstance().getUser();


Later, you can request updated data from the server at any point.



UserRepository.getInstance().fetchUser2();


You could also call fetchUser2() on the first construction of UserRepository. Then only updates would call fetchUser2() directly.



private UserRepository() {
apiService = RestClient.getClient().create(ApiService.class);
fetchUser2();
}


Fragment



Also, in your Fragment, do not observe on this. Instead use getViewLifecycleOwner()



userViewModel.getUser().observe(getViewLifecycleOwner(), new Observer<User>() {
@Override
public void onChanged(User user) {
//Set UI
}
});





share|improve this answer























  • would you mind to explain what's the difference of using this vs getViewLifecycleOwner() ?
    – jackycflau
    Nov 21 '18 at 8:04








  • 1




    It changes what the LiveData binds to. The problem is that Fragment lives much longer than you might expect. This can lead to observing the same LiveData multiple times. getViewLifecycleOwner() will actually bind to the lifecycle of the fragments View. So when the view hierarchy is destroyed, the LiveData observers will be unbound too.
    – Knossos
    Nov 21 '18 at 8:23










  • For a more official explanation, there is also this link from the docs: developer.android.com/reference/androidx/fragment/app/…
    – Knossos
    Nov 21 '18 at 8:23










  • It still doesn't update. And with this code, even after the fragment is destroyed and finished, it still shows the old data.
    – Saurabh Thorat
    Nov 21 '18 at 8:37












  • You might consider adding logs to the code in all places. Log in your repository under fetchUser2() to ensure that the LiveData is being transmitted to, for example. So log in fetchUser2() directly, in onResponse() and in onFailure(). Double check that you aren't still using fetchUser() in your code, if you just copy and pasted.
    – Knossos
    Nov 21 '18 at 8:45














1












1








1






The issue is that fetchUser creates a new LiveData<> every time you call it.



This means that your first one will never receive an update.



Please take a look at these...



Repository



public class UserRepository {    
private ApiService apiService;
private static UserRepository userRepository;

private UserRepository() {
apiService = RestClient.getClient().create(ApiService.class);
}

public synchronized static UserRepository getInstance() {
if (userRepository == null) userRepository = new UserRepository();
return userRepository;
}

// Your example code
public LiveData<User> fetchUser() {
// Your problem lies here. Every time you fetch user data, you create a new LiveData.
// Instead, fetch user should update the data on a pre-existing LiveData.
final MutableLiveData<User> data = new MutableLiveData<>();
Call<User> call = apiService.getUser();
call.enqueue(new Callback<User>() {
@Override
public void onResponse(@NonNull Call<User> call, @NonNull Response<User> response) {
if (response.body() != null) {
data.postValue(response.body());
}
}

@Override
public void onFailure(@NonNull Call<User> call, @NonNull Throwable t) {
data.postValue(null);
t.printStackTrace();
}
});
return data;
}

// My alterations below:
private MutableLiveData<User> userLiveData = new MutableLiveData<>();

public LiveData<User> getUser() {
return userLiveData;
}

public LiveData<User> fetchUser2() {
Call<User> call = apiService.getUser();
call.enqueue(new Callback<User>() {
@Override
public void onResponse(@NonNull Call<User> call, @NonNull Response<User> response) {
if (response.body() != null) {
userLiveData.postValue(response.body());
}
// TODO: Consider a fallback response to the LiveData here, in the case that bad data is returned. Perhaps null?
}

@Override
public void onFailure(@NonNull Call<User> call, @NonNull Throwable t) {
userLiveData.postValue(null);
t.printStackTrace();
}
});
return userLiveData;
}
}


ViewModel



I would also change this slightly. Instead of observing fetch, I would observe the LiveData directly.



user = UserRepository.getInstance().getUser();


Later, you can request updated data from the server at any point.



UserRepository.getInstance().fetchUser2();


You could also call fetchUser2() on the first construction of UserRepository. Then only updates would call fetchUser2() directly.



private UserRepository() {
apiService = RestClient.getClient().create(ApiService.class);
fetchUser2();
}


Fragment



Also, in your Fragment, do not observe on this. Instead use getViewLifecycleOwner()



userViewModel.getUser().observe(getViewLifecycleOwner(), new Observer<User>() {
@Override
public void onChanged(User user) {
//Set UI
}
});





share|improve this answer














The issue is that fetchUser creates a new LiveData<> every time you call it.



This means that your first one will never receive an update.



Please take a look at these...



Repository



public class UserRepository {    
private ApiService apiService;
private static UserRepository userRepository;

private UserRepository() {
apiService = RestClient.getClient().create(ApiService.class);
}

public synchronized static UserRepository getInstance() {
if (userRepository == null) userRepository = new UserRepository();
return userRepository;
}

// Your example code
public LiveData<User> fetchUser() {
// Your problem lies here. Every time you fetch user data, you create a new LiveData.
// Instead, fetch user should update the data on a pre-existing LiveData.
final MutableLiveData<User> data = new MutableLiveData<>();
Call<User> call = apiService.getUser();
call.enqueue(new Callback<User>() {
@Override
public void onResponse(@NonNull Call<User> call, @NonNull Response<User> response) {
if (response.body() != null) {
data.postValue(response.body());
}
}

@Override
public void onFailure(@NonNull Call<User> call, @NonNull Throwable t) {
data.postValue(null);
t.printStackTrace();
}
});
return data;
}

// My alterations below:
private MutableLiveData<User> userLiveData = new MutableLiveData<>();

public LiveData<User> getUser() {
return userLiveData;
}

public LiveData<User> fetchUser2() {
Call<User> call = apiService.getUser();
call.enqueue(new Callback<User>() {
@Override
public void onResponse(@NonNull Call<User> call, @NonNull Response<User> response) {
if (response.body() != null) {
userLiveData.postValue(response.body());
}
// TODO: Consider a fallback response to the LiveData here, in the case that bad data is returned. Perhaps null?
}

@Override
public void onFailure(@NonNull Call<User> call, @NonNull Throwable t) {
userLiveData.postValue(null);
t.printStackTrace();
}
});
return userLiveData;
}
}


ViewModel



I would also change this slightly. Instead of observing fetch, I would observe the LiveData directly.



user = UserRepository.getInstance().getUser();


Later, you can request updated data from the server at any point.



UserRepository.getInstance().fetchUser2();


You could also call fetchUser2() on the first construction of UserRepository. Then only updates would call fetchUser2() directly.



private UserRepository() {
apiService = RestClient.getClient().create(ApiService.class);
fetchUser2();
}


Fragment



Also, in your Fragment, do not observe on this. Instead use getViewLifecycleOwner()



userViewModel.getUser().observe(getViewLifecycleOwner(), new Observer<User>() {
@Override
public void onChanged(User user) {
//Set UI
}
});






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 21 '18 at 8:40

























answered Nov 21 '18 at 7:59









KnossosKnossos

11.4k74171




11.4k74171












  • would you mind to explain what's the difference of using this vs getViewLifecycleOwner() ?
    – jackycflau
    Nov 21 '18 at 8:04








  • 1




    It changes what the LiveData binds to. The problem is that Fragment lives much longer than you might expect. This can lead to observing the same LiveData multiple times. getViewLifecycleOwner() will actually bind to the lifecycle of the fragments View. So when the view hierarchy is destroyed, the LiveData observers will be unbound too.
    – Knossos
    Nov 21 '18 at 8:23










  • For a more official explanation, there is also this link from the docs: developer.android.com/reference/androidx/fragment/app/…
    – Knossos
    Nov 21 '18 at 8:23










  • It still doesn't update. And with this code, even after the fragment is destroyed and finished, it still shows the old data.
    – Saurabh Thorat
    Nov 21 '18 at 8:37












  • You might consider adding logs to the code in all places. Log in your repository under fetchUser2() to ensure that the LiveData is being transmitted to, for example. So log in fetchUser2() directly, in onResponse() and in onFailure(). Double check that you aren't still using fetchUser() in your code, if you just copy and pasted.
    – Knossos
    Nov 21 '18 at 8:45


















  • would you mind to explain what's the difference of using this vs getViewLifecycleOwner() ?
    – jackycflau
    Nov 21 '18 at 8:04








  • 1




    It changes what the LiveData binds to. The problem is that Fragment lives much longer than you might expect. This can lead to observing the same LiveData multiple times. getViewLifecycleOwner() will actually bind to the lifecycle of the fragments View. So when the view hierarchy is destroyed, the LiveData observers will be unbound too.
    – Knossos
    Nov 21 '18 at 8:23










  • For a more official explanation, there is also this link from the docs: developer.android.com/reference/androidx/fragment/app/…
    – Knossos
    Nov 21 '18 at 8:23










  • It still doesn't update. And with this code, even after the fragment is destroyed and finished, it still shows the old data.
    – Saurabh Thorat
    Nov 21 '18 at 8:37












  • You might consider adding logs to the code in all places. Log in your repository under fetchUser2() to ensure that the LiveData is being transmitted to, for example. So log in fetchUser2() directly, in onResponse() and in onFailure(). Double check that you aren't still using fetchUser() in your code, if you just copy and pasted.
    – Knossos
    Nov 21 '18 at 8:45
















would you mind to explain what's the difference of using this vs getViewLifecycleOwner() ?
– jackycflau
Nov 21 '18 at 8:04






would you mind to explain what's the difference of using this vs getViewLifecycleOwner() ?
– jackycflau
Nov 21 '18 at 8:04






1




1




It changes what the LiveData binds to. The problem is that Fragment lives much longer than you might expect. This can lead to observing the same LiveData multiple times. getViewLifecycleOwner() will actually bind to the lifecycle of the fragments View. So when the view hierarchy is destroyed, the LiveData observers will be unbound too.
– Knossos
Nov 21 '18 at 8:23




It changes what the LiveData binds to. The problem is that Fragment lives much longer than you might expect. This can lead to observing the same LiveData multiple times. getViewLifecycleOwner() will actually bind to the lifecycle of the fragments View. So when the view hierarchy is destroyed, the LiveData observers will be unbound too.
– Knossos
Nov 21 '18 at 8:23












For a more official explanation, there is also this link from the docs: developer.android.com/reference/androidx/fragment/app/…
– Knossos
Nov 21 '18 at 8:23




For a more official explanation, there is also this link from the docs: developer.android.com/reference/androidx/fragment/app/…
– Knossos
Nov 21 '18 at 8:23












It still doesn't update. And with this code, even after the fragment is destroyed and finished, it still shows the old data.
– Saurabh Thorat
Nov 21 '18 at 8:37






It still doesn't update. And with this code, even after the fragment is destroyed and finished, it still shows the old data.
– Saurabh Thorat
Nov 21 '18 at 8:37














You might consider adding logs to the code in all places. Log in your repository under fetchUser2() to ensure that the LiveData is being transmitted to, for example. So log in fetchUser2() directly, in onResponse() and in onFailure(). Double check that you aren't still using fetchUser() in your code, if you just copy and pasted.
– Knossos
Nov 21 '18 at 8:45




You might consider adding logs to the code in all places. Log in your repository under fetchUser2() to ensure that the LiveData is being transmitted to, for example. So log in fetchUser2() directly, in onResponse() and in onFailure(). Double check that you aren't still using fetchUser() in your code, if you just copy and pasted.
– Knossos
Nov 21 '18 at 8:45


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53406859%2flivedata-not-updating-when-data-changes%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Create new schema in PostgreSQL using DBeaver

Deepest pit of an array with Javascript: test on Codility

Costa Masnaga