MVVM RXAndroid Cannot invoke setValue on a background thread
In my app i'm requesting a json to fill recyclerview , at the first in init kotlin viewmodel it always successful but when i wanna to request again in the timer.schedule method it goes to onError method in disposable subscribe , here is Edittext's onTextChange that binded in xml view :
fun onSearchTextChanged(text: CharSequence) {
if (text.isNotEmpty()) {
if (myTimer != null) {
myTimer!!.cancel()
}
myTimer = Timer()
myTimer!!.schedule(object : TimerTask() {
override fun run() {
loadMovies(text.toString(), 1)
}
}, 1000)
} else {
if (myTimer != null) {
myTimer!!.cancel()
}
}
}
and here is my request methods :
fun loadMovies(searchText: String, pageNumber: Int) {
subscription = searchApi.getSearch(API_KEY, searchText, pageNumber)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe { onRetrieveMoviesListStart() }
.doOnTerminate { onRetrieveMoviesListFinish() }
.subscribe(
{ result -> onRetrieveMoviesListSuccess(result) },
{ err -> onRetrieveMoviesListError(err) })
}
private fun onRetrieveMoviesListStart() {
loadingVisibility.value = View.VISIBLE
Timber.d("started")
}
private fun onRetrieveMoviesListFinish() {
loadingVisibility.value = View.GONE
Timber.d("finished")
}
private fun onRetrieveMoviesListSuccess(search: Search) {
Timber.d(search.toString())
movieListAdapter.updateMoviesList(search.Search)
movieEvent.value = MovieEvent.ANIMATE_RECYCLER
}
private fun onRetrieveMoviesListError(err: Throwable) {
Timber.e(err)
}
And this is viewModel class declaration :
@Inject
lateinit var searchApi: SearchApi
val movieListAdapter: MovieListAdapter = MovieListAdapter()
private var myTimer: Timer? = null
private val movieEvent = SingleLiveEvent<MovieEvent>()
private lateinit var subscription: Disposable
val loadingVisibility: MutableLiveData<Int> = MutableLiveData()
init {
loadMovies("someText", 1)
}
What should i do ?
android retrofit2 rx-android
add a comment |
In my app i'm requesting a json to fill recyclerview , at the first in init kotlin viewmodel it always successful but when i wanna to request again in the timer.schedule method it goes to onError method in disposable subscribe , here is Edittext's onTextChange that binded in xml view :
fun onSearchTextChanged(text: CharSequence) {
if (text.isNotEmpty()) {
if (myTimer != null) {
myTimer!!.cancel()
}
myTimer = Timer()
myTimer!!.schedule(object : TimerTask() {
override fun run() {
loadMovies(text.toString(), 1)
}
}, 1000)
} else {
if (myTimer != null) {
myTimer!!.cancel()
}
}
}
and here is my request methods :
fun loadMovies(searchText: String, pageNumber: Int) {
subscription = searchApi.getSearch(API_KEY, searchText, pageNumber)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe { onRetrieveMoviesListStart() }
.doOnTerminate { onRetrieveMoviesListFinish() }
.subscribe(
{ result -> onRetrieveMoviesListSuccess(result) },
{ err -> onRetrieveMoviesListError(err) })
}
private fun onRetrieveMoviesListStart() {
loadingVisibility.value = View.VISIBLE
Timber.d("started")
}
private fun onRetrieveMoviesListFinish() {
loadingVisibility.value = View.GONE
Timber.d("finished")
}
private fun onRetrieveMoviesListSuccess(search: Search) {
Timber.d(search.toString())
movieListAdapter.updateMoviesList(search.Search)
movieEvent.value = MovieEvent.ANIMATE_RECYCLER
}
private fun onRetrieveMoviesListError(err: Throwable) {
Timber.e(err)
}
And this is viewModel class declaration :
@Inject
lateinit var searchApi: SearchApi
val movieListAdapter: MovieListAdapter = MovieListAdapter()
private var myTimer: Timer? = null
private val movieEvent = SingleLiveEvent<MovieEvent>()
private lateinit var subscription: Disposable
val loadingVisibility: MutableLiveData<Int> = MutableLiveData()
init {
loadMovies("someText", 1)
}
What should i do ?
android retrofit2 rx-android
add a comment |
In my app i'm requesting a json to fill recyclerview , at the first in init kotlin viewmodel it always successful but when i wanna to request again in the timer.schedule method it goes to onError method in disposable subscribe , here is Edittext's onTextChange that binded in xml view :
fun onSearchTextChanged(text: CharSequence) {
if (text.isNotEmpty()) {
if (myTimer != null) {
myTimer!!.cancel()
}
myTimer = Timer()
myTimer!!.schedule(object : TimerTask() {
override fun run() {
loadMovies(text.toString(), 1)
}
}, 1000)
} else {
if (myTimer != null) {
myTimer!!.cancel()
}
}
}
and here is my request methods :
fun loadMovies(searchText: String, pageNumber: Int) {
subscription = searchApi.getSearch(API_KEY, searchText, pageNumber)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe { onRetrieveMoviesListStart() }
.doOnTerminate { onRetrieveMoviesListFinish() }
.subscribe(
{ result -> onRetrieveMoviesListSuccess(result) },
{ err -> onRetrieveMoviesListError(err) })
}
private fun onRetrieveMoviesListStart() {
loadingVisibility.value = View.VISIBLE
Timber.d("started")
}
private fun onRetrieveMoviesListFinish() {
loadingVisibility.value = View.GONE
Timber.d("finished")
}
private fun onRetrieveMoviesListSuccess(search: Search) {
Timber.d(search.toString())
movieListAdapter.updateMoviesList(search.Search)
movieEvent.value = MovieEvent.ANIMATE_RECYCLER
}
private fun onRetrieveMoviesListError(err: Throwable) {
Timber.e(err)
}
And this is viewModel class declaration :
@Inject
lateinit var searchApi: SearchApi
val movieListAdapter: MovieListAdapter = MovieListAdapter()
private var myTimer: Timer? = null
private val movieEvent = SingleLiveEvent<MovieEvent>()
private lateinit var subscription: Disposable
val loadingVisibility: MutableLiveData<Int> = MutableLiveData()
init {
loadMovies("someText", 1)
}
What should i do ?
android retrofit2 rx-android
In my app i'm requesting a json to fill recyclerview , at the first in init kotlin viewmodel it always successful but when i wanna to request again in the timer.schedule method it goes to onError method in disposable subscribe , here is Edittext's onTextChange that binded in xml view :
fun onSearchTextChanged(text: CharSequence) {
if (text.isNotEmpty()) {
if (myTimer != null) {
myTimer!!.cancel()
}
myTimer = Timer()
myTimer!!.schedule(object : TimerTask() {
override fun run() {
loadMovies(text.toString(), 1)
}
}, 1000)
} else {
if (myTimer != null) {
myTimer!!.cancel()
}
}
}
and here is my request methods :
fun loadMovies(searchText: String, pageNumber: Int) {
subscription = searchApi.getSearch(API_KEY, searchText, pageNumber)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe { onRetrieveMoviesListStart() }
.doOnTerminate { onRetrieveMoviesListFinish() }
.subscribe(
{ result -> onRetrieveMoviesListSuccess(result) },
{ err -> onRetrieveMoviesListError(err) })
}
private fun onRetrieveMoviesListStart() {
loadingVisibility.value = View.VISIBLE
Timber.d("started")
}
private fun onRetrieveMoviesListFinish() {
loadingVisibility.value = View.GONE
Timber.d("finished")
}
private fun onRetrieveMoviesListSuccess(search: Search) {
Timber.d(search.toString())
movieListAdapter.updateMoviesList(search.Search)
movieEvent.value = MovieEvent.ANIMATE_RECYCLER
}
private fun onRetrieveMoviesListError(err: Throwable) {
Timber.e(err)
}
And this is viewModel class declaration :
@Inject
lateinit var searchApi: SearchApi
val movieListAdapter: MovieListAdapter = MovieListAdapter()
private var myTimer: Timer? = null
private val movieEvent = SingleLiveEvent<MovieEvent>()
private lateinit var subscription: Disposable
val loadingVisibility: MutableLiveData<Int> = MutableLiveData()
init {
loadMovies("someText", 1)
}
What should i do ?
android retrofit2 rx-android
android retrofit2 rx-android
asked Jan 1 at 23:19
Ali KhoshraftarAli Khoshraftar
19311
19311
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
Your initial call to loadMovies in the ViewModel init comes from the main/ui thread. The call to loadMovies from the timertask comes from a background thread. Now I don't have too much experience with rx but the problem seems to be related to livedata anyway.
You're observing on the mainthread, which is fine for the success and error methods. Your problem seems to be onRetrieveMoviesListStart() and onRetrieveMoviesListFinish() which are called from a backround thread.
The setter for the value of a livedata can only be called from the main thread, to set the value from a background thread you need to call postValue.
Changing your two methods/functions like this should do the trick:
private fun onRetrieveMoviesListStart() {
loadingVisibility.postValue(View.VISIBLE)
Timber.d("started")
}
private fun onRetrieveMoviesListFinish() {
loadingVisibility.postValue(View.GONE)
Timber.d("finished")
}
It works fine , Thanks :)
– Ali Khoshraftar
Jan 2 at 6:54
add a comment |
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%2f53999701%2fmvvm-rxandroid-cannot-invoke-setvalue-on-a-background-thread%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
Your initial call to loadMovies in the ViewModel init comes from the main/ui thread. The call to loadMovies from the timertask comes from a background thread. Now I don't have too much experience with rx but the problem seems to be related to livedata anyway.
You're observing on the mainthread, which is fine for the success and error methods. Your problem seems to be onRetrieveMoviesListStart() and onRetrieveMoviesListFinish() which are called from a backround thread.
The setter for the value of a livedata can only be called from the main thread, to set the value from a background thread you need to call postValue.
Changing your two methods/functions like this should do the trick:
private fun onRetrieveMoviesListStart() {
loadingVisibility.postValue(View.VISIBLE)
Timber.d("started")
}
private fun onRetrieveMoviesListFinish() {
loadingVisibility.postValue(View.GONE)
Timber.d("finished")
}
It works fine , Thanks :)
– Ali Khoshraftar
Jan 2 at 6:54
add a comment |
Your initial call to loadMovies in the ViewModel init comes from the main/ui thread. The call to loadMovies from the timertask comes from a background thread. Now I don't have too much experience with rx but the problem seems to be related to livedata anyway.
You're observing on the mainthread, which is fine for the success and error methods. Your problem seems to be onRetrieveMoviesListStart() and onRetrieveMoviesListFinish() which are called from a backround thread.
The setter for the value of a livedata can only be called from the main thread, to set the value from a background thread you need to call postValue.
Changing your two methods/functions like this should do the trick:
private fun onRetrieveMoviesListStart() {
loadingVisibility.postValue(View.VISIBLE)
Timber.d("started")
}
private fun onRetrieveMoviesListFinish() {
loadingVisibility.postValue(View.GONE)
Timber.d("finished")
}
It works fine , Thanks :)
– Ali Khoshraftar
Jan 2 at 6:54
add a comment |
Your initial call to loadMovies in the ViewModel init comes from the main/ui thread. The call to loadMovies from the timertask comes from a background thread. Now I don't have too much experience with rx but the problem seems to be related to livedata anyway.
You're observing on the mainthread, which is fine for the success and error methods. Your problem seems to be onRetrieveMoviesListStart() and onRetrieveMoviesListFinish() which are called from a backround thread.
The setter for the value of a livedata can only be called from the main thread, to set the value from a background thread you need to call postValue.
Changing your two methods/functions like this should do the trick:
private fun onRetrieveMoviesListStart() {
loadingVisibility.postValue(View.VISIBLE)
Timber.d("started")
}
private fun onRetrieveMoviesListFinish() {
loadingVisibility.postValue(View.GONE)
Timber.d("finished")
}
Your initial call to loadMovies in the ViewModel init comes from the main/ui thread. The call to loadMovies from the timertask comes from a background thread. Now I don't have too much experience with rx but the problem seems to be related to livedata anyway.
You're observing on the mainthread, which is fine for the success and error methods. Your problem seems to be onRetrieveMoviesListStart() and onRetrieveMoviesListFinish() which are called from a backround thread.
The setter for the value of a livedata can only be called from the main thread, to set the value from a background thread you need to call postValue.
Changing your two methods/functions like this should do the trick:
private fun onRetrieveMoviesListStart() {
loadingVisibility.postValue(View.VISIBLE)
Timber.d("started")
}
private fun onRetrieveMoviesListFinish() {
loadingVisibility.postValue(View.GONE)
Timber.d("finished")
}
answered Jan 2 at 0:47
lukas.bloderlukas.bloder
662
662
It works fine , Thanks :)
– Ali Khoshraftar
Jan 2 at 6:54
add a comment |
It works fine , Thanks :)
– Ali Khoshraftar
Jan 2 at 6:54
It works fine , Thanks :)
– Ali Khoshraftar
Jan 2 at 6:54
It works fine , Thanks :)
– Ali Khoshraftar
Jan 2 at 6:54
add a comment |
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.
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%2f53999701%2fmvvm-rxandroid-cannot-invoke-setvalue-on-a-background-thread%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