LiveData not updating when data changes
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
|
show 8 more comments
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
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 toLiveData
when you want to notify observers.
– Jeel Vankhede
Nov 21 '18 at 7:16
@JeelVankhede I already trieddata.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 ofLiveData
, try delaying your API call to check that.
– Jeel Vankhede
Nov 21 '18 at 7:20
|
show 8 more comments
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
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
java android android-architecture-components android-livedata android-viewmodel
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 toLiveData
when you want to notify observers.
– Jeel Vankhede
Nov 21 '18 at 7:16
@JeelVankhede I already trieddata.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 ofLiveData
, try delaying your API call to check that.
– Jeel Vankhede
Nov 21 '18 at 7:20
|
show 8 more comments
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 toLiveData
when you want to notify observers.
– Jeel Vankhede
Nov 21 '18 at 7:16
@JeelVankhede I already trieddata.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 ofLiveData
, 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
|
show 8 more comments
1 Answer
1
active
oldest
votes
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
}
});
would you mind to explain what's the difference of usingthis
vsgetViewLifecycleOwner()
?
– jackycflau
Nov 21 '18 at 8:04
1
It changes what theLiveData
binds to. The problem is thatFragment
lives much longer than you might expect. This can lead to observing the sameLiveData
multiple times.getViewLifecycleOwner()
will actually bind to the lifecycle of the fragmentsView
. So when the view hierarchy is destroyed, theLiveData
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 underfetchUser2()
to ensure that the LiveData is being transmitted to, for example. So log infetchUser2()
directly, inonResponse()
and inonFailure()
. Double check that you aren't still usingfetchUser()
in your code, if you just copy and pasted.
– Knossos
Nov 21 '18 at 8:45
|
show 5 more comments
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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
}
});
would you mind to explain what's the difference of usingthis
vsgetViewLifecycleOwner()
?
– jackycflau
Nov 21 '18 at 8:04
1
It changes what theLiveData
binds to. The problem is thatFragment
lives much longer than you might expect. This can lead to observing the sameLiveData
multiple times.getViewLifecycleOwner()
will actually bind to the lifecycle of the fragmentsView
. So when the view hierarchy is destroyed, theLiveData
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 underfetchUser2()
to ensure that the LiveData is being transmitted to, for example. So log infetchUser2()
directly, inonResponse()
and inonFailure()
. Double check that you aren't still usingfetchUser()
in your code, if you just copy and pasted.
– Knossos
Nov 21 '18 at 8:45
|
show 5 more comments
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
}
});
would you mind to explain what's the difference of usingthis
vsgetViewLifecycleOwner()
?
– jackycflau
Nov 21 '18 at 8:04
1
It changes what theLiveData
binds to. The problem is thatFragment
lives much longer than you might expect. This can lead to observing the sameLiveData
multiple times.getViewLifecycleOwner()
will actually bind to the lifecycle of the fragmentsView
. So when the view hierarchy is destroyed, theLiveData
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 underfetchUser2()
to ensure that the LiveData is being transmitted to, for example. So log infetchUser2()
directly, inonResponse()
and inonFailure()
. Double check that you aren't still usingfetchUser()
in your code, if you just copy and pasted.
– Knossos
Nov 21 '18 at 8:45
|
show 5 more comments
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
}
});
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
}
});
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 usingthis
vsgetViewLifecycleOwner()
?
– jackycflau
Nov 21 '18 at 8:04
1
It changes what theLiveData
binds to. The problem is thatFragment
lives much longer than you might expect. This can lead to observing the sameLiveData
multiple times.getViewLifecycleOwner()
will actually bind to the lifecycle of the fragmentsView
. So when the view hierarchy is destroyed, theLiveData
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 underfetchUser2()
to ensure that the LiveData is being transmitted to, for example. So log infetchUser2()
directly, inonResponse()
and inonFailure()
. Double check that you aren't still usingfetchUser()
in your code, if you just copy and pasted.
– Knossos
Nov 21 '18 at 8:45
|
show 5 more comments
would you mind to explain what's the difference of usingthis
vsgetViewLifecycleOwner()
?
– jackycflau
Nov 21 '18 at 8:04
1
It changes what theLiveData
binds to. The problem is thatFragment
lives much longer than you might expect. This can lead to observing the sameLiveData
multiple times.getViewLifecycleOwner()
will actually bind to the lifecycle of the fragmentsView
. So when the view hierarchy is destroyed, theLiveData
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 underfetchUser2()
to ensure that the LiveData is being transmitted to, for example. So log infetchUser2()
directly, inonResponse()
and inonFailure()
. Double check that you aren't still usingfetchUser()
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
|
show 5 more comments
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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