how to binding correctly recyclerview items in kotlin? - android

I am developing a news app and I am following MVVM with data binding in recycler view I am trying to bind items but I am just stuck below my recyclerview items xml file
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="article"
type="yodgorbek.komilov.musobaqayangiliklari.model.Article">
</variable>
</data>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp">
<ImageView
android:text="#{article.urlToImage}"
android:id="#+id/imageView"
android:layout_width="100dp"
android:layout_height="85dp"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:contentDescription="bbc"
tools:background="#color/colorPrimary" />
<TextView
android:id="#+id/articleTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_toEndOf="#id/imageView"
android:layout_toRightOf="#id/imageView"
android:ellipsize="end"
android:lines="3"
android:maxLines="3"
android:text="#{article.title}" />
<ImageView
android:id="#+id/imageCategory"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_below="#id/articleTitle"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_toEndOf="#id/imageView"
android:layout_toRightOf="#id/imageView"
android:src="#drawable/ic_espn"
tools:background="#color/colorPrimary" />
<TextView
android:id="#+id/articleSourceName"
android:layout_width="wrap_content"
android:layout_height="32dp"
android:layout_below="#id/articleTitle"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_toEndOf="#id/imageCategory"
android:layout_toRightOf="#id/imageCategory"
android:gravity="center|start"
android:text="#{article.source.name}" />
<TextView
android:id="#+id/articleTime"
android:layout_width="wrap_content"
android:layout_height="32dp"
android:layout_below="#id/articleTitle"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_toEndOf="#id/articleSourceName"
android:layout_toRightOf="#id/articleSourceName"
android:gravity="center|start"
android:text="#{article.publishedAt}"
android:textColor="#android:color/darker_gray"
tools:ignore="NotSibling" />
</RelativeLayout>
</androidx.cardview.widget.CardView>
</layout>
below TopHeadlinesAdapter.kt where I am trying to implement data binding logic
#Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS")
class TopHeadlinesAdapter(val context: Context, private val article: List<Article>) :
RecyclerView.Adapter<TopHeadlinesAdapter.MyViewHolder>() {
private var articleList: List<Article> by Delegates.observable(emptyList()) { _, _, _ ->
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val inflater =
LayoutInflater.from(parent.context)//.inflate(R.layout.news_list, parent, false)
// val binding = Article.inflate(inflater)
return MyViewHolder(article, parent)
}
override fun getItemCount(): Int {
return articleList.size
}
#SuppressLint("NewApi")
override fun onBindViewHolder(holder: MyViewHolder, position: Int) =
holder.bind(articleList[position])
//holder.articleTitle.text = articleList.get(position).title
//holder.articleSourceName.text = articleList.get(position).source.name
//Picasso.get().load(articleList.get(position).urlToImage).into(holder.image)
// val input = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX")
// val output = SimpleDateFormat("dd/MM/yyyy")
// var d = Date()
// try {
// d = input.parse(articleList[5].publishedAt)
// } catch (e: ParseException) {
// try {
// val fallback = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
// fallback.timeZone = TimeZone.getTimeZone("UTC")
// d = fallback.parse(articleList[5].publishedAt)
// } catch (e2: ParseException) {
// // TODO handle error
// val formatted = output.format(d)
// val timelinePoint = LocalDateTime.parse(formatted)
// val now = LocalDateTime.now()
//
// var elapsedTime = Duration.between(timelinePoint, now)
//
// println(timelinePoint)
// println(now)
// elapsedTime.toMinutes()
//
// holder.articleTime.text = "${elapsedTime.toMinutes()}"
//
//
fun updateData(newList: List<Article>) {
articleList = newList
Log.e("articleListSize", articleList?.size.toString())
}
inner class MyViewHolder(private val binding: Article) : RecyclerView.ViewHolder(binding.root) {
fun bind(article: Article) {
binding.article = article
// val image: ImageView = itemView!!.findViewById(R.id.imageView)
// val articleTitle: TextView = itemView!!.findViewById(R.id.articleTitle)
// val articleSourceName: TextView = itemView!!.findViewById(R.id.articleSourceName)
// val imageCategory: ImageView = itemView!!.findViewById(R.id.imageCategory)
// val articleTime: TextView = itemView!!.findViewById(R.id.articleTime)
}
}
}
below my Article.kt data class
data class Article(
val author: String,
val content: String,
val description: String,
val publishedAt: String,
val source: Source,
val title: String,
val url: String,
val urlToImage: String
)
below fragment_top_headlines.xml where I am hosting recyclerview
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="#+id/pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
below TopHeadlinesFragment.kt
class TopHeadlinesFragment : Fragment() {
private val viewModel by viewModel<MainViewModel>()
private lateinit var topHeadlinesAdapter: TopHeadlinesAdapter
// private val newsRepository: NewsRepository by inject()
private lateinit var article:List<Article>
//3
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(
R.layout.fragment_top_headlines
, container, false
)
val recyclerView = view.findViewById(R.id.recyclerView) as RecyclerView
val pb = view.findViewById(R.id.pb) as ProgressBar
topHeadlinesAdapter = TopHeadlinesAdapter(recyclerView.context, article)
recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.adapter = topHeadlinesAdapter
initViewModel()
return view
}
private fun initViewModel() {
viewModel?.sportList?.observe(this, Observer { newList ->
topHeadlinesAdapter.updateData(newList)
})
viewModel?.showLoading?.observe(this, Observer { showLoading ->
pb.visibility = if (showLoading) View.VISIBLE else View.GONE
})
viewModel?.showError?.observe(this, Observer { showError ->
(showError)
})
viewModel?.loadNews()
}
}
I want to know what I have to do in order to bind correctly recyclerview items and show correctly in my app?

try this in
class yourAdapterName(val context: Context, var listData:
MutableList<Article>) :
RecyclerView.Adapter<LanguageAdapter.ViewHolder>() {
lateinit var bindind: YourBinding
fun onRefresh(listData: MutableList<Article>) {
this.listData = listData
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
ViewHolder {
bindind = YourBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(bindind)
}
override fun getItemCount(): Int {
return listData.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.setData(listData[position])
}
inner class ViewHolder(private val binding: LangugaeItemBinding) : RecyclerView.ViewHolder(binding.getRoot()) {
fun setData(model: Article) {
with(binding) {
artical = model
executePendingBindings()
}
}
}
}
and call these into onViewCreated in fragment
val recyclerView = view.findViewById(R.id.recyclerView) as
RecyclerView
val pb = view.findViewById(R.id.pb) as ProgressBar
topHeadlinesAdapter = TopHeadlinesAdapter(recyclerView.context,
article)
recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.adapter = topHeadlinesAdapter
initViewModel()

Related

Communication between ViewPager's host Fragment and ViewPager's Fragment item

I have a Fragment(InsiraDocumentosFragment) that has a viewpager and in that fragment I initialize an adapter(InsiraDocumentoAdapter) to initialize the viewpager.
The adapter(InsiraDocumentoAdapter) initializes generic fragments (DocumentoFragment) that I update dynamically, I can now update the image that is shown inside it, but I need to get the click on that image to either change it or to remove it, but this needs to be done in the Fragment that contains the viewpager, because is in this fragment(InsiraDocumentosFragment) that I have the viewmodel that communicates with the database.
How can I watch from InsiraDocumentosFragment the click on the imageview of DocumentFragment ?
Here are my code samples.
class InsiraDocumentosFragment : Fragment() {
private lateinit var _view: View
private lateinit var _imgBack: ImageView
private lateinit var _viewpager: ViewPager
private lateinit var _imgCamera: ImageView
private lateinit var _footerTitle: TextView
private lateinit var _titles: List<String>
private lateinit var _files: MutableList<File?>
private lateinit var _viewModel: DocumentoViewModel
private lateinit var _viewModelProposta: PropostaViewModel
private lateinit var _viewModelArquivo: ArquivoViewModel
private lateinit var _adapter: InsiraDocumentoAdapter
private lateinit var _proposta: PropostaEntity
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? = inflater.inflate(R.layout.fragment_insira_documento, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_view = view
_imgBack = _view.findViewById(R.id.imgBack)
_viewpager = _view.findViewById(R.id.viewpager)
_imgCamera = _view.findViewById(R.id.cameraDocumento)
_footerTitle = _view.findViewById(R.id.footerTitle)
_files = mutableListOf(null, null, null)
_titles = listOf(getString(R.string.identidade), getString(R.string.comprovante_renda), getString(R.string.foto))
_adapter = InsiraDocumentoAdapter(_titles, _files, childFragmentManager)
_viewpager.adapter = _adapter
_viewModel = ViewModelProvider(
this,
DocumentoViewModel.DocumentoViewModelFactory(DocumentoRepositorio(AppDatabase.getDatabase(_view.context).documentoDao()))
).get(DocumentoViewModel::class.java)
_viewModelProposta = ViewModelProvider(
this,
PropostaViewModel.PropostaViewModelFactory(PropostaRepositorio(AppDatabase.getDatabase(_view.context).propostaDao()))
).get(PropostaViewModel::class.java)
_viewModelArquivo = ViewModelProvider(
this,
ArquivoViewModel.ArquivoViewModelFactory(ArquivoRepositorio(AppDatabase.getDatabase(_view.context).arquivoDao()))
).get(ArquivoViewModel::class.java)
addViewPagerListener()
onClickImgBack()
onClickImgCamera()
onClickFooterTitle()
val propostaStr = arguments?.getString(PROPOSTA)
if (!propostaStr.isNullOrBlank()) {
_proposta = jsonToObjProposta(propostaStr)
}
}
private fun addViewPagerListener() {
_viewpager.addOnPageChangeListener(object : OnPageChangeListener {
override fun onPageScrollStateChanged(state: Int) {}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
override fun onPageSelected(position: Int) {
if (position == _viewpager.adapter!!.count - 1) {
_footerTitle.text = getString(R.string.concluir)
} else {
_footerTitle.text = getString(R.string.proximo)
}
updateViewPagerLayout(position)
}
})
}
private fun updateViewPagerLayout(currentPage: Int) {
when (currentPage) {
0 -> {
habilitaIndicadorPagina(_view.findViewById(R.id.primeiraPagina), _view.findViewById(R.id.imgPrimeiraPagina), R.drawable.primeira_pagina_selecionada)
desabilitaIndicadorPagina(_view.findViewById(R.id.segundaPagina), _view.findViewById(R.id.imgSegundaPagina), R.drawable.segunda_pagina_nao_selecionada)
desabilitaIndicadorPagina(_view.findViewById(R.id.terceiraPagina), _view.findViewById(R.id.imgTerceiraPagina), R.drawable.terceira_pagina_nao_selecionada)
}
1 -> {
desabilitaIndicadorPagina(_view.findViewById(R.id.primeiraPagina), _view.findViewById(R.id.imgPrimeiraPagina), R.drawable.primeira_pagina_nao_selecionada)
habilitaIndicadorPagina(_view.findViewById(R.id.segundaPagina), _view.findViewById(R.id.imgSegundaPagina), R.drawable.segunda_pagina_selecionada)
desabilitaIndicadorPagina(_view.findViewById(R.id.terceiraPagina), _view.findViewById(R.id.imgTerceiraPagina), R.drawable.terceira_pagina_nao_selecionada)
}
2 -> {
desabilitaIndicadorPagina(_view.findViewById(R.id.primeiraPagina), _view.findViewById(R.id.imgPrimeiraPagina), R.drawable.primeira_pagina_nao_selecionada)
desabilitaIndicadorPagina(_view.findViewById(R.id.segundaPagina), _view.findViewById(R.id.imgSegundaPagina), R.drawable.segunda_pagina_nao_selecionada)
habilitaIndicadorPagina(_view.findViewById(R.id.terceiraPagina), _view.findViewById(R.id.imgTerceiraPagina), R.drawable.terceira_pagina_selecionada)
}
}
}
private fun desabilitaIndicadorPagina(layout: ConstraintLayout, image: ImageView, imageDrawable: Int) {
layout.setBackgroundResource(R.drawable.not_selected_indicator)
image.setBackgroundResource(imageDrawable)
}
private fun habilitaIndicadorPagina(layout: ConstraintLayout, image: ImageView, imageDrawable: Int, ) {
layout.setBackgroundResource(R.drawable.indicador_selecionado)
image.setBackgroundResource(imageDrawable)
}
private fun onClickFooterTitle() {
_footerTitle.setOnClickListener {
if (_viewpager.currentItem == _viewpager.adapter!!.count - 1) {
var success = true
for (i in 0..2) {
if (_files[i] == null || _files[i]?.path.isNullOrEmpty()) {
Toast.makeText(_view.context, R.string.favor_preencher_todas_as_fotos, Toast.LENGTH_LONG).show()
_viewpager.currentItem = i
success = false
break
}
}
if (success) {
_viewModelProposta.addProposta(_proposta.numeroProposta, _proposta.valorPropasta, _proposta.clienteId).observe(viewLifecycleOwner, { idProposta ->
_proposta.id = idProposta
_viewModel.addDocumento("Nome do Documento", _proposta.id).observe(viewLifecycleOwner, { idDocumento ->
val arquivos = mutableListOf<ArquivoEntity>()
for (i in 0..2) {
arquivos.add(ArquivoEntity(0, _files[i]!!.path, _titles[i], idDocumento))
}
_viewModelArquivo.addArquivos(arquivos).observe(viewLifecycleOwner, {
_view.findNavController().popBackStack(R.id.clienteFragment, false)
})
})
})
}
} else {
_viewpager.currentItem = _viewpager.currentItem + 1
}
}
}
private fun onClickImgBack() {
_imgBack.setOnClickListener {
_view.findNavController().navigateUp()
}
}
private fun onClickImgCamera() {
_imgCamera.setOnClickListener {
val intent = Intent(_view.context, ScannerActivity::class.java)
startActivityForResult(intent, REQUEST_CODE)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) {
val mediaList = ScannerActivity.getOutputDirectory(_view.context).listFiles()?.toMutableList() ?: mutableListOf()
if (mediaList.size > 0) {
val documentoFile = mediaList[mediaList.size - 1]
_files.removeAt(_viewpager.currentItem)
_files.add(_viewpager.currentItem, documentoFile)
_adapter.notifyDataSetChanged()
}
}
}
private fun jsonToObjProposta(json: String): PropostaEntity {
val gson = Gson()
val arrayTutorialType = object : TypeToken<PropostaEntity>() {}.type
return gson.fromJson(json, arrayTutorialType)
}
override fun onResume() {
super.onResume()
_view = requireView()
}
companion object {
const val REQUEST_CODE = 1
const val IMAGE = "IMAGE"
const val ID_PROPOSTA = "ID_PROPOSTA"
const val PROPOSTA = "PROPOSTA"
}
}
class InsiraDocumentoAdapter(private val titles: List<String>, private var files: List<File?>, manager: FragmentManager): FragmentStatePagerAdapter(manager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
override fun getCount() = 3
override fun getItem(position: Int): Fragment {
return DocumentoFragment.newInstance(titles[position], files[position])
}
override fun getItemPosition(`object`: Any): Int {
return POSITION_NONE
}
}
class DocumentoFragment : Fragment() {
private lateinit var _view: View
private lateinit var _documento: ImageView
private lateinit var _documentoShape: ImageView
private lateinit var _txtTitle: TextView
private var _file: File? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? = inflater.inflate(R.layout.fragment_documento, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_view = view
}
private fun setUpView() {
_documento = _view.findViewById(R.id.documento)
_documentoShape = _view.findViewById(R.id.documentoShape)
_txtTitle = _view.findViewById(R.id.txtTitle)
_txtTitle.text = arguments?.getString(TITLE)
if (!arguments?.getString(FILE).isNullOrEmpty()) {
_file = File(arguments?.getString(FILE))
}
onImgClick()
insereImagem()
}
private fun onImgClick() {
_documento.setOnClickListener {
if (_documentoShape.visibility == View.GONE && _file != null) {
val intent = Intent(_view.context, FullScreenActivity::class.java)
intent.putExtra(InsiraDocumentosFragment.IMAGE, _file?.path)
intent.putExtra(TITLE, _txtTitle.text)
startActivity(intent)
}
}
}
private fun insereImagem() {
if (_file != null) {
Picasso.get().load(_file!!).into(_view.findViewById<ImageView>(R.id.documento))
_view.findViewById<ImageView>(R.id.documentoShape)?.visibility = View.GONE
} else {
_view.findViewById<ImageView>(R.id.documentoShape)?.visibility = View.VISIBLE
}
}
override fun onResume() {
super.onResume()
setUpView()
}
companion object {
fun newInstance(title: String, file: File?): DocumentoFragment {
val fragmentFirst = DocumentoFragment()
val args = bundleOf(
TITLE to title,
FILE to file?.path
)
fragmentFirst.arguments = args
return fragmentFirst
}
const val TITLE = "TITLE"
const val FILE = "FILE"
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".documento.view.DocumentoFragment">
<TextView
android:id="#+id/txtTitle"
android:layout_width="wrap_content"
android:layout_height="#dimen/dimen_24dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:text="Identidade"
android:textColor="#015669"
android:textSize="#dimen/dimen_20sp"
/>
<ImageView
android:id="#+id/documento"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#ffffff"
android:src="#drawable/rectangle_white"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/txtTitle"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:scaleType="fitXY"
android:layout_marginTop="#dimen/dimen_20dp"
android:contentDescription="#string/foto_documento"/>
<ImageView
android:id="#+id/documentoShape"
android:layout_width="88dp"
android:layout_height="101dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:src="#drawable/document_shape"
android:contentDescription="#string/foto_documento"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".documento.view.InsiraDocumentosFragment"
android:background="#f0f0f0">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="#dimen/dimen_56dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="#drawable/rectangle_blue_toolbar">
<ImageView
android:id="#+id/imgBack"
android:layout_width="#dimen/dimen_12dp"
android:layout_height="#dimen/dimen_20dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginStart="#dimen/dimen_20dp"
android:layout_marginTop="18dp"
android:src="#drawable/tint_color"
android:contentDescription="#string/voltar"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:text="#string/insira_os_documentos"
android:textColor="#ffffff"
android:textSize="#dimen/dimen_20sp"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/pagerIndicator"
android:layout_width="wrap_content"
android:layout_height="#dimen/dimen_30dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#id/toolbar"
android:layout_marginTop="#dimen/dimen_20dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/primeiraPagina"
android:layout_width="#dimen/dimen_30dp"
android:layout_height="#dimen/dimen_30dp"
android:background="#drawable/indicador_selecionado"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/segundaPagina"
android:layout_marginHorizontal="#dimen/dimen_10dp"
>
<ImageView
android:id="#+id/imgPrimeiraPagina"
android:layout_width="#dimen/dimen_9dp"
android:layout_height="#dimen/dimen_18dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:background="#drawable/primeira_pagina_selecionada"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/segundaPagina"
android:layout_width="#dimen/dimen_30dp"
android:layout_height="#dimen/dimen_30dp"
android:background="#drawable/not_selected_indicator"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="#id/primeiraPagina"
android:layout_marginHorizontal="#dimen/dimen_10dp"
>
<ImageView
android:id="#+id/imgSegundaPagina"
android:layout_width="#dimen/dimen_9dp"
android:layout_height="#dimen/dimen_18dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:background="#drawable/segunda_pagina_nao_selecionada"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/terceiraPagina"
android:layout_width="#dimen/dimen_30dp"
android:layout_height="#dimen/dimen_30dp"
android:background="#drawable/not_selected_indicator"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="#id/segundaPagina"
android:layout_marginHorizontal="#dimen/dimen_10dp"
>
<ImageView
android:id="#+id/imgTerceiraPagina"
android:layout_width="#dimen/dimen_9dp"
android:layout_height="#dimen/dimen_18dp"
android:layout_gravity="center"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:background="#drawable/terceira_pagina"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.viewpager.widget.ViewPager
android:id="#+id/viewpager"
android:layout_width="#dimen/dimen_280dp"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/pagerIndicator"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="#id/footer"
android:layout_marginHorizontal="#dimen/dimen_40dp"
android:layout_marginTop="#dimen/dimen_20dp"
android:layout_marginBottom="#dimen/dimen_20dp"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/footer"
android:layout_width="match_parent"
android:layout_height="#dimen/dimen_69dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:background="#drawable/footer">
<ImageView
android:id="#+id/imgDocumento"
android:layout_width="#dimen/dimen_26dp"
android:layout_height="#dimen/dimen_30dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginStart="#dimen/dimen_20dp"
android:layout_marginVertical="#dimen/dimen_20dp"
android:src="#drawable/combined_shape"
android:backgroundTint="#0179b0"
android:contentDescription="#string/formato_documento"
/>
<TextView
android:id="#+id/footerTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="#id/imgDocumento"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="#+id/cameraDocumento"
app:layout_constraintBottom_toBottomOf="parent"
android:textSize="#dimen/dimen_20sp"
android:textColor="#0179b0"
android:gravity="center"
android:text="#string/proximo"/>
<ImageView
android:id="#+id/cameraDocumento"
android:layout_width="#dimen/dimen_33dp"
android:layout_height="#dimen/dimen_30dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginEnd="#dimen/dimen_20dp"
android:layout_marginVertical="#dimen/dimen_20dp"
android:src="#drawable/camera_shape"
android:backgroundTint="#0179b0"
android:contentDescription="#string/capturar_foto"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
I need to get the click on that image to either change it or to remove it, but this needs to be done in the Fragment that contains the viewpager, because is in this fragment(InsiraDocumentosFragment) that I have the viewmodel that communicates with the database.
You have a couple of options to do that:
First one:
Make the ViewModel shared between both fragments (InsiraDocumentosFragment & DocumentoFragment) by instantiating it in both fragments with the activity as the owner using requireActivity() that hosts both fragments:
val viewModel =
ViewModelProvider(requireActivity()).get(MyViewModel::class.java)
And then no need to access the parent fragment for changing the image; because now you've an instance of the ViewModel in the DocumentoFragment.
Second one:
Access the InsiraDocumentosFragment from the DocumentoFragment using requireParentFragment(), but first create a method in parent that you want to call from the page fragment to do your needed job.
Assuming the method that you created in InsiraDocumentosFragment is someMethodInParent()
In DocumentoFragment:
val parentFragment = requireParentFragment() as InsiraDocumentosFragment
parentFragment.someMethodInParent()

How to display JSON data from Horizontal recycle view kotlin using MVP method

I hope is all well with you.
I have constructed my code and build according the MVP style as well pulling JSON data but when I run the the code the horizontal recycle view and the JSON data is not being displayed. I tried going through every line of code and watching other tutorials but still no results.
Here is below my main activity:
class ProductCategoryActivity : BaseMvpActivity<ProductCategoryActivityView, ProductCategoryActivityPresnter> (),
ProductCategoryActivityView, CategoryAdapter.onItemClickListener{
private lateinit var binding: FragmentProductCategoryBinding
val data :MutableList<CateogryResponse> = ArrayList()
val adapter= CategoryAdapter(data, this)
#Inject
lateinit var presenter: ProductCategoryActivityPresnter
#Inject
lateinit var progressDialog: ProgressDialog
override fun onCreateComponent() {
userComponent.plus(CategoryActivityModule(this)).inject(this)
}
override fun providePresenter(): ProductCategoryActivityPresnter {
return presenter
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = FragmentProductCategoryBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
presenter.fetchcatogries()
showdata(ArrayList())
}
override fun showError(message: String) {
}
override fun showProgress() {
}
override fun hideProgress() {
}
override fun showdata(data: ArrayList<CateogryResponse>) {
val layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
recyclerViewPrimary.layoutManager = layoutManager
recyclerViewPrimary.setHasFixedSize(true)
recyclerViewPrimary.adapter = adapter
for(i in data)
data.add(CateogryResponse("product"))
}
override fun onItemClick(position: Int) {
Toast.makeText(this, "Item $position clicked", Toast.LENGTH_SHORT).show()
val clickedItem = data[position]
adapter.notifyItemChanged(position)
}
}
Here is my presenter:
#ActivityScope
class ProductCategoryActivityPresnter #Inject constructor(
private val stringProvider: StringProvider,
#AndroidScheduler private val observeOnScheduler: Scheduler,
#IOScheduler private val subscribeOnScheduler: Scheduler,
private val getCategoryUseCase: CategoryUseCase
) : BasePresenter<ProductCategoryActivityView>() {
lateinit var catogriesservice: CategoryRepositoryImpl
val catogriesLoadError = MutableLiveData<Boolean>()
val loading = MutableLiveData<Boolean>()
var catogries: ArrayList<CateogryResponse> = arrayListOf()
override fun onCreatePresenter(savedInstanceState: Bundle?) {
}
override fun onSaveInstanceState(outState: Bundle?) {
}
override fun onLoadData(arguments: Bundle?) {
fetchcatogries()
}
fun fetchcatogries() {
getCategoryUseCase.execute()
.observeOn(observeOnScheduler)
.subscribeOn(subscribeOnScheduler)
.subscribe(
SingleRequestSubscriber(
{
it
if (it != null && it.size > 0) {
catogries.removeAll(catogries)
catogries.addAll(it)
}
},
onFailure = { appException ->
view?.showError(
ErrorHandler.getErrorMessage(
appException,
stringProvider
)
)
},
onApiError = { apiException ->
view?.showError(
ErrorHandler.getErrorMessage(
apiException,
stringProvider
)
)
},
onAuthenticationError = { requestxception ->
view?.showError(
ErrorHandler.getErrorMessage(
requestxception,
stringProvider
)
)
},
onShowProgress = {
if (it) {
view?.showProgress()
} else {
view?.hideProgress()
}
},
onSubscribed = {
disposable.add(it)
})
)
}
}
Here is my view:
interface ProductCategoryActivityView {
fun showError(message: String)
fun showProgress()
fun hideProgress()
fun showdata ( data: ArrayList<CateogryResponse>)
}
Here is my adapter:
class CategoryAdapter(
private val data: List<CateogryResponse>,
private val listener: onItemClickListener
) : RecyclerView.Adapter<CategoryAdapter.ViewHolder>() {
private val items: MutableList<CardView>
init {
this.items = ArrayList()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context)
.inflate(R.layout.fragment_category_adapter, parent, false)
return ViewHolder(v)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.tvTitle.text = data[position].product
items.add(holder.card)
}
override fun getItemCount(): Int {
return data.size
}
inner class ViewHolder(itemView: View
) : RecyclerView.ViewHolder(itemView),
View.OnClickListener {
val tvTitle: TextView = itemView.featured_title
val card: CardView = itemView.CardView
init {
itemView.setOnClickListener(this)
}
override fun onClick(v: View?) {
val position: Int = adapterPosition
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(position)
}
}
}
interface onItemClickListener {
fun onItemClick(position: Int)
}
}
Image:
Fragment Category Adapter:
android:id="#+id/CardView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
app:cardCornerRadius="2dp"
app:cardElevation="8dp">
<!-- We Will Add here the card & ImageViews -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="15dp">
<ImageView
android:id="#+id/featured_image"
android:layout_width="match_parent"
android:layout_height="140dp"
android:scaleType="centerCrop" />
<TextView
android:id="#+id/featured_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lineHeight="23dp"
android:text="Chairs"
android:textColor="#color/colorAccent"
android:textSize="20sp" />
<TextView
android:id="#+id/featured_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="asbkd asudhlasn saudnas jasdjasl hisajdl asjdlnas" />
</LinearLayout>
</androidx.cardview.widget.CardView>
Fragment Product Category:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fafcfe"
tools:context="ui.category.ProductCategoryActivity">
<ImageView
android:id="#+id/imageView3"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/constraintLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="48dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="#+id/imageView"
app:layout_constraintTop_toTopOf="parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerViewPrimary"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="48dp"
android:layout_marginTop="20dp"
android:text="#string/topselling"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/constraintLayout" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/constraintLayout2"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="32dp"
android:layout_marginLeft="32dp"
android:layout_marginTop="16dp"
app:layout_constraintBottom_toTopOf="#+id/imageView3"
app:layout_constraintEnd_toEndOf="#+id/constraintLayout"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerViewSecondary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<ImageView
android:id="#+id/imageView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
app:layout_constraintBottom_toBottomOf="#+id/imageView3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
/>
<TextView
android:id="#+id/textViewCategories"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="48dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="15dp"
android:text="#string/catogries"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="#+id/constraintLayout"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteX="39dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
Not sure what went wrong.
If someone can point it out or show me what needs to be done to be able to display the data in horzintal recycle view, I would be really thanlful
You should update your recycler view adapter once your fetch call is executed, not before it ends.
Modify your fetchcatogries declaration so it accepts a callback method, which will be executed after the data are loaded.
This method will accept a list object as a parameter, which you will manage in your ProductCategoryActivity to populate the RecyclerView.
fun fetchcatogries(callback: (MutableList<CateogryResponse>) -> Unit) {
getCategoryUseCase.execute()
.observeOn(observeOnScheduler)
.subscribeOn(subscribeOnScheduler)
.subscribe(
SingleRequestSubscriber(
{ categories ->
callback(categories)
},
...
)
}
You can now edit your onCreate and showdata methods in ProductCategoryActivity like this:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = FragmentProductCategoryBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
presenter.fetchcatogries { categories ->
showdata(categories as ArrayList<CateogryResponse>)
}
}
override fun showdata(data: ArrayList<CateogryResponse>) {
val layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
recyclerViewPrimary.layoutManager = layoutManager
recyclerViewPrimary.setHasFixedSize(true)
recyclerViewPrimary.adapter = CategoryAdapter(data.toList(), this)
}

