Skip to content

Instantly share code, notes, and snippets.

@oligazar
Last active December 20, 2019 09:21
Show Gist options
  • Save oligazar/7a92231bbebe483ad0d27547835d2e8d to your computer and use it in GitHub Desktop.
Save oligazar/7a92231bbebe483ad0d27547835d2e8d to your computer and use it in GitHub Desktop.
import android.arch.lifecycle.LiveData
import android.arch.lifecycle.MutableLiveData
import android.arch.paging.PageKeyedDataSource
import android.arch.paging.PagedList
import kotlinx.coroutines.experimental.Dispatchers
import kotlinx.coroutines.experimental.GlobalScope
import kotlinx.coroutines.experimental.android.Main
import kotlinx.coroutines.experimental.launch
import us.kostenko.architecturecomponentstmdb.details.model.Movie
import us.kostenko.architecturecomponentstmdb.details.repository.persistance.MovieDao
import us.kostenko.architecturecomponentstmdb.master.repository.webservice.MoviesWebService
class MoviesRepository(private val webService: MoviesWebService,
private val movieDao: MovieDao) {
// fun getMovies(): LiveData<ArrayList<Movie>> {
// val ldMovies = MutableLiveData<ArrayList<Movie>>()
// GlobalScope.launch {
// val movies = webService.getMovies().await()
// ldMovies.postValue(movies.results)
// }
// return ldMovies
// }
fun getMovies(): LiveData<PagedList<Movie>> {
val movieData = MutableLiveData<PagedList<Movie>>()
val config = PagedList.Config.Builder()
.setPageSize(10)
.setEnablePlaceholders(true).build()
val dataSource = MoviesDataSource()
val list = PagedList.Builder(dataSource, config)
.setFetchExecutor { GlobalScope.launch(Dispatchers.Main) { it.run() } }
.setNotifyExecutor { GlobalScope.launch(Dispatchers.Main) { it.run() } }.build()
movieData.value = list
return movieData
}
// val factory =
// val liveDataPl = LivePagedListBuilder<Int, Movie>(factory, config).build()
inner class MoviesDataSource: PageKeyedDataSource<Int, Movie>() {
override fun loadInitial(params: LoadInitialParams<Int>,
callback: LoadInitialCallback<Int, Movie>) {
GlobalScope.launch {
val response = webService.getMovies(1).await()
if (params.placeholdersEnabled) {
callback.onResult(response.results, 0, response.totalResults, null, 2)
} else {
callback.onResult(response.results, null, 2)
}
}
}
override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, Movie>) {
GlobalScope.launch {
val movies = webService.getMovies(params.key).await().results
callback.onResult(movies, params.key + 1)
}
}
override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Int, Movie>) { }
}
inner class MovieBoundaryCallback: PagedList.BoundaryCallback<Movie>() {
private var isLoading = false
override fun onItemAtEndLoaded(itemAtEnd: Movie) {
super.onItemAtEndLoaded(itemAtEnd)
val position = 1 // TODO: how to compute page?
if (isLoading) return
GlobalScope.launch {
isLoading = true
val response = webService.getMovies(position).await()
movieDao.saveMovies(response.results)
isLoading = false
}
}
}
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
// viewModel.movies.observe(this, Observer {
// Timber.d("movies: $it")
// })
val dataSource = MoviesDataSource(RetrofitManager.createService(activity!!.application, MoviesWebService::class.java))
val config = PagedList.Config.Builder()
.setEnablePlaceholders(false)
.build()
//
val pagedList = PagedList.Builder(dataSource, config)
.setFetchExecutor(Executors.newSingleThreadExecutor())
.setNotifyExecutor(MainThreadExecutor())
.build()
val diffUtilCallback = MovieDiffUtilCallback()
val movieAdapter = MoviesAdapter(diffUtilCallback)
movieAdapter.submitList(pagedList)
recycler.apply {
adapter = movieAdapter
layoutManager = GridLayoutManager(activity, 2)
addItemDecoration(GridItemDecorator(2, 8, 8,true))
setHasFixedSize(true)
}
}
internal inner class MainThreadExecutor : Executor {
private val mHandler = Handler(Looper.getMainLooper())
override fun execute(command: Runnable) {
mHandler.post(command)
}
}
class MoviesDataSource(private val service: MoviesWebService): PageKeyedDataSource<Int, Movie>() {
override fun loadInitial(params: LoadInitialParams<Int>,
callback: LoadInitialCallback<Int, Movie>) {
Timber.d("loadInitial, requestedLoadSize: ${params.requestedLoadSize}, placeholdersEnabled: ${params.placeholdersEnabled}")
service.getMovies(1).enqueue(object: Callback<Movies> {
override fun onFailure(call: Call<Movies>, t: Throwable) {
Timber.d("call: $call, error: $t")
}
override fun onResponse(call: Call<Movies>, response: Response<Movies>) {
val movies = response.body()?.results
if (movies != null) {
callback.onResult(movies, null, 2)
} else {
Timber.d("call: $call, response: $response")
}
}
})
}
override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, Movie>) {
Timber.d("loadAfter, key: ${params.key}, requestedLoadSize: ${params.requestedLoadSize}")
service.getMovies(params.key).enqueue(object: Callback<Movies> {
override fun onFailure(call: Call<Movies>, t: Throwable) {
Timber.d("call: $call, error: $t")
}
override fun onResponse(call: Call<Movies>, response: Response<Movies>) {
val movies = response.body()?.results
if (movies != null) {
callback.onResult(movies, params.key + 1)
} else {
Timber.d("call: $call, response: $response")
}
}
})
}
override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Int, Movie>) { }
// TODO: implement this and save page position in onSavedInstanceState to resume work after app is killed
}
internal inner class MovieDiffUtilCallback: DiffUtil.ItemCallback<Movie>() {
override fun areItemsTheSame(p0: Movie, p1: Movie) = p0.id == p1.id
override fun areContentsTheSame(p0: Movie, p1: Movie) = p0 == p1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment