I am using Jsoup and GoogleNews to show some news in a Recycler view. I have used this tutorial and I've able to to show the results in the RecyclerView but depending of the quantity of news related to the search it takes several seconds to show all the results. What I would like to do is show each element in the RecyclerView when they are ready, one by one and in a way that they accumulate and so on instead to wait until have all the elemens ready.
In the tutorial I see that the autor used AsynTask, honestly Im really new on Android(mobile development) and I don't understand how it works, so for that I decided to use my own implementation.
At the end of the mentioned tutorial theres a video that shows that I want like to replicate.
I think that the main problem resides on the recyclerview, so for that reason I'll show below my modified code . Some notes, I'm implementing this on a fragment and I used FramentBinding:
This is the framgment class:
class NewxFragment : Fragment() {
private lateinit var binding: NewxFragmentBinding
private val viewModel by lazy { ViewModelProvider(this).get(EventViewModel::class.java) }
private lateinit var adapter: EventAdapter
override fun onCreateView(
inflater: LayoutInflater,
containter: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = NewxFragmentBinding.inflate(inflater, containter, false)
binding.progressBar.visibility = View.VISIBLE
binding.rvNewx.layoutManager = LinearLayoutManager(requireActivity())
adapter = EventAdapter(requireActivity())
binding.rvNewx.adapter = adapter
viewModel.fetchData().observe(viewLifecycleOwner, Observer {
adapter.setListData(it)
binding.progressBar.visibility = View.GONE
})
return binding.root
}
}
The ViewModel:
class EventViewModel:ViewModel() {
var items: MutableLiveData<MutableList<EventItem>> = MutableLiveData()
fun init(context: Context){
if(items.value != null)
return
}
private val repo = Repo()
fun fetchData():MutableLiveData<MutableList<EventItem>>{
viewModelScope.launch(IO) {
items.postValue(repo.getNewxList())
}
return items
}
}
The Repo where I have the Jsoup logic:
class Repo {
companion object {
var instace: Repo? = null
lateinit var mContext: Context
}
fun getInstace(context: Context): Repo {
mContext = context
if (instace == null)
instace = Repo()
return instace!!
}
fun getNewxList(): MutableList<EventItem> {
val listData = mutableListOf<EventItem>()
try {
val url = "https://news.google.com/rss/search?q=uniswap&hl=en-US&gl=US&ceid=US:en"
val doc = Jsoup.connect(url).get()
val events = doc.select("item")
val eventsSize = events.size
for (i in 0 until eventsSize) {
val title = events.select("title")
.eq(i)
.text()
val link = events.select("link")
.eq(i)
.text()
val pubDate = events.select("pubDate")
.eq(i)
.text()
val description = events.select("description")
.eq(i)
.html()
val innerDesc = Html.fromHtml(description)
var deeperDoc = Jsoup.connect(link).get()
var deeperDesc: Elements? =
deeperDoc?.select("meta[name="description"],meta[property="og:description"],meta[property="sailthru.description"]")
var fullDesc = deeperDesc?.attr("content")
val descList = Jsoup.parse(innerDesc.toString()).select("a")
var srcList = Jsoup.parse(innerDesc.toString()).select("font")
var src = srcList.html()
listData.add(
EventItem(
i,
title,
link,
pubDate,
description,
innerDesc.toString(),
fullDesc.toString(),//listData2.elementAt(i),
src.toString()
)
)
d("info: ", listData[i].toString())
}
} catch (e: IOException) {
e.printStackTrace()
}
return listData
}
}
The EventAdapter:
class EventAdapter (private val context: Context):RecyclerView.Adapter<EventAdapter.ViewHolder>(){
private var items= mutableListOf<EventItem>()
fun setListData(data:MutableList<EventItem>){
items = data
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EventAdapter.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = EventItemBinding.inflate(inflater,parent,false)
return ViewHolder(binding)
}
override fun getItemCount(): Int {
return items.size
}
override fun onBindViewHolder(holder: EventAdapter.ViewHolder, position: Int) = holder.bind(items[position])
inner class ViewHolder(val binding: EventItemBinding):RecyclerView.ViewHolder(binding.root) {
fun bind(item:EventItem)=with(itemView){
binding.setVariable(BR.item,item)
binding.executePendingBindings()
itemView.setOnClickListener{
//navigate to other fragment with Safe Args
val action = NewxFragmentDirections.actionNewxFragmentToEventDetailFragment(item)
findNavController().navigate(action)
}
}
}
}