Recycler view is not populated with data

I have a recycler view and I am passing data to the recyclerviewadapter but recycler view does not show any data.
ProdyctsRecyclerViewAdapter - it is getting the data in setList but does not display it
Where am I doing it wrong please
Thanks
R
class ProductsRecyclerViewAdapter(private val clickListener: (Product) -> Unit): RecyclerView.Adapter<ProductsMyViewHolder>() {
private val productsList = ArrayList<Product>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductsMyViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding: ListItemBinding =
DataBindingUtil.inflate(layoutInflater, R.layout.products_list_item, parent, false)
return ProductsMyViewHolder(binding)
}
override fun getItemCount(): Int {
return productsList.size
}
override fun onBindViewHolder(holder: ProductsMyViewHolder, position: Int) {
holder.bind(productsList[position], clickListener)
}
fun setList(products: List<Product>) {
productsList.clear()
productsList.addAll(products)
}
}
class ProductsMyViewHolder(val binding: ListItemBinding): RecyclerView.ViewHolder(binding.root) {
fun bind(product: Product, clickListener: (Product) -> Unit) {
binding.nameTextView.text = product.name
binding.emailTextView.text = product.catagory
binding.listItemLayout.setOnClickListener {
clickListener(product)
}
}
}
ProductsFragment
class ProductsFragment: Fragment() {
private lateinit var binding: ProductsBinding
private lateinit var navController: NavController
private lateinit var productsViewModel: ProductsViewModel
private lateinit var adapter: ProductsRecyclerViewAdapter
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.products, container, false)
val dao = SubscriberDatabase.getInstance(requireActivity().applicationContext).productDAO
val repository = ProductRepository(dao)
val factory = ProductsViewModelFactory(repository, requireActivity().applicationContext)
productsViewModel = ViewModelProvider(this, factory).get(ProductsViewModel::class.java)
binding.productsViewModel = productsViewModel
binding.lifecycleOwner = this
val view = binding.root
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
navController = Navigation.findNavController(view)
initRecyclerView()
productsViewModel.navigateScreen.observe(viewLifecycleOwner, EventObserver {
navController.navigate(it)
})
}
private fun initRecyclerView() {
binding.productsRecyclerView.layoutManager = LinearLayoutManager(context)
adapter = ProductsRecyclerViewAdapter ({ selectedItem: Product -> listItemClicked(selectedItem)})
displayProductssList()
}
private fun displayProductssList() {
productsViewModel.products.observe(viewLifecycleOwner, Observer {
Log.i("MYTAG", it.toString())
adapter.setList(it)
adapter.notifyDataSetChanged()
})
}
private fun listItemClicked(product: Product) {
Toast.makeText(context, "Selected name is ${product.name}", Toast.LENGTH_LONG).show()
//productsViewModel.initUpdateAndDelete(subscriber)
}
}
ProductsViewModel
class ProductsViewModel (
private val repository: ProductRepository,
private val context: Context
): ViewModel() {
val products = repository.products
}
Products_list_item
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:orientation="vertical">
<androidx.cardview.widget.CardView
android:id="#+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:clickable="true"
android:focusable="true"
app:cardBackgroundColor="#color/colorPrimary"
app:cardCornerRadius="10dp"
app:cardElevation="10dp" >
<LinearLayout
android:id="#+id/product_list_item_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/product_name_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="name"
android:textColor="#FFFFFF"
android:textSize="30sp"
android:textStyle="bold" />
<TextView
android:id="#+id/product_catagory_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="catagory"
android:textColor="#FFFFFF"
android:textSize="24sp"
android:textStyle="bold" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
</layout>
Thank you Parag Pawar for the answer
For reference made the followingn changes
private fun initRecyclerView() {
binding.productsRecyclerView.layoutManager = LinearLayoutManager(context)
adapter = ProductsRecyclerViewAdapter ({ selectedItem: Product -> listItemClicked(selectedItem)})
binding.productsRecyclerView.adapter = adapter //ADDED THIS LINE
displayProductssList()
}
In productsRecyclerView, had the wrong binding it should be ProductsListItemBinding
val binding: ProductsListItemBinding =
DataBindingUtil.inflate(layoutInflater, R.layout.products_list_item, parent, false)
ProductsMyViewHolder(val binding: ProductsListItemBinding):
You've not set the adapter to recycler view. In your initRecyclerView() set the adapter after initializing it.
private fun initRecyclerView() {
binding.productsRecyclerView.layoutManager = LinearLayoutManager(context)
adapter = ProductsRecyclerViewAdapter ({ selectedItem: Product -> listItemClicked(selectedItem)})
//notice this
binding.productsRecyclerView.adapter = adapter
displayProductssList()
}
add notifyDataSetChanged() method in your Adapter's setList() method
I don't understand why are you clearing your list and adding them at the same time.
fun setList(products: List<Product>) {
productsList.clear()
productsList.addAll(products)
}
if you want to first clear your list you should do it outside the loop

