Recyclerview keep being reset - kotlin

I'm facing a problem with my recycler view, I'd wanted to refresh it every second, for that I use a timer which creates new request, but I think that my recyclerview is destroyed and directly recreated, when I'm scrolling it keep always returning to the top every second. Here is my fragment, I heard about layoutmanager but don't really know how to use it, is it linked?
class DlFragment (private val context: MainActivity): Fragment(){
private var myTimer: Timer? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_dl,container, false)
val dlRecyclerView = view?.findViewById<RecyclerView>(R.id.dl_list_recycle_view)
myTimer = Timer()
myTimer!!.schedule(object : TimerTask() {
override fun run() {
getDlList(dlRecyclerView)
}
}, 0, 1000)
val comfirmButton= view.findViewById<Button>(R.id.input_post_dl_button)
comfirmButton.setOnClickListener { postDl(view) }
return view
}
private fun getDlList(dlRecyclerView: RecyclerView?) {
GlobalScope.launch(Dispatchers.Main) {
try {
val response = ApiClientQnap.apiServiceQnap.getQuery(0,20,"all","all",ApiClientQnap.sid)
if (response.isSuccessful && response.body() != null) {
val content = response.body()
if (content != null) {
//println(content)
//val dlRecyclerView = view?.findViewById<RecyclerView>(R.id.dl_list_recycle_view)
dlRecyclerView?.adapter = DlAdapter(context,content.data)
}
} else { println("Error Occurred: ${response.message()}") }
} catch (e: Exception) {println("Error Occurred: ${e.message}") }
}
}
private fun postDl(view: View){
val url_Dl = view.findViewById<EditText>(R.id.input_post_dl_text)
GlobalScope.launch(Dispatchers.Main) {
try {
val response = ApiClientQnap.apiServiceQnap.postDL("Films","Films",
url_Dl.text.toString(),ApiClientQnap.sid)
if (response.isSuccessful && response.body() != null) {
val content = response.body()
println(response.body())
if (content != null) {
if(content.error == 0) {
Toast.makeText(context, "yeee", Toast.LENGTH_LONG).show()
url_Dl.text.clear()
}
else
Toast.makeText(context, "no", Toast.LENGTH_LONG).show()
}
} else { println("Error Occurred: ${response.message()}") }
} catch (e: Exception) {println("Error Occurred: ${e.message}") }
}
}
Edit: Here's my DlAdapter
class DlAdapter(
val context: MainActivity,
private var dlList: ArrayList<Data>
) : RecyclerView.Adapter<DlAdapter.ViewHolder>() {
class ViewHolder(view : View): RecyclerView.ViewHolder(view){
val dl_title = view.findViewById<TextView>(R.id.dl_title)
val dl_progress = view.findViewById<TextView>(R.id.dl_progress)
val dl_speed = view.findViewById<TextView>(R.id.dl_speed)
val progressBar = view.findViewById<ProgressBar>(R.id.progressBar)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater
.from(parent.context)
.inflate(R.layout.fragment_dl_list,parent,false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val currentDl = dlList[position]
holder.dl_title.text = currentDl.source_name
holder.progressBar.progress = (currentDl.progress!!)
when (currentDl.state) {
5 -> holder.dl_progress.text = ("Terminé")
2 -> holder.dl_progress.text = ("Arrété")
4 -> holder.dl_progress.text = ("Echec")
1 -> holder.dl_progress.text = (currentDl.progress.toString() + " % En pause")
104 -> {
holder.dl_progress.text = (currentDl.progress.toString() + " %")
var toFloat = currentDl.down_rate?.toFloat()
toFloat = toFloat?.div(1000000)
holder.dl_speed.text = (toFloat.toString()+" Mo")
}
}
}
override fun getItemCount(): Int = dlList.size
fun updateData(newData: ArrayList<Data>) {
dlList.clear()
dlList.addAll(newData)
notifyDataSetChanged()
}
}

As #hardartcore suggested, you can try to convert the RecyclerView.Adapter to a ListAdapter and use a DiffUtil.ItemCallback class.
Try to convert your adapter like this:
class DlAdapter : ListAdapter<Data, DlAdapter.ViewHolder>(DlDiffCallback()) {
class ViewHolder(view : View): RecyclerView.ViewHolder(view){
val dl_title = view.findViewById<TextView>(R.id.dl_title)
val dl_progress = view.findViewById<TextView>(R.id.dl_progress)
val dl_speed = view.findViewById<TextView>(R.id.dl_speed)
val progressBar = view.findViewById<ProgressBar>(R.id.progressBar)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater
.from(parent.context)
.inflate(R.layout.fragment_dl_list,parent,false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// Use the getItem method to retrieve a specific item
val currentDl = getItem(position)
holder.dl_title.text = currentDl.source_name
holder.progressBar.progress = (currentDl.progress!!)
when (currentDl.state) {
5 -> holder.dl_progress.text = ("Terminé")
2 -> holder.dl_progress.text = ("Arrété")
4 -> holder.dl_progress.text = ("Echec")
1 -> holder.dl_progress.text = (currentDl.progress.toString() + " % En pause")
104 -> {
holder.dl_progress.text = (currentDl.progress.toString() + " %")
var toFloat = currentDl.down_rate?.toFloat()
toFloat = toFloat?.div(1000000)
holder.dl_speed.text = (toFloat.toString()+" Mo")
}
}
}
}
class DlDiffCallback : DiffUtil.ItemCallback<Data>() {
// Change this method comparisons based on your equality conditions
override fun areItemsTheSame(oldItem: DataItem, newItem: DataItem): Boolean = oldItem.id == newItem.id
override fun areContentsTheSame(oldItem: DataItem, newItem: DataItem): Boolean = oldItem == newItem
}
You can then update your RecyclerView adapter by using the submitList method:
val adapter = DlAdapter()
adapter.submitList(content.data)

Related

how do i update items that change in recyclerview use diffutil?

DiffUtil do not update items recyclerview with the same id and not same the content,
The model has [id : Int and title : String]. I want to the diffUtilCallBack check items with the same id and not same title and update to recyclerview
Please help me fix it
my DiffUtil CallBAck
class DiffCB(
val oldl : ArrayList<Test>,
val newl : ArrayList<Test>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int {
return oldl.size
}
override fun getNewListSize(): Int {
return newl.size
}
override fun areItemsTheSame(oldItemPos: Int, newItemPos: Int): Boolean {
return oldl[oldItemPos].id == newl[newItemPos].id
}
override fun areContentsTheSame(oldItemPos: Int, newItemPos: Int): Boolean {
return oldl[oldItemPos].title.equals(newl[newItemPos].title)
}
}
my Adapter.kt
class TestAdapter(val click: TestClick) :
RecyclerView.Adapter<TestAdapter.TestVH>() {
var list: ArrayList<Test> = ArrayList()
inner class TestVH(val bin: ItemTestBinding) : RecyclerView.ViewHolder(bin.root) {
fun bind(test: Test) {
bin.tvTestId.text = "[id: ${test.id}]"
bin.tvTestTitle.text = test.title
bin.cbTest.isChecked = test.select
bin.cbTest.setOnClickListener {
click.click(test)
}
}
}
fun sumbitData(newl: ArrayList<Test>) {
val diff = DiffCB(this.list, newl)
val diffResult = DiffUtil.calculateDiff(diff)
list.clear()
this.list.addAll(newl)
diffResult.dispatchUpdatesTo(this)
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: TestVH, position: Int) {
holder.bind(list[position])
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TestVH {
return TestVH(ItemTestBinding.inflate(LayoutInflater.from(parent.context),
parent, false))
}
}
my Activity.kt
class TestActivity : AppCompatActivity(), TestClick {
private var list : ArrayList<Test> = ArrayList()
private lateinit var bin : ActivityTestBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bin = ActivityTestBinding.inflate(layoutInflater)
setContentView(bin.root)
val viewModel = ViewModelProviders.of(this).get(TestViewModel::class.java)
val manager = LinearLayoutManager(this)
bin.rvTest.layoutManager = manager
val adapter = TestAdapter(this)
bin.rvTest.adapter = adapter
//init first data
viewModel.setTests(initData())
viewModel.getTests().observe(this, Observer {
adapter.sumbitData(it as ArrayList<Test>)
})
bin.btnTest.setOnClickListener{
viewModel.setTests(updateData())
}
}
fun updateData() : ArrayList<Test> {
for (i in 2..6) {
var test = Test()
test.id = i
test.title = "title test $i update"
list.add(test)
}
return list
}
fun initData() : ArrayList<Test> {
for (i in 1..3) {
var test = Test()
test.id = i
test.title = "title test $i"
list.add(test)
}
return list
}
override fun click(test: Test) {
Toast.makeText(this, "${test.id} ${test.title}", Toast.LENGTH_SHORT).show()
}
}
it is first data
after update data, items with the same id have not been updated (id 2, 3)

Two recycler view on same fragment, holder or db brings wrong data when I select item

Like title I can't get correct item data, now imagine I have 2 recycler view list on my main fragment, one recycler view is vertical, other horizontal. If I use only one recycler everything is working fine. But when I add other one it's opening items randomly, but that random data openings only random both recyclers positions. Like my first recycler have [a,b,c,d] , other recycler have [e,f,g,h]. When I click first item of first recycler its go to other fragment which shows detail, its opening e instead of a, if I go back and retry it, its opening e again, retry and its a !! so its opening randomly, why this is happening why can't I open correct data? I put Log.d on my adapters and when I click recycler items, adapters log says u clicked "a" but my detail fragment shows me data of "e". What I am doing wrong? Here is my codes:(I have lots of codes so I share what we need)
my databases TvDAO:
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import com.bt.filmdenemesi.model.Result
#Dao
interface TVDAO {
//Veri erişim nesnesi
#Insert
suspend fun insertAll(vararg movie: Result) : List<Long>
#Query("SELECT * FROM Result")
suspend fun getAllTV() : List<Result>
#Query("SELECT * FROM Result WHERE uuid2=:diziId")
suspend fun getTV(diziId:Int) : Result
#Query("DELETE FROM Result")
suspend fun deleteAllTV(
)
}
Tv Database:
#Database(entities = arrayOf(Result::class), version = 1)
abstract class TvDatabase: RoomDatabase() {
abstract fun tvDao(): TVDAO
companion object{
#Volatile
private var INSTANCE: TvDatabase?=null
fun databaseOlustur2(context: Context): TvDatabase {
return INSTANCE ?: synchronized(this){
val instance = Room.databaseBuilder(context.applicationContext,TvDatabase::class.java, "tvdatabase").fallbackToDestructiveMigration().build()
INSTANCE=instance
instance
}
}
}
}
movie Dao:
#Dao
interface MovieDAO {
//Veri erişim nesnesi
#Insert
suspend fun insertAll(vararg movie: Movie) : List<Long>
#Query("SELECT * FROM Movie")
suspend fun getAllMovie() : List<Movie>
#Query("Select * from Movie where uuid=:movieId")
suspend fun getMovie(movieId:Int) : Movie
#Query("Delete from Movie")
suspend fun deleteAllMovie(
)
}
movie database:
#Database(entities = arrayOf(Movie::class ), version = 1)
abstract class MovieDatabase:RoomDatabase() {
abstract fun movieDao(): MovieDAO
//singleton
companion object{
#Volatile private var instance: MovieDatabase? = null
private val lock = Any()
operator fun invoke(context: Context) = instance ?: synchronized(lock){
instance?: databaseOlustur(context).also {
instance = it
}
}
private fun databaseOlustur(context: Context)= Room.databaseBuilder(
context.applicationContext,
MovieDatabase::class.java,"moviedatabase").build()
}
}
my adapters:
class vizyonrecycleradapter(val diziListesi: ArrayList<Result>):RecyclerView.Adapter<vizyonrecycleradapter.DiziViewHolder>() {
class DiziViewHolder(itemview: View) : RecyclerView.ViewHolder(itemview)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DiziViewHolder {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.now_playing_recycler_row, parent, false)
return DiziViewHolder(view)
}
override fun onBindViewHolder(holder: DiziViewHolder, konum: Int) {
holder.itemView.tv_ismi.text=diziListesi.get(konum).name
val fotoDenemeleri = "https://image.tmdb.org/t/p/w500"
val fotobirlestirme: String = "${fotoDenemeleri}"+ diziListesi.get(konum).posterPath
holder.itemView.vizyon.gorselIndir(fotobirlestirme, placeHolderYap(holder.itemView.context))
holder.itemView.setOnClickListener {
val action2 = AnaSayfaDirections.actionAnaSayfaToDetaySayfasi(diziListesi[konum].uuid2)
Log.d("movie-title","${diziListesi.get(konum).originalName}")
Navigation.findNavController(it).navigate(action2)
}
}
override fun getItemCount(): Int {
return diziListesi.size
}
fun diziListesiniGuncelle(yeniDiziListesi: List<Result>) {
diziListesi.clear()
diziListesi.addAll(yeniDiziListesi)
notifyDataSetChanged()
}
}
other adapter:
class MovieRecyclerAdapter(val movieListesi: ArrayList<Movie>):RecyclerView.Adapter<MovieRecyclerAdapter.MovieViewHolder>() {
class MovieViewHolder(itemview: View) :RecyclerView.ViewHolder(itemview)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MovieViewHolder {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.movie_recycler_row,parent,false)
return MovieViewHolder(view)
}
override fun onBindViewHolder(holder: MovieViewHolder, position: Int) {
holder.itemView.movieId.text= movieListesi.get(position).title
val fotoDenemeleri = "https://image.tmdb.org/t/p/w500"
val fotobirlestirme: String = "${fotoDenemeleri}"+movieListesi.get(position).backdropPath
holder.itemView.ana_foto.gorselIndir(fotobirlestirme, placeHolderYap(holder.itemView.context))
holder.itemView.setOnClickListener {
val action = AnaSayfaDirections.actionAnaSayfaToDetaySayfasi(movieListesi.get(position).uuid)
Log.d("movie-title","${movieListesi.get(position).title}")
Navigation.findNavController(it).navigate(action)
}
}
override fun getItemCount(): Int {
return movieListesi.size
}
fun movieListesiniGuncelle(yeniMovieListesi: List<Movie>){
movieListesi.clear()
movieListesi.addAll(yeniMovieListesi)
notifyDataSetChanged()
}
}
my base ViewModel:
open class BaseViewModel(application: Application) : AndroidViewModel(application),CoroutineScope {
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun onCleared() {
super.onCleared()
job.cancel()
}
}
detail ViewModel:
class MovieDetayiViewModel(application: Application): BaseViewModel(application) {
val diziLiveData = MutableLiveData<Result>()
val movieLiveData = MutableLiveData<Movie>()
val aramaLiveData = MutableLiveData<ResultX>()
fun roomVerisiniAl2(uuid2: Int){
launch {
val dao2=TvDatabase.databaseOlustur2(getApplication()).tvDao().getTV(uuid2)
//val dizi = dao.getTV(uuid2)
diziLiveData.value=dao2
}
}
fun roomVerisiniAl(uuid: Int){
launch {
val dao= MovieDatabase(getApplication()).movieDao().getMovie(uuid)
// val film = dao.getMovie(uuid)
movieLiveData.value=dao
}
}
fun roomVerisiniAl3(uuid3: Int){
launch {
val dao= AramaDatabase(getApplication()).aramaDao()
val arama = dao.getMovie(uuid3)
aramaLiveData.value=arama
}
}
}
movielistviewmvdel:
class MovieListesiViewModel(application: Application): BaseViewModel(application){
val filmler = MutableLiveData<List<Movie>>()
val dizi = MutableLiveData<List<Result>>()
val arama = MutableLiveData<List<ResultX>>()
val filmHataMesaji = MutableLiveData<Boolean>()
val filmYukleniyor = MutableLiveData<Boolean>()
private var guncellemeZamani = 1 * 60 * 1000 * 1000 * 1000L
private val filmApiServis = FilmAPIServis()
private val disposable = CompositeDisposable()
private val disposable2 = CompositeDisposable()
private val disposable3 = CompositeDisposable()//kullan at
private val ozelSharedPrefences = OzelSharedPrefences(getApplication())
fun refreshData(){
val kaydedilmeZamani = ozelSharedPrefences.zamaniAl()
if(kaydedilmeZamani != null && kaydedilmeZamani !=0L && System.nanoTime()-kaydedilmeZamani < guncellemeZamani){
verileriSQLitedenAl()
}else{
verileriInternettenAl()
}
}
fun refreshFromInternet(){
verileriInternettenAl()
}
private fun verileriSQLitedenAl(){
filmYukleniyor.value = true
launch {
val movieListesi = MovieDatabase(getApplication()).movieDao().getAllMovie()
movieleriGoster(movieListesi)
val diziListesi = TvDatabase.databaseOlustur2(getApplication()).tvDao().getAllTV()
tvleriGoster(diziListesi)
}
launch {
val aramaListesi = AramaDatabase(getApplication()).aramaDao().getAllMovie()
aramalariGoster(aramaListesi)
}
}
private fun verileriInternettenAl(){
filmYukleniyor.value = true
disposable.add(
filmApiServis.getData()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(object: DisposableSingleObserver<GetMoviesResponse>(){
override fun onSuccess(t: GetMoviesResponse) {
filmler.value= t.results
filmHataMesaji.value=false
filmYukleniyor.value=false
sqliteSakla(t.results)
// Toast.makeText(getApplication(),"Filmler internetten yüklendi",Toast.LENGTH_LONG).show()
}
override fun onError(e: Throwable) {
filmHataMesaji.value=true
filmYukleniyor.value=false
e.printStackTrace()
}
})
)
disposable2.add(
filmApiServis.getVizyondakiler()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(object: DisposableSingleObserver<NowPlaying>(){
override fun onSuccess(t: NowPlaying) {
dizi.value= t.results
filmHataMesaji.value=false
filmYukleniyor.value=false
diziSqLiteSakla(t.results)
}
override fun onError(e: Throwable) {
filmHataMesaji.value=true
filmYukleniyor.value=false
e.printStackTrace()
}
})
)
}
fun aramayiInternettenAl(denemeText:String){
disposable3.add(
filmApiServis.getArama(denemeText)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(object: DisposableSingleObserver<search>(){
override fun onSuccess(t: search) {
arama.value= t.results
aramaSqliteSakla(t.results)
}
override fun onError(e: Throwable) {
e.printStackTrace()
}
})
)
}
private fun movieleriGoster(filmlerListesi : List<Movie>?){
filmler.value= filmlerListesi
filmHataMesaji.value=false
filmYukleniyor.value=false
}
private fun tvleriGoster(tvListesi: List<Result>?){
dizi.value= tvListesi
filmHataMesaji.value=false
filmYukleniyor.value=false
}
private fun aramalariGoster(aramaListesi: List<ResultX>){
arama.value= aramaListesi
}
private fun sqliteSakla(filmListesi : List<Movie>){
launch {
val dao = MovieDatabase(getApplication()).movieDao()//dao içerisindeki fonksiyonlara ulaşmak için
dao.deleteAllMovie()
val uuidListesi = dao.insertAll(*filmListesi.toTypedArray())//tek tek movie haline getirmek için typed array. (*) koymak lazım
var i = 0
while (i < filmListesi.size){
filmListesi[i].uuid = uuidListesi[i].toInt()//uuid ye ulaştık modemdeki idleri eşledik
i = i + 1
}
movieleriGoster(filmListesi)
}
ozelSharedPrefences.zamaniKaydet(System.nanoTime())
}
private fun diziSqLiteSakla(diziListesi : List<Result>){
launch {
val dao2 = TvDatabase.databaseOlustur2(getApplication()).tvDao()//dao içerisindeki fonksiyonlara ulaşmak için
dao2.deleteAllTV()
val uuidListesi2 = dao2.insertAll(*diziListesi.toTypedArray())//tek tek movie haline getirmek için typed array. (*) koymak lazım
var i = 0
while (i < diziListesi.size){
diziListesi[i].uuid2 = uuidListesi2[i].toInt()//uuid ye ulaştık modemdeki idleri eşledik
i = i + 1
}
tvleriGoster(diziListesi)
}
ozelSharedPrefences.zamaniKaydet(System.nanoTime())
}
private fun aramaSqliteSakla(aramaListesi : List<ResultX>){
launch {
val dao = AramaDatabase(getApplication()).aramaDao()//dao içerisindeki fonksiyonlara ulaşmak için
dao.deleteAllMovie()
val uuidListesi3 = dao.insertAll(*aramaListesi.toTypedArray())//tek tek movie haline getirmek için typed array. (*) koymak lazım
var i = 0
while (i < aramaListesi.size){
aramaListesi[i].uuid3 = uuidListesi3[i].toInt()//uuid ye ulaştık modemdeki idleri eşledik
i = i + 1
}
arama.value?.let { aramalariGoster(it) }
}
ozelSharedPrefences.zamaniKaydet(System.nanoTime())
}
}
and this is my detail page fragment codes:
class DetaySayfasi : Fragment() {
private lateinit var viewModel : MovieDetayiViewModel
private lateinit var viewModel2: MovieListesiViewModel
var movieId : Int = 0
var getId : String =""
var listeIdAlma : Int = 0
private val ozelSharedPrefences2 = OzelSharedPrefences()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_detay_sayfa, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel2 = ViewModelProviders.of(this).get(MovieListesiViewModel::class.java)
viewModel2.refreshData()
arguments?.let {
movieId = DetaySayfasiArgs.fromBundle(it).movieID
}
viewModel = ViewModelProviders.of(this).get(MovieDetayiViewModel::class.java)
viewModel.roomVerisiniAl(movieId)
observeLiveData2()
viewModel.roomVerisiniAl2(movieId)
observeLiveData()
viewModel.roomVerisiniAl3(movieId)
dislike.setOnClickListener {
like()
}
like.setOnClickListener {
dislike()
}
observeLiveData3()
geri()
uygulamaPaylas()
}
fun observeLiveData(){
viewModel.movieLiveData.observe(viewLifecycleOwner, Observer { movie->
movie?.let {
getId = "movie/"+"${it.id}"
listeIdAlma= it.id
movie_title.text=it.title
movie_overview.text= it.overview
movie_rating_text.text=it.voteAverage.toFloat().toString()
movie_rating.rating = it.voteAverage.toFloat()/2
context?.let {
movie_backdrop.gorselIndir("https://image.tmdb.org/t/p/w500"+"${movie.backdropPath}", placeHolderYap(it))
movie_poster.gorselIndir("https://image.tmdb.org/t/p/w500"+"${movie.posterPath}", placeHolderYap(it))
}
if (!(listeIdAlma in ozelSharedPrefences2.korku())){
Log.d("ozelshared","${ozelSharedPrefences2.korku()}")
Log.d("listetaramaid","${listeIdAlma}")
like.visibility=View.GONE
dislike.visibility=View.VISIBLE
}else{
like.visibility=View.VISIBLE
dislike.visibility=View.GONE
Log.d("else","like kapalı olması lazım")
}
}
})
}
fun observeLiveData2(){
viewModel.diziLiveData.observe(viewLifecycleOwner, Observer { tv->
tv?.let {
getId = "tv/"+"${it.id}"
listeIdAlma = it.id
movie_title.text=it.name
movie_overview.text= it.overview
movie_rating_text.text= it.voteAverage?.toFloat().toString()
movie_rating.rating = it.voteAverage!!.toFloat()/2
context?.let {
movie_backdrop.gorselIndir("https://image.tmdb.org/t/p/w500"+"${tv.backdropPath}", placeHolderYap(it))
movie_poster.gorselIndir("https://image.tmdb.org/t/p/w500"+"${tv.posterPath}", placeHolderYap(it))
}
if (!(listeIdAlma in ozelSharedPrefences2.korku())){
Log.d("ozelshared","${ozelSharedPrefences2.korku()}")
Log.d("listetaramaid","${listeIdAlma}")
like.visibility=View.GONE
dislike.visibility=View.VISIBLE
}else{
like.visibility=View.VISIBLE
dislike.visibility=View.GONE
Log.d("else","like kapalı olması lazım")
}
}
})
}
fun observeLiveData3(){
viewModel.aramaLiveData.observe(viewLifecycleOwner, Observer { tv->
tv?.let {
if (it.voteAverage!=null){
getId = "tv/"+"${it.id}"
listeIdAlma = it.id!!
movie_title.text=it.name
movie_overview.text= it.overview
movie_rating_text.text= it.voteAverage?.toFloat().toString()
movie_rating.rating = it.voteAverage?.toFloat()!!/2
context?.let {
movie_backdrop.gorselIndir("https://image.tmdb.org/t/p/w500"+"${tv.backdropPath}", placeHolderYap(it))
movie_poster.gorselIndir("https://image.tmdb.org/t/p/w500"+"${tv.posterPath}", placeHolderYap(it))
}
}else{
getId = "tv/"+"${it.id}"
listeIdAlma = it.id!!
movie_title.text=it.name
movie_overview.text= it.name
movie_rating_text.text= ""
movie_rating.rating = 10F
context?.let {
movie_backdrop.gorselIndir("https://image.tmdb.org/t/p/w500"+"${tv.profile_path}", placeHolderYap(it))
movie_poster.gorselIndir("https://image.tmdb.org/t/p/w500"+"${tv.profile_path}", placeHolderYap(it))
}
}
if (!(listeIdAlma in ozelSharedPrefences2.korku())){
Log.d("ozelshared","${ozelSharedPrefences2.korku()}")
Log.d("listetaramaid","${listeIdAlma}")
like.visibility=View.GONE
dislike.visibility=View.VISIBLE
}else{
like.visibility=View.VISIBLE
dislike.visibility=View.GONE
Log.d("else","like kapalı olması lazım")
}
}
})
}
Like I said if I delete my one of recycler view its working perfect but if I use two recycler on same fragment I got wrong datas. Logs says I open correct data but it's not.
If u need my other codes to solve problem say it please I have lots of screens don't know which one I need to share to solve it.
i solved my problem but i don't know what i changed on background
i just seperate my one function to two function in MovieListesiViewmodel and gave a parameter and its worked like a miracle
private fun verileriInternettenAl(denemeInt: Int){
filmYukleniyor.value = true
disposable.add(
filmApiServis.getData(denemeInt)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(object: DisposableSingleObserver<GetMoviesResponse>(){
override fun onSuccess(t: GetMoviesResponse) {
filmler.value= t.results
filmHataMesaji.value=false
filmYukleniyor.value=false
sqliteSakla(t.results)
// Toast.makeText(getApplication(),"Filmler internetten yüklendi",Toast.LENGTH_LONG).show()
}
override fun onError(e: Throwable) {
filmHataMesaji.value=true
filmYukleniyor.value=false
e.printStackTrace()
}
})
)
}
fun verileriInternettenAl2(){
disposable2.add(
filmApiServis.getVizyondakiler()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(object: DisposableSingleObserver<NowPlaying>(){
override fun onSuccess(t: NowPlaying) {
dizi.value= t.results
filmHataMesaji.value=false
filmYukleniyor.value=false
diziSqLiteSakla(t.results)
}
override fun onError(e: Throwable) {
filmHataMesaji.value=true
filmYukleniyor.value=false
e.printStackTrace()
}
})
)
}

