我有某种新闻应用程序,我正在加载经过改造的新闻,并将其放入回收者视图。我使用rxjava进行分页,并使用房间将新闻保存到房间数据库中。看起来是这样的: https://imgur.com/a/7TbQn4C
当我点击“保存”图标时,应该像这样更改图标 https://imgur.com/a/nndEfdB
并将该新闻保存到DB。它更改了图标并保存了新闻,但它保存了另一个新闻,而不是它应该保存 https://imgur.com/a/cLRrDvE
当我继续滚动以获取更多新闻时,我发现所有图标都进入了第一个状态,就像第一张图片一样,但是在DB中仍然没有正确的新闻。所以我有两个问题: 1.如何保存图标状态 2.如何保存我需要的新闻
这是我的回收站视图适配器的代码(在这里,我单击图像并保存到数据库)
package com.hfad.cointask.adapter
import android.content.Context
import android.content.Intent
import android.graphics.drawable.TransitionDrawable
import android.util.Log
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.AnimationUtils
import android.widget.ImageView
import android.widget.TextView
import com.hfad.cointask.R
import com.hfad.cointask.helper.AppDatabase
import com.hfad.cointask.helper.CallableNews
import com.hfad.cointask.model.News
import com.hfad.cointask.service.ItemClickListener
import com.squareup.picasso.Picasso
import io.reactivex.Completable
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import java.util.*
import java.util.function.Consumer
@Suppress("DEPRECATION")
class CoinAdapter(var values: List<News>, var context: Context): androidx.recyclerview.widget.RecyclerView.Adapter<CoinAdapter.CoinViewHolder>() {
val intent = Intent(context, NewsViewActivity::class.java)
lateinit var item: News
var db:AppDatabase = AppDatabase.getInstance(context) as AppDatabase
private var compositeDispossable: CompositeDisposable = CompositeDisposable()
object NewsFields {
var title = ""
var id = ""
var newsThumb = ""
var label: String? = ""
}
override fun onBindViewHolder(p0: CoinViewHolder, p1: Int) {
item = values[p1]
NewsFields.title = item.getTitle()
p0.newsTitle.text = NewsFields.title
NewsFields.id = item.getId().toString()
val idItem = NewsFields.id
NewsFields.label = item.getBadge()?.getLabel()
val labelItem = NewsFields.label
NewsFields.newsThumb = item.getThumb()
val thumbItem = NewsFields.newsThumb
if (labelItem == "default") {
p0.newsThumb.setImageDrawable(null)
} else {
p0.newsThumb.visibility = View.VISIBLE
Picasso.get()
.load(thumbItem)
.into(p0.newsThumb)
}
p0.setItemClickListener(object: ItemClickListener {
override fun onClick(v: View, position: Int, isLongClick: Boolean) {
intent.putExtra("id", idItem)
context.startActivity(intent)
}
})
setOnImageClickListener(p0.saveNews)
}
override fun getItemCount(): Int {
return values.size
}
fun saveToDb(data: News, db: AppDatabase) {
Completable.fromAction{ db.newsDao().insert(data) }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({}, {
Log.d("SaveToDb", "Again", it)
})
}
fun deleteFromDb(data: News, db: AppDatabase) {
Completable.fromAction{ db.newsDao().delete(data) }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({}, {
Log.d("SaveToDb", "Again", it)
})
}
private fun setOnImageClickListener(img: ImageView) {
img.setOnClickListener {
if (img.tag == "saved") {
img.setImageResource(R.drawable.save_icon_outline_24)
img.tag = "not saved"
deleteFromDb(item, db)
} else {
img.setImageResource(R.drawable.save_icon_24)
img.tag = "saved"
saveToDb(item, db)
}
}
img.setOnLongClickListener {
img.setImageResource(R.drawable.save_icon_24)
true
}
}
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): CoinViewHolder {
val view: View = LayoutInflater.from(p0.context).inflate(R.layout.news_item_view, p0, false)
return CoinViewHolder(view)
}
class CoinViewHolder(itemView: View): ViewHolder(itemView), View.OnLongClickListener, View.OnClickListener {
private lateinit var itemClickListener:ItemClickListener
lateinit var transition: TransitionDrawable
fun setItemClickListener(itemClickListener: ItemClickListener) {
this.itemClickListener = itemClickListener
}
init {
itemView.setOnLongClickListener(this)
itemView.setOnClickListener(this)
}
override fun onClick(v: View) {
itemClickListener.onClick(v, adapterPosition, false)
v.startAnimation(AnimationUtils.loadAnimation(v.context, R.anim.tap))
}
override fun onLongClick(v: View): Boolean {
//itemClickListener.onClick(v, adapterPosition, true)
//v.startAnimation(AnimationUtils.loadAnimation(v.context, R.anim.tap))
return true
}
var newsTitle: TextView = itemView.findViewById(R.id.item_title)
var newsThumb: ImageView = itemView.findViewById(R.id.thumb_image)
var saveNews: ImageView = itemView.findViewById(R.id.save_icon)
}
}
这是我的供稿代码:
package com.hfad.cointask.fragments
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ProgressBar
import android.widget.Toast
import com.google.gson.GsonBuilder
import com.hfad.cointask.FeedActivity
import com.hfad.cointask.R
import com.hfad.cointask.adapter.CoinAdapter
import com.hfad.cointask.model.News
import com.hfad.cointask.service.CoinClient
import io.reactivex.Flowable
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import io.reactivex.processors.PublishProcessor
import io.reactivex.schedulers.Schedulers
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.scalars.ScalarsConverterFactory
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
/**
* A simple [Fragment] subclass.
*
*/
class FeedFragment : androidx.fragment.app.Fragment() {
private var news = mutableListOf<News>()
private val gson = GsonBuilder().setDateFormat("yyyy-mm-dd HH:mm:ss.SSSSSS").create()
private lateinit var newsRecyclerView: androidx.recyclerview.widget.RecyclerView
private lateinit var newsAdapter: CoinAdapter
private lateinit var layoutManager: androidx.recyclerview.widget.LinearLayoutManager
private val client = FeedFragment.mCoinClient().build()
var offset = 0
var length = 10
private lateinit var compositeDispossable: CompositeDisposable
private lateinit var pagination: PublishProcessor<Int>
private val TAG = "FeedActivity"
private var totalItemCount = 0
private var lastVisibleItem = 0
private var loading = false
private val VISIBLE_TRESHOLD = 1
private lateinit var progressBar: ProgressBar
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
var view = inflater.inflate(R.layout.fragment_feed, container, false)
progressBar = view.findViewById(R.id.progressBar)
newsRecyclerView = view.findViewById(R.id.news_recycler_view)
newsRecyclerView.isNestedScrollingEnabled = false
layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this.requireContext(), androidx.recyclerview.widget.LinearLayoutManager.VERTICAL, false)
newsRecyclerView.layoutManager = layoutManager
newsAdapter = CoinAdapter(news, this.requireContext())
newsRecyclerView.adapter = newsAdapter
compositeDispossable = CompositeDisposable()
pagination = PublishProcessor.create()
news.clear()
headerNews()
setUpLoadMoreListener()
subscribeForData()
return view
}
private fun setUpLoadMoreListener() {
newsRecyclerView.addOnScrollListener(object: androidx.recyclerview.widget.RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: androidx.recyclerview.widget.RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
totalItemCount = newsRecyclerView.layoutManager!!.itemCount
lastVisibleItem = layoutManager.findLastVisibleItemPosition()
if (!loading && totalItemCount <= (lastVisibleItem + VISIBLE_TRESHOLD)) {
offset += length
pagination.onNext(offset)
loading = true
}
}
})
}
private fun subscribeForData() {
var disposable: Disposable = pagination
.onBackpressureDrop()
.concatMap {
loading = true
progressBar.visibility = View.VISIBLE
getNews(offset)
}
.observeOn(AndroidSchedulers.mainThread())
.subscribe ({ t ->
jsonLatest(t)
newsAdapter.notifyDataSetChanged()
loading = false
progressBar.visibility = View.INVISIBLE
}
,{
Log.e(TAG, it.toString())
})
compositeDispossable.add(disposable)
pagination.onNext(offset)
}
private fun headerNews() {
getHeader().enqueue(object: Callback<String> {
override fun onResponse(call: Call<String>, response: Response<String>) {
var headNews = response.body()
if (headNews != null) {
jsonHeader(headNews)
}
newsAdapter.notifyDataSetChanged()
}
override fun onFailure(call: Call<String>?, t: Throwable?) {
val toast = Toast.makeText(FeedActivity(), t.toString(), Toast.LENGTH_SHORT)
toast.show()
}
})
}
private fun getHeader() = client.getHead()
private fun getNews(offset: Int): Flowable<String> {
return client.getNews(offset, length)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
class mCoinClient {
private val builder = Retrofit
.Builder()
.baseUrl("https://api.cointelegraph.com/")
.addConverterFactory(ScalarsConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
private val retrofit: Retrofit by lazy {
builder.build()
}
private val client: CoinClient by lazy {
retrofit.create(CoinClient::class.java)
}
fun build() = client
}
private fun jsonLatest(jsonString: String) {
var latestNews = jsonString.substringAfter("\"type\":\"latest\",\"data\":")
latestNews = latestNews.substringBefore("}]}}")
val listNews = gson.fromJson(latestNews, Array<News>::class.java).asList()
news.addAll(listNews)
}
fun jsonHeader(jsonString: String) {
var headerNews = jsonString.substringAfter("\"type\":\"header\",\"data\":")
headerNews = headerNews.substringBefore("},{\"type\":")
val header: News = gson.fromJson(headerNews, News::class.java)
news.add(header)
}
override fun onDestroy() {
super.onDestroy()
compositeDispossable.dispose()
}
}