Data binding in recylerview adapter android?

I want to bind data to my recylerview adapter. This is my current code following the MVVM pattern
Fragment
class NotificationFragment : Fragment() {
var customeProgressDialog: CustomeProgressDialog? = null
private val appPreferences: AppPreference by inject()
private val notificationViewModel: NotificationViewModel by viewModel()
private lateinit var binding: FragmentNotificationBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentNotificationBinding.inflate(inflater, container, false)
return binding.getRoot()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.notification.layoutManager=LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
customeProgressDialog = CustomeProgressDialog(activity)
notificationViewModel.notifications(
appPreferences.getUsername(),
appPreferences.getPassword(),
appPreferences.getUserId()
)
initObservables()
}
private fun initObservables() {
notificationViewModel.progressDialog?.observe(this, Observer {
if (it!!) customeProgressDialog?.show() else customeProgressDialog?.dismiss()
})
notificationViewModel.apiResponse?.observe(
viewLifecycleOwner,
androidx.lifecycle.Observer { response ->
if (response.dataList != null) {
val notificationAdapter = NotificationAdapter(response.dataList as List<Data>)
notificationAdapter.notifyDataSetChanged()
binding.notification.adapter = notificationAdapter
}
})
}
}
View model
class NotificationViewModel(networkCall: NetworkCall) : ViewModel(),
Callback<ApiResponse> {
var progressDialog: SingleLiveEvent<Boolean>? = null
var apiResponse: MutableLiveData<ApiResponse>? = null
var networkCall: NetworkCall;
init {
progressDialog = SingleLiveEvent<Boolean>()
apiResponse = MutableLiveData<ApiResponse>()
this.networkCall = networkCall
}
fun notifications(username: String?, password: String?, userId: String?) {
progressDialog?.value = true
val apiPost = ApiPost()
apiPost.userName = username
apiPost.password = password
apiPost.UserId = userId
apiPost.FileType = NetworkConstant.FILE_TYPE_NOT
networkCall.getPDF(apiPost).enqueue(this)
}
override fun onFailure(call: Call<ApiResponse>, t: Throwable) {
progressDialog?.value = false
}
override fun onResponse(call: Call<ApiResponse>, response: Response<ApiResponse>) {
progressDialog?.value = false
apiResponse?.value = response.body()
}
}
The adapter
class NotificationAdapter(private val list: List<Data>) :
RecyclerView.Adapter<NotificationAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = ElementListBinding.inflate(inflater)
// val view = inflater.inflate(R.layout.element_list, parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val movie: Data = list[position]
holder.bind(movie)
holder.itemView.setOnClickListener {
if (!TextUtils.isEmpty(movie.filePath)) {
try {
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(movie.filePath))
holder.itemView.context.startActivity(browserIntent)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
override fun getItemCount(): Int = list.size
inner class ViewHolder(binding: ElementListBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(movie: Data) {
binding.item = movie
}
}
}
unable to find binding object
the recylerview element list xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="data"
type="com.mountmeru.model.Data" />
</data>
<androidx.cardview.widget.CardView
android:id="#+id/main_cardview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="#+id/main_cardrl"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<RelativeLayout
android:id="#+id/rl_newsdate"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.3">
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tv_notifi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:maxLines="2"
android:text="#{data.displayName}"
android:textColor="#android:color/black"
android:textSize="16sp" />
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tv_brief"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/tv_notifi"
android:layout_marginLeft="10dp"
android:layout_marginTop="5dp"
android:layout_marginRight="10dp"
android:textColor="#android:color/black"
android:textSize="16sp"
android:visibility="gone" />
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tv_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/tv_brief"
android:layout_marginLeft="10dp"
android:layout_marginTop="2dp"
android:layout_marginRight="10dp"
android:maxLines="1"
android:text="hey i am date"
android:textColor="#color/inactive_text"
android:textSize="14sp" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toRightOf="#+id/rl_newsdate"
android:layout_weight="0.7"
android:padding="5dp">
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/iv_notifi"
android:layout_width="match_parent"
android:layout_height="75dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="#drawable/mer" />
</RelativeLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.cardview.widget.CardView>
</layout>
Can someone confirm me is my implementation of MVVM correct or it needs some refactoring?
How do I make of data binding in my recyclerview list element xml?
You have already used <layout> as parent tag in element_list.xml. Now you can inflate it in the adapter class using DataBinding. See the example below:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ElementListBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(Binding)
}
You have to modify your ViewHolder class as well as shown below:
inner class ViewHolder(val binding: ElementListBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(movie: Data) {
with(itemView) {
binding.tvNotifi.text = movie.displayName
binding.tvDate.text = movie.UpdatedDate
if (movie.description != null) {
binding.tvBrief.text = movie.description
binding.tvBrief.visibility = View.VISIBLE
}
}
}
}