i want to add next page (every page is 10) to my recyclerview but it delet my last page

my recyclerview fragment:
this is the fragment that I set my recycler view , I want when touch the continue button (btn_continue) add the rest of the list, which is actually the next page, to my list when I click the button
But it deletes the previous list and displays the new list
and i use the kotlin coruotine, viewmodel and recyclerview
class AllUnpublishedAdsFragment : Fragment() {
lateinit var unpublishedAdsAdapter: UnpublishedAdsAdapter
var items = ArrayList<M_Ads>()
lateinit var loadMoreItems: ArrayList<M_Ads>
lateinit var scrollListener: RecyclerViewLoadMoreScroll
lateinit var mLayoutManager: RecyclerView.LayoutManager
val page = "1"
var newpage = page.toInt()
var navController: NavController? = null
lateinit var btn_continue: Button
private lateinit var viewModel: MainViewmodels
lateinit var token: String
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_all_unpublished_ads, container,
false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btn_continue = view.findViewById<Button>(R.id.btn_continueAds)
token = arguments?.getString(TOKEN_KEY).toString()
Log.i("TOKEN", token)
setupViewModel(token, page)
continueAds()
unpublishedAdsAdapter.itemClickListener = { item, position ->
val id = item.id
val bundle_id = Bundle()
bundle_id.putString(ID_KEY, id.toString())
navController = Navigation.findNavController(view)
//view.findNavController().navigate(R.id.action_UnpublishedAds_to_Detail,
bundle_id)
navController!!.navigate(
R.id.action_allUnpublishedAdsFragment_to_adsDetailFragment,
bundle_id
)
}
}
private fun setupViewModel(token: String, page: String) {
LoadingDialog.show(requireContext(), { ld ->
recy_unpublished_ads.layoutManager = LinearLayoutManager(activity)
val decoration = DividerItemDecoration(activity, DividerItemDecoration.VERTICAL)
recy_unpublished_ads.addItemDecoration(decoration)
viewModel = ViewModelProvider(this).get(MainViewmodels::class.java)
unpublishedAdsAdapter = UnpublishedAdsAdapter()
recy_unpublished_ads.adapter = unpublishedAdsAdapter
viewModel.adsListObserve().observe({ lifecycle }, { model ->
items.clear()
items.addAll(model.adsList!!)
unpublishedAdsAdapter.setUpdateData(items)
ld.dismiss()
btn_continue.visibility = View.VISIBLE
})
viewModel.getAdsList(token, page)
})
}
fun continueAds() {
var isTouched=false
btn_continue.setOnClickListener {
isTouched=true
newpage = newpage + 1
Log.i("CONTINUE", newpage.toString())
setupViewModel(token, newpage.toString())
unpublishedAdsAdapter.notifyDataSetChanged()
isTouched=false
}
}
RetrofitInstance class
class RetrofitInstance {
companion object{
fun getRetrofitInstance (): Retrofit{
// val interceptor = HttpLoggingInterceptor()
// interceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
// val client: OkHttpClient = OkHttpClient.Builder().addInterceptor(interceptor).build()
val okHttpClient: OkHttpClient = OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.build()
return Retrofit.Builder()
.baseUrl(BASEURL)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build()
}
}
}
my adapter:
class UnpublishedAdsAdapter : RecyclerView.Adapter<UnpublishedAdsAdapter.MyViewHolder>() {
var items = ArrayList<M_Ads>()
var itemClickListener: ((item: M_Ads, position: Int) -> Unit)? = null
lateinit var mcontext: Context
class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
class LoadingViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
fun setUpdateData(items: ArrayList<M_Ads>) {
this.items = items
notifyDataSetChanged()
}
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val img_ads = view.findViewById<ImageView>(R.id.img_recy_ads)
val txt_title = view.findViewById<TextView>(R.id.txt_recy_ads_title)
val txt_accountType = view.findViewById<TextView>(R.id.txt_recy_ads_acctype)
fun bind(data: M_Ads) {
txt_title.setText(data.title)
txt_accountType.setText(data.accountType)
if (!data.image1.equals("")) {
Picasso.with(img_ads.context).load(data.image1).into(img_ads)
} else {
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
mcontext = parent.context
return if (viewType == Constant.VIEW_TYPE_ITEM) {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.row_recy_unpublished_ads, parent, false)
MyViewHolder(view)
} else {
val view =
LayoutInflater.from(mcontext).inflate(R.layout.progress_loading, parent, false)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
view.progressbar.indeterminateDrawable.colorFilter =
BlendModeColorFilter(Color.WHITE, BlendMode.SRC_ATOP)
} else {
view.progressbar.indeterminateDrawable.setColorFilter(
Color.WHITE,
PorterDuff.Mode.MULTIPLY
)
}
MyViewHolder(view)
}
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(items.get(position))
handleClick(holder)
}
fun handleClick(holder: UnpublishedAdsAdapter.MyViewHolder) {
holder.itemView.setOnClickListener {
val position = holder.adapterPosition
itemClickListener?.invoke(items.get(position), position)
}
}
override fun getItemCount(): Int {
return items.size
}
my Viewmodel:
class MainViewmodels:ViewModel() {
lateinit var getAds:MutableLiveData<Main_ModelAds>
init {
getAds= MutableLiveData<Main_ModelAds>()
}
fun adsListObserve():MutableLiveData<Main_ModelAds>{
return getAds
}
fun getAdsList(token:String,page:String){
viewModelScope.launch(Dispatchers.IO) {
try {
Log.i("ERRORRES",token + "")
val retrofitInstance=RetrofitInstance.getRetrofitInstance().create(RetrofitService::class.java)
val response=retrofitInstance.unPublishedAdsList(token,page)
getAds.postValue(response)
}catch (ex:Exception){
Log.i("ERRORRES", ex.message.toString() + "")
}
}
}
What you want here is to update the list that you are showing when the user clicks the button.
In this case you should use ListAdapter.
You can refer to this article for implementation:
https://developer.android.com/reference/androidx/recyclerview/widget/ListAdapter

How to call a method of a fragment from adapter class?

I have seen many questions like this but they are not the same as my situation and I couldn't use those solutions.
I have a fragment (OrdersByStatusFragment.kt) and the method I want to call from the adapter is getOrderStatusList()
class OrdersByStatusFragment : BaseFragment() {
private lateinit var binding: OrderStatusLayoutBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_orders_by_status, container, false)
}
override fun onResume() {
super.onResume()
getOrderStatusList()
}
fun getOrderStatusList() {
showProgressDialog(resources.getString(R.string.please_wait))
FirestoreClass().getOrderStatusList(this#OrdersByStatusFragment)
}
fun successOrderStatusList(orderStatusList: ArrayList<OrderStatus>) {
hideProgressDialog()
if (orderStatusList.size > 0) {
rv_order_by_status.visibility = View.VISIBLE
tv_no_orders_by_status_found.visibility = View.GONE
rv_order_by_status.layoutManager = LinearLayoutManager(activity)
rv_order_by_status.setHasFixedSize(true)
val orderStatusListAdapter =
OrderStatusListAdapter(requireActivity(), orderStatusList)
rv_order_by_status.adapter = orderStatusListAdapter
} else {
rv_order_by_status.visibility = View.GONE
tv_no_orders_by_status_found.visibility = View.VISIBLE
}
}
fun successNewOrderStatus() {
Toast.makeText(requireContext(), "Success", Toast.LENGTH_SHORT).show()
}
}
Adapter OrderStatusListAdapter.kt
open class OrderStatusListAdapter(
private val context: Context,
private var list: ArrayList<OrderStatus>,
) : RecyclerView.Adapter<OrderStatusListAdapter.MyViewHolder>() {
class MyViewHolder(var binding: OrderStatusLayoutBinding) :
RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(
OrderStatusLayoutBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val model = list[position]
if (true) {
GlideLoader(context).loadProductPicture(
model.image,
holder.itemView.iv_order_status_item_image
)
val dateFormat = "dd MMM yyyy HH:mm"
val formatter = SimpleDateFormat(dateFormat, Locale.getDefault())
val calendar: Calendar = Calendar.getInstance()
calendar.timeInMillis = model.order_datetime
val orderDateTime = formatter.format(calendar.time)
holder.itemView.tv_order_status_order_date.text = orderDateTime
holder.itemView.tv_order_status_item_name.text = model.items[0].title
holder.itemView.tv_order_status_item_price.text = "$${model.total_amount}"
holder.itemView.tv_order_status.text = model.order_status
holder.itemView.tv_order_status_order_id.text = model.id
holder.binding.spnOrderChangeStatus.onItemSelectedListener =
object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
holder.binding.tvSpinnerValue.text =
parent?.getItemAtPosition(position).toString()
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
holder.binding.btnOrderStatusChangeStatus.setOnClickListener {
Toast.makeText(context, "Button Clicked", Toast.LENGTH_SHORT).show()
FirestoreClass().updateOrderStatus(
model.id,
holder.binding.tvSpinnerValue.text.toString()
)
Toast.makeText(context, "DB Updated", Toast.LENGTH_SHORT).show()
}
holder.itemView.ib_order_status_delete_product.visibility = View.GONE
holder.itemView.setOnClickListener {
val intent = Intent(context, SoldProductDetailsActivity::class.java)
intent.putExtra(Constants.EXTRA_SOLD_PRODUCT_DETAILS, model)
context.startActivity(intent)
}
}
}
}
As you can see the fun getOrderStatusList() in the OrdersByStatusFragment.kt is actually calling a method in the FirestoreClass.kt. Following is the getOrderStatusList() in the FirestoreClass.kt
fun getOrderStatusList(fragment: OrdersByStatusFragment) {
mFireStore.collection(Constants.ORDERS)
.whereIn("order_status", listOf("Pending", "In process"))
.get()
.addOnSuccessListener { document ->
val list: ArrayList<OrderStatus> = ArrayList()
for (i in document.documents) {
val orderStatus = i.toObject(OrderStatus::class.java)!!
orderStatus.id = i.id
list.add(orderStatus)
}
fragment.successOrderStatusList(list)
}
.addOnFailureListener {
fragment.hideProgressDialog()
}
}
The way I solved something like this is to pass a reference to the method into the adapter's constructor, then you can call the method in the adapter.
See kotlin-how-to-pass-a-function-as-parameter-to-another
In general, the link shows a class containing a method called buz.
Let's say your adapter has a constructor like:
class MyAdapter (private val context: Context, val buzz: () -> Unit) : RecyclerView.Adapter<RecyclerView.ViewHolder>()
then you can create the adapter like
MyAdapter(applicationContext, ::buz)
In the adapter the method can be called normally:
buzz()

