MVVM RXAndroid Cannot invoke setValue on a background thread












0















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 ?










share|improve this question



























    0















    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 ?










    share|improve this question

























      0












      0








      0








      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 ?










      share|improve this question














      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






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Jan 1 at 23:19









      Ali KhoshraftarAli Khoshraftar

      19311




      19311
























          1 Answer
          1






          active

          oldest

          votes


















          2














          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")
          }





          share|improve this answer
























          • It works fine , Thanks :)

            – Ali Khoshraftar
            Jan 2 at 6:54











          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%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









          2














          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")
          }





          share|improve this answer
























          • It works fine , Thanks :)

            – Ali Khoshraftar
            Jan 2 at 6:54
















          2














          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")
          }





          share|improve this answer
























          • It works fine , Thanks :)

            – Ali Khoshraftar
            Jan 2 at 6:54














          2












          2








          2







          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")
          }





          share|improve this answer













          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")
          }






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jan 2 at 0:47









          lukas.bloderlukas.bloder

          662




          662













          • 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





          It works fine , Thanks :)

          – Ali Khoshraftar
          Jan 2 at 6:54




















          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.




          draft saved


          draft discarded














          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





















































          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

          Monofisismo

          Angular Downloading a file using contenturl with Basic Authentication

          Olmecas