Bind viewmodel to recyclerview item.xml with databinding, android?

I want to bind data on adapter from viewmodel in xml layout file
This is my fragment class.
class NotificationFragment : Fragment() {
var customeProgressDialog: CustomeProgressDialog? = null
private val appPreferences: AppPreference by inject()
private val notificationViewModel: NotificationViewModel by viewModel()
private lateinit var binding: FragmentNotificationBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentNotificationBinding.inflate(inflater, container, false)
return binding.getRoot()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.notification.layoutManager=LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
customeProgressDialog = CustomeProgressDialog(activity)
notificationViewModel.notifications(
appPreferences.getUsername(),
appPreferences.getPassword(),
appPreferences.getUserId()
)
initObservables()
}
private fun initObservables() {
notificationViewModel.progressDialog?.observe(this, Observer {
if (it!!) customeProgressDialog?.show() else customeProgressDialog?.dismiss()
})
notificationViewModel.apiResponse?.observe(
viewLifecycleOwner,
androidx.lifecycle.Observer { response ->
if (response.dataList != null) {
var notificationAdapter = NotificationAdapter(response.dataList as List<Data>)
notificationAdapter.notifyDataSetChanged()
binding.notification.adapter = notificationAdapter
}
})
}
}
My viewmodel
class NotificationViewModel(networkCall: NetworkCall) : ViewModel(),
Callback<ApiResponse> {
var progressDialog: SingleLiveEvent<Boolean>? = null
var apiResponse: MutableLiveData<ApiResponse>? = null
var networkCall: NetworkCall;
init {
progressDialog = SingleLiveEvent<Boolean>()
apiResponse = MutableLiveData<ApiResponse>()
this.networkCall = networkCall
}
fun notifications(username: String?, password: String?, userId: String?) {
progressDialog?.value = true
val apiPost = ApiPost()
apiPost.userName = username
apiPost.password = password
apiPost.UserId = userId
apiPost.FileType = NetworkConstant.FILE_TYPE_NOT
networkCall.getPDF(apiPost).enqueue(this)
}
override fun onFailure(call: Call<ApiResponse>, t: Throwable) {
progressDialog?.value = false
}
override fun onResponse(call: Call<ApiResponse>, response: Response<ApiResponse>) {
progressDialog?.value = false
apiResponse?.value = response.body()
}
}
The adapter class
lass NotificationAdapter(private val list: List<Data>) :
RecyclerView.Adapter<NotificationAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.element_list, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val movie: Data = list[position]
holder.bind(movie)
holder.itemView.setOnClickListener {
if (!TextUtils.isEmpty(movie.filePath)) {
try {
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(movie.filePath))
holder.itemView.context.startActivity(browserIntent)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
override fun getItemCount(): Int = list.size
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(movie: Data) {
with(itemView) {
tv_notifi.text = movie.displayName
tv_date.text = movie.UpdatedDate
if (movie.description != null) {
tv_brief.text = movie.description
tv_brief.visibility = View.VISIBLE
}
}
}
}
}
This is my item xml layout
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewmodel"
type="com.mountmeru.viewmodel.NotificationViewModel" />
</data>
<androidx.cardview.widget.CardView
android:id="#+id/main_cardview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="#+id/main_cardrl"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<RelativeLayout
android:id="#+id/rl_newsdate"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.3">
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tv_notifi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:maxLines="2"
android:text="hey i am notification text"
android:textColor="#android:color/black"
android:textSize="16sp" />
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tv_brief"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/tv_notifi"
android:layout_marginLeft="10dp"
android:layout_marginTop="5dp"
android:layout_marginRight="10dp"
android:textColor="#android:color/black"
android:textSize="16sp"
android:visibility="gone" />
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tv_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/tv_brief"
android:layout_marginLeft="10dp"
android:layout_marginTop="2dp"
android:layout_marginRight="10dp"
android:maxLines="1"
android:text="hey i am date"
android:textColor="#color/inactive_text"
android:textSize="14sp" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toRightOf="#+id/rl_newsdate"
android:layout_weight="0.7"
android:padding="5dp">
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/iv_notifi"
android:layout_width="match_parent"
android:layout_height="75dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="#drawable/mer" />
</RelativeLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.cardview.widget.CardView>
</layout>
I was able to do the binding for the fragment but for adapter I am unsure how to proceed.
If I understand your question correctly, you want to pass data to your adapter inside xml. For this, you will need to write custom binding adapter for your RecyclerView.
This link has all you need.
https://android.jlelse.eu/how-to-bind-a-list-of-items-to-a-recyclerview-with-android-data-binding-1bd08b4796b4

Categories

Resources