display list view in fragment kotlin

l want display my list view in fragment , l used separated listview adpater .
l got error in class adapter under line val view : View = LayoutInflater.from(context,this).inflate(R.layout.arr_list,parent,false)
class fragment
class fragment_Arr :Fragment(), View.OnClickListener {
override fun onClick(v: View?) {
// val intent = Intent(context, FlightsArrbefor::class.java)
// context!!.startActivity(intent)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_arrivel,container,false)
val url = "xxxxxxxx/airport.json?code=BGW"
Arr().execute(url)
return view
}
inner class Arr : AsyncTask<String, String, String>(){
override fun onPreExecute() {
super.onPreExecute()
}
// for build connection
override fun doInBackground(vararg url: String?): String{
var text : String
val connection = URL(url[0]).openConnection() as HttpURLConnection
try {
connection.connect()
text = connection.inputStream.use { it.reader().use{reader -> reader.readText()} }
} finally{
connection.disconnect()
}
return text
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
handleJson(result)
}
override fun onProgressUpdate(vararg text: String?) {
}
#SuppressLint("WrongViewCast")
private fun handleJson (jsonString: String?) {
val jsonObj = JSONObject(jsonString)
val result = jsonObj.getJSONObject("result")
val response = result.getJSONObject("respe")
val airport = response.getJSONObject("airport")
val pluginData = airport.getJSONObject("Data")
val schedule = pluginData.getJSONObject("schedule")
val arrivals = schedule.getJSONObject("arrivals")
// val data = arrivals.getJSONObject("data")
val jsonArray = JSONArray(arrivals.get("data").toString())
val list = ArrayList<FlightShdu>()
var x = 0
while (x < jsonArray.length()) {
val jsonObject = jsonArray.getJSONObject(x)
list.add(
FlightShdu(
jsonObject.getJSONObject("flight").getJSONObject("identification").getJSONObject("number").getString("default"),
jsonObject.getJSONObject("flight").getJSONObject("airline").getString("short"),
jsonObject.getJSONObject("flight").getJSONObject("status").getJSONObject("generic").getJSONObject("status" )
)
)
x++
}
list.forEach(::println)
var adapter = ListAdapteArr(this#MainActivity, list)
flight_arrivel_list.adapter = adapter
}
}
List Aadpter Class
class ListAdapteArr (val context: fragment_Arr, var list: ArrayList<FlightShdu>): BaseAdapter() {
#SuppressLint("ViewHolder", "NewApi")
override fun getView(p0: Int, convertView: View?, parent: ViewGroup?): View {
val view : View = LayoutInflater.from(context,this).inflate(R.layout.arr_list,parent,false)
val list = list[p0]
val code = view.findViewById(R.id.code_id) as AppCompatTextView
view.callsign_id.text=list.Callsign
view.airline_id.text=list.Airline
code.text = list.code
view.setOnClickListener {
val intent = Intent(context, FlightDeatilasArr::class.java)
intent.putExtra("Stauts",list.Stauts!!)
intent.putExtra("Callsign",list.Callsign!!)
intent.putExtra("Airline",list.Airline!!)
context!!.startActivity(intent)
}
}
private fun getDateTime(s: String): String? {
try {
val sdf = SimpleDateFormat("EE, MMM d KK:mm a")
val netDate = Date(s.toLong() * 1000)
return sdf.format(netDate)
} catch (e: Exception) {
return e.toString()
}
}
override fun getItem(p0: Int): Any {
return list [p0]
}
override fun getItemId(p0: Int): Long {
return p0.toLong()
}
override fun getCount(): Int {
return list.size
}
}
According to documentation, there is method with single parameter LayoutInflater.html#from(android.content.Context), but you invoke it with 2 parameters
LayoutInflater.from(context,this).inflate(R.layout.arr_list,parent,false)
And by the way, context that you pass is not actually Context, but a fragment
class ListAdapteArr (val context: fragment_Arr, ...)
To fix your problem use next approach
override fun getView(p0: Int, convertView: View?, parent: ViewGroup?): View? {
val view: View = LayoutInflater.from(parent!!.context).inflate(R.layout.arr_list,parent,false)
...
return view
}
According to documentation, parent should never be null.
The parent that this view will eventually be attached to