RecyclerView not updating View - android

I have a recycler view. For the first time, it loads all the data and the view is shown perfect. But when the data is added dynamically, pull to refresh, I add it to the list of data and call notifyDataSetChanged. It increases the count of the list and the list is updated with the latest data but the view is not updating with the latest data added to the list. onBindViewHolder has the updated listView size and the listView has all the valid data within it.
override fun onBindViewHolder(holder: HistoryListAdapter.ViewHolder?, position: Int) {
info("onBindViewHolder =>"+listAssets.size)
info("onBindViewHolder itemCount =>"+itemCount)
info("onBindViewHolder position =>"+position)
val notesButton = holder?.notesButton
val notesView = holder?.notesTextView
val dateTime = listAssets[position].date
val location = listAssets[position].location
val sessionId = listAssets[position].id
holder?.sessionID = sessionId
holder?.portraitImageView?.setImageDrawable(listAssets[position].image)
holder?.titleTextView?.text = DateTimeFormatter.getFormattedDate(context, dateTime)
val timeString = DateTimeFormatter.getFormattedTime(context, dateTime)
if (location.length != 0) {
holder?.subtitleTextView?.text = "$timeString # $location"
} else {
holder?.subtitleTextView?.text = "$timeString"
}
val data = listAssets[position].data
for (actionData in data) {
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val parent = inflater.inflate(R.layout.history_card_action, null)
val icon = parent?.findViewById(R.id.historyActionIcon) as ImageView
val title = parent?.findViewById(R.id.historyActionTitle) as TextView
val subtitle = parent?.findViewById(R.id.historyActionSubtitle) as TextView
var iconDrawable: Drawable? = null
when(actionData.type) {
ActionType.HEART -> {
iconDrawable = ContextCompat.getDrawable(context, R.drawable.heart)
}
ActionType.LUNGS -> {
iconDrawable = ContextCompat.getDrawable(context, R.drawable.lungs)
}
ActionType.TEMPERATURE -> {
iconDrawable = ContextCompat.getDrawable(context, R.drawable.temperature)
}
}
icon.setImageDrawable(iconDrawable)
val titleString = actionData.title
titleString?.let {
title.text = titleString
}
val subtitleString = actionData.subtitle
subtitleString?.let {
subtitle.text = subtitleString
}
holder?.actionContainer?.addView(parent)
}
val notes = listAssets[position].notes
notesView?.text = notes
if (notes.length == 0) {
notesButton?.layoutParams?.width = 0
} else {
notesButton?.layoutParams?.width = toggleButtonWidth
}
if (expandedNotes.contains(sessionId)) {
notesView?.expandWithoutAnimation()
} else {
notesView?.collapseWithoutAnimation()
}
notesButton?.onClick {
notesView?.toggleExpansion()
}
}
data class ListAssets(val id: String,
val date: Date,
val location: String,
val notes: String,
val image: Drawable,
val data: ArrayList<ListData>)
data class ListData(val type: ActionType,
val title: String?,
val subtitle: String?)
override fun onViewRecycled(holder: HistoryListAdapter.ViewHolder?) {
super.onViewRecycled(holder)
if (holder != null) {
holder.actionContainer.removeAllViews()
val notesTextView = holder.notesTextView
if (notesTextView != null) {
if (notesTextView.expandedState) {
val sessionID = holder.sessionID
sessionID?.let {
val sessionSearch = expandedNotes.firstOrNull {
it.contentEquals(sessionID)
}
if (sessionSearch == null) {
expandedNotes.add(sessionID)
}
}
} else {
val sessionID = holder.sessionID
sessionID?.let {
val sessionSearch = expandedNotes.firstOrNull {
it.contentEquals(sessionID)
}
if (sessionSearch != null) {
expandedNotes.remove(sessionSearch)
}
}
}
}
}
}
ActionView is Enum.
Kindly please let me know if I am doing anything wrong.

Related

issue with firebase and kotlin

For a long time I can not solve two problems, for some reason the elements in my RecyclerView are not displayed immediately but after interacting with something, for example when you click on the message field, the second problem is that when you send an image, it is once written to the database, but 3 times is displayed on screen, but if you go to the chat it is displayed once, with text messages no such problem
private fun listenMessage() {
database
.collection(KEY_COLLECTION_USERS)
.document(preferenceManager.getString(KEY_USER_ID)!!)
.collection(KEY_COLLECTION_CHAT)
.addSnapshotListener { value, error ->
if (error != null) {
return#addSnapshotListener
} else {
if (value == null) {
return#addSnapshotListener
} else {
for (documentChange in value.documentChanges) {
if (documentChange.type == DocumentChange.Type.ADDED) {
var doc = documentChange.document
if (doc.getString(KEY_MESSAGE_RECEIVER_ID) == receiverUser.uid) {
var text = doc.getString(KEY_MESSAGE).toString()
var id = doc.getString(KEY_MESSAGE_ID).toString()
var receiverId = doc.getString(KEY_MESSAGE_RECEIVER_ID).toString()
var date = doc.getDate(KEY_MESSAGE_DATE)!!
var isChecked = doc.getBoolean(KEY_MESSAGE_ISCHECKED)!!
var type = doc.getString(KEY_TYPE_MESSAGE).toString()
var message = Message(text, id, receiverId, date, isChecked, type)
messages.add(message)
}
}
}
val chatComparator =
Comparator { obj1: Message, obj2: Message -> obj1.date.compareTo(obj2.date) }
Collections.sort(messages, chatComparator)
var messages_test = ArrayList(messages)
userChatAdpater.updateList(messages_test)
if (messages.size != 0) {
mBinding.rvUserChat.smoothScrollToPosition(messages.size - 1)
}
}
}
}
database
.collection(KEY_COLLECTION_USERS)
.document(receiverUser.uid)
.collection(KEY_COLLECTION_CHAT)
.addSnapshotListener { value, error ->
if (error != null) {
return#addSnapshotListener
} else {
if (value == null) {
return#addSnapshotListener
} else {
for (documentChange in value.documentChanges) {
if (documentChange.type == DocumentChange.Type.ADDED) {
var doc = documentChange.document
if (doc.getString(KEY_MESSAGE_RECEIVER_ID) == preferenceManager.getString(
KEY_USER_ID
)
) {
var text = doc.getString(KEY_MESSAGE).toString()
var id = doc.getString(KEY_MESSAGE_ID).toString()
var receiverId = doc.getString(KEY_MESSAGE_RECEIVER_ID).toString()
var date = doc.getDate(KEY_MESSAGE_DATE)!!
var isChecked = doc.getBoolean(KEY_MESSAGE_ISCHECKED)!!
var type = doc.getString(KEY_TYPE_MESSAGE).toString()
var message = Message(text, id, receiverId, date, isChecked, type)
messages.add(message)
}
}
}
val chatComparator =
Comparator { obj1: Message, obj2: Message -> obj1.date.compareTo(obj2.date) }
Collections.sort(messages, chatComparator)
var messages_test = ArrayList(messages)
userChatAdpater.updateList(messages_test)
if (messages.size != 0) {
mBinding.rvUserChat.smoothScrollToPosition(messages.size - 1)
}
}
}
}
}
is a message listener
class UserChatAdapter( messages:List<Message>,receiverImage: String,senderId:String) :
RecyclerView.Adapter<UserChatAdapter.UserChatViewHolder>() {
var messages = messages
var receiverImage = receiverImage
var senderID = senderId
open class UserChatViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private fun getBitmapFromEncodedString(encodedImage:String): Bitmap {
val bytes = Base64.decode(encodedImage, Base64.DEFAULT)
return BitmapFactory.decodeByteArray(bytes,0,bytes.size)
}
private fun getReadableDateTime(date: Date): String {
return SimpleDateFormat("MMMM dd, yyyy - hh:mm a", Locale.getDefault()).format(date)
}
fun bind(type:Int, view:View, position: Int, messages: List<Message>, receiverImage: String){
if(type == SENT_TEXT){
SentTextMessageViewHolder(view).message.text = messages.get(position).message
SentTextMessageViewHolder(view).dateTime.text = getReadableDateTime(messages.get(position).date)
}else if( type == SENT_IMAGE){
SentImageMessageViewHolder(view).message.setImageURI(Uri.parse(messages.get(position).message))
SentImageMessageViewHolder(view).dateTime.text = getReadableDateTime(messages.get(position).date)
}else if(type == RECEIVED_TEXT){
ReceivedTextMessageViewHolder(view).message.text = messages.get(position).message
ReceivedTextMessageViewHolder(view).dateTime.text = getReadableDateTime(messages.get(position).date)
ReceivedTextMessageViewHolder(view).imageReceiver.setImageBitmap(getBitmapFromEncodedString(receiverImage))
}else if(type == RECEIVED_IMAGE){
ReceivedImageMessageViewHolder(view).message.setImageURI(Uri.parse(messages.get(position).message))
ReceivedImageMessageViewHolder(view).dateTime.text = getReadableDateTime(messages.get(position).date)
ReceivedImageMessageViewHolder(view).imageReceiver.setImageBitmap(getBitmapFromEncodedString(receiverImage))
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserChatViewHolder {
lateinit var viewHolder:UserChatViewHolder
if (viewType == SENT_TEXT) {
val layout = R.layout.item_container_sent_message
val view = LayoutInflater.from(parent.context).inflate(layout, parent, false)
viewHolder = SentTextMessageViewHolder(view)
} else if(viewType == RECEIVED_TEXT) {
val layout = R.layout.item_container_received_message
val view = LayoutInflater.from(parent.context).inflate(layout, parent, false)
viewHolder = ReceivedTextMessageViewHolder(view)
}else if(viewType == RECEIVED_IMAGE){
val layout = R.layout.item_container_received_message_image
val view = LayoutInflater.from(parent.context).inflate(layout, parent, false)
viewHolder = ReceivedImageMessageViewHolder(view)
}else if(viewType == SENT_IMAGE){
val layout = R.layout.item_container_sent_message_image
val view = LayoutInflater.from(parent.context).inflate(layout, parent, false)
viewHolder = SentImageMessageViewHolder(view)
}
return viewHolder
}
override fun onBindViewHolder(holder: UserChatViewHolder, position: Int) {
holder.bind(holder.itemViewType,holder.itemView,position,messages,receiverImage)
}
override fun getItemCount(): Int {
return messages.size
}
fun updateList(newMessages: ArrayList<Message>){
val oldList = messages
val newList = newMessages
val diffResult: DiffUtil.DiffResult = DiffUtil.calculateDiff(
UserChatDiffCallBack(oldList,newList)
)
messages = newMessages
diffResult.dispatchUpdatesTo(this)
}
override fun getItemViewType(position: Int): Int {
if(messages.get(position).type == MESSAGE_TYPE_IMAGE){
if (senderID == messages.get(position).receiverID) {
return RECEIVED_IMAGE
} else {
return SENT_IMAGE
}
}else{
if (senderID == messages.get(position).receiverID) {
return RECEIVED_TEXT
} else {
return SENT_TEXT
}
}
}
}
is an adapter for RecyclerView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mGetContent = registerForActivityResult(ActivityResultContracts.GetContent(),
ActivityResultCallback {
val intent = Intent(APP_ACTIVITY, CropperAcrtivity::class.java)
intent.putExtra("DATA", it.toString())
startActivityForResult(intent, 101)
})
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == -1 && requestCode == 101) {
var result = data!!.getStringExtra("RESULT")
var resultUri: Uri = Uri.parse(result)
if (resultUri != null) {
sendMessageAsImage(resultUri)
}
}
}
private fun sendMessageAsImage(image: Uri) {
var text = image.toString()
var id = UUID.randomUUID().mostSignificantBits.toString()
val message = Message(text, id, receiverUser.uid, Date(), false, MESSAGE_TYPE_IMAGE)
database.collection(KEY_COLLECTION_USERS)
.whereEqualTo(KEY_UID,preferenceManager.getString(KEY_UID))
.get().addOnCompleteListener {
it.getResult().documents.get(0).reference.collection(KEY_COLLECTION_CHAT).add(message)
}
}

Why is the .update("field","value") not working?

If you see the read messages function in my activity class below, i wanted to update the isSeen field in firestore, but for some reason it does not work at all. My guess it requires a specific document value but that would not be possible as this a messaging app so there will be a lot of documents created.
Activity Class
class MessageActivity : AppCompatActivity() {
private lateinit var binding: ActivityMessageBinding
private lateinit var chat: ArrayList<Message>
private lateinit var messageAdapter: MessageAdapter
private lateinit var roomID: String
private lateinit var userID: String
private lateinit var recID: String
private var c: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMessageBinding.inflate(layoutInflater)
setContentView(binding.root)
userID = FirebaseAuth.getInstance().uid.toString()
recID = intent.getStringExtra("userID").toString()
val recName:String = intent.getStringExtra("userName").toString()
binding.userName.text = recName
chat = arrayListOf()
messageAdapter = MessageAdapter(chat)
binding.recyclerView.setHasFixedSize(true)
binding.recyclerView.layoutManager = LinearLayoutManager(this)
when {
userID < recID ->
{
roomID = userID + recID
}
userID.compareTo(recID) == 0 ->
{
Toast.makeText(this, "Error you are chatting with yourself!!!", Toast.LENGTH_SHORT).show()
}
else -> {
roomID = recID + userID
}
}
readMessages(userID,recID)
binding.btnSend.setOnClickListener {
val message: String = binding.textSend.text.toString()
if(message.isNotEmpty()){
sendMessage(userID,recID,message)
binding.textSend.text.clear()
}
else{
Toast.makeText(this,"You can't send empty message", Toast.LENGTH_SHORT).show()
}
}
binding.gps.setOnClickListener {
val uri = "http://maps.google.com/maps?daddr="
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(uri))
intent.setPackage("com.google.android.apps.maps")
startActivity(intent)
}
}
private fun sendMessage(sender: String, rec: String, message: String){
val db = Firebase.firestore
val time: FieldValue = FieldValue.serverTimestamp()
val msg = hashMapOf(
"userID" to sender,
"recID" to rec,
"message" to message,
"time" to time,
"roomID" to roomID,
"isSeen" to false
)
db.collection("chats").document(roomID).collection("messages").document().set(msg,SetOptions.merge())
}
private fun readMessages(userId: String, recId: String){
val rootRef = Firebase.firestore
rootRef.collection("chats").document(roomID).collection("messages").orderBy("time", Query.Direction.ASCENDING).addSnapshotListener(object : EventListener<QuerySnapshot?>
{
override fun onEvent(#Nullable documentSnapshots: QuerySnapshot?, #Nullable e: FirebaseFirestoreException?)
{
if (e != null)
{
Log.e(TAG, "onEvent: Listen failed.", e)
return
}
chat.clear()
if (documentSnapshots != null)
{
for (queryDocumentSnapshots in documentSnapshots)
{
val msg = queryDocumentSnapshots.toObject(Message::class.java)
if (msg.recID == recId && msg.userID == userId || msg.recID == userId && msg.userID == recId)
{
chat.add(msg)
}
if(msg.recID.equals(userID).and(msg.userID.equals(recID))){
rootRef.collection("chats").document(roomID).collection("messages").document().update("isSeen",true)
}
messageAdapter = MessageAdapter(chat)
binding.recyclerView.adapter = messageAdapter
}
}
}
})
}
}
Adapter Class
class MessageAdapter(private val MessageList:ArrayList<Message>):RecyclerView.Adapter<MessageAdapter.MessageViewHolder>() {
private val left = 0
private val right = 1
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageViewHolder {
return if(viewType==right){
val view1 = LayoutInflater.from(parent.context).inflate(R.layout.chat_sender_item,parent,false)
MessageViewHolder(view1)
}else{
val view2 = LayoutInflater.from(parent.context).inflate(R.layout.chat_receiver_item,parent,false)
MessageViewHolder(view2)
}
}
override fun onBindViewHolder(holder: MessageViewHolder, position: Int) {
val message:Message = MessageList[position]
holder.showMessage.text = message.message
if(position==MessageList.size-1){
if(message.isSeen)
{
holder.textSeen.text = "Seen"
}else{
holder.textSeen.text = "Delivered"
}
}else{
holder.textSeen.visibility = View.GONE
}
}
override fun getItemCount(): Int {
return MessageList.size
}
class MessageViewHolder(itemView:View) : RecyclerView.ViewHolder(itemView){
val showMessage: TextView = itemView.findViewById(R.id.showMessage)
val textSeen: TextView = itemView.findViewById(R.id.textSeen)
}
override fun getItemViewType(position: Int): Int {
val userID = FirebaseAuth.getInstance().currentUser!!.uid
return if(MessageList[position].userID==userID)
{
right
}else
{
left
}
}
}
Model Class
package com.aarondcosta99.foodreuseapp.model
data class Message(var userID:String? = "",var message:String? = "",var recID:String? = "",var isSeen:Boolean=false)
Firestore
This won't work:
rootRef.collection("chats").document(roomID).collection("messages").document().update("isSeen",true)
The document() call without any arguments creates a reference to a new non-existing document, which you then try to update. But update() only works when a document already exists, you can't use update() to create a document, so this code ends up doing nothing.
To update a document, you need to specify the complete path to that document. The fact that you need to update a lot of documents makes no difference to that fact, it just means you'll need to paths to a lot of documents.
As far as I can tell, you are trying to update the document that you read in documentSnapshots, which means you already have the DocumentReference handy and can update it with:
queryDocumentSnapshots.reference.update("isSeen",true)

Recyclerview is not showing any items after filter results are set

I had to remade ArrayAdapter with filter feature to RecyclerView Adapter because of nested scrolling issues. But after I remade it, RecyclerView is empty, but adapter.itemCount is returning right value. Problem is that after I call adapter.notifyDataSetChanged(), it is not calling onCreateViewHolder or onBindViewHolder function.
class ZoneViewHolder(val root: ViewGroup): RecyclerView.ViewHolder(root) {
fun bind(
zone: FlightZone,
manageZoneCheck: (View)-> Unit,
maybeAutoselectZone: (View) -> Unit){
root.setOnClickListener {
manageZoneCheck(root.find(R.id.check))
}
root.find<View>(R.id.check).also { check->
check.setOnClickListener {
manageZoneCheck(check)
}
//autoselect zone if it was previously picked (after search reset)
maybeAutoselectZone(check)
}
root.findText(R.id.zoneNum).text = zone.name
root.findText(R.id.zoneName).apply {
isSelected = true
text = zone.radarInfo
}
root.findText(R.id.separator).setVisibleNotGone(zone.radarInfo != null)
}
}
class ZoneListAdapter(
private val ctx: Context,
private val inflater: LayoutInflater,
private val zoneView: Int,
private val zoneList: List<FlightZone>,
private var list: MutableList<FlightZone>,
private val pickedZones: List<FlightZone>,
private val onZoneChecked: (FlightZone, Boolean) -> Unit,
private val onAllZonesChecked: (Boolean) -> Unit,
private val onFilterDone: (List<FlightZone>) -> Unit
): RecyclerView.Adapter<ZoneViewHolder>(), Filterable{
override fun getItemCount() = list.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ZoneViewHolder {
return ZoneViewHolder(inflater.inflate(zoneView, parent, false) as ViewGroup)
}
override fun onBindViewHolder(vh: ZoneViewHolder, position: Int) {
val zone = list[position]
App.log("ZoneListAdapter: onBindView: ${list.size}")
vh.bind(
zone,
manageZoneCheck = { check->
manageZoneCheck(check, zone)
},
maybeAutoselectZone = {check->
App.log("ZoneListAdapter: alreadyPicked: ${pickedZones.size}")
if (pickedZones.find { it.id == zone.id } != null) check.callOnClick()
}
)
}
/**
* Custom Filter implementation for custom suggestions we provide.
*/
data class ZoneFilterable(val zone: FlightZone, val prefixLength: Int)
internal var tempItems: MutableList<FlightZone> = zoneList.toMutableList()
internal var suggestions: MutableList<ZoneFilterable> = mutableListOf()
internal val sharedCounterLock = Semaphore(1)
private var filter = object : Filter(){
override fun performFiltering(constraint: CharSequence?): FilterResults {
return if (constraint != null) {
sharedCounterLock.acquire()
suggestions.clear()
filterByName(constraint)
suggestions.sortedByDescending { it.prefixLength }
val filterResults = FilterResults()
filterResults.values = suggestions
filterResults.count = suggestions.size
sharedCounterLock.release()
filterResults
} else {
FilterResults()
}
}
private fun filterByName(constraint: CharSequence?){
tempItems.forEach {
val zoneName = it.name.toLowerCase(Locale.getDefault())
val zoneNameNonAccent = zoneName.removeDiacritics()
val query = constraint.toString().toLowerCase(Locale.getDefault())
val queryNonAccent = query.removeDiacritics()
App.log("FlightZonePicker filter zone name non-accent: $zoneNameNonAccent")
if (zoneNameNonAccent.contains(queryNonAccent)) {
val prefix = zoneName.commonPrefixWith(query)
suggestions.add(ZoneFilterable(it, prefix.length))
}
}
}
override fun publishResults(constraint: CharSequence?, results: FilterResults) {
if (results.count > 0) {
list.clear()
val filterList = results.values as? List<Any?>
var resultList = mutableListOf<FlightZone>()
GlobalScope.launch(Dispatchers.Main) {
val resultListAsync = async {
withContext(Dispatchers.Default) {
val list = mutableListOf<FlightZone>()
sharedCounterLock.acquire()
val iter = filterList?.iterator()
iter?.let {
while (iter.hasNext()) {
val item = iter.next()
(item as ZoneFilterable).let { (zoneEntity) -> list.add(zoneEntity) }
}
}
sharedCounterLock.release()
return#withContext list
}
}
resultList = resultListAsync.await().take(10).toMutableList()
App.log("ZoneListAdapter: Results: ${resultList.size}")
list.addAll(resultList)
onFilterDone.invoke(resultList)
}
}
}
}
init {
tempItems = zoneList.toMutableList()
}
override fun getFilter(): Filter {
return filter
}
}
MainClass:
zoneListRecycleView = findViewById(R.id.zoneResults)
zoneListAdapter = ZoneListAdapter(
ctx,
f.layoutInflater,
R.layout.zone_pick_item,
zoneList,
filteredZones,
pickedZones,
onZoneChecked = {
zone, isPicked ->
pickedZones.apply {
if (isPicked){
if (find { it.id == zone.id } == null) add(zone)
} else {
if (find { it.id == zone.id } != null) remove(zone)
}
}
zoneListAdapter.notifyDataSetChanged()
},
onAllZonesChecked = {ischecked->
pickedZones.apply {
clear()
if(ischecked) addAll(zoneList)
}
zoneListAdapter.notifyDataSetChanged()
},
::onFilterResult
)
zoneListRecycleView.adapter = zoneListAdapter
private fun onFilterResult(list: List<FlightZone>){
filteredZones = list.toMutableList()
zoneListAdapter.notifyDataSetChanged()
App.log("ZonelistAdapter: count = ${zoneListAdapter.itemCount}")
}
UPDATE:
I changed Adapter to ListAdapter and I changed publishResults function to
resultList = resultListAsync.await().take(10).toMutableList()
onFilterDone.invoke(resultList)
And inside my parent class I call:
private fun onFilterResult(list: List<FlightZone>){
filteredZones = list.toMutableList()
zoneListAdapter.submitList(filteredZones)
App.log("ZonelistAdapter: filteredList = ${filteredZones.size}")
App.log("ZonelistAdapter: count = ${zoneListAdapter.itemCount}")
}
Log:
app: ZonelistAdapter: filteredList = 10
app: ZonelistAdapter: count = 0
There is still some issue with adapter. So filter feature is working as intended but adapter and recyclerview is not displaying items for some reason.

Print all items in Recyclerview to pdf file

I have been stuck on this for over 2 weeks. I tried everything and search everywhere but nothing worked.
I have an android app with sqlite database.
I made a recyclerview with a custom adapter because every item in the recyclerview consists of 80 Textviews.
I want to print every row of the recyclerview in a seperate page but in the same document. when I try to print the rows of recyclerview, I get only the visible rows on the screen which is the first and the second row only while my recyclerview consists of at least 10 to 20 rows. I'm using the latest version of android studio and Kotlin.
here is what I have so far
this is my custom Adapter
class BianProductsAdapter(mCtx: Context,val bianproducts: ArrayList<LV_BProducts>) : RecyclerView.Adapter<BianProductsAdapter.ViewHolder>() {
val mCtx = mCtx
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val lbpid = itemView.bianproductid
val lbpproductname = itemView.bianproductname
val lbpproductunit = itemView.bianproductunit
val lbpproductquantity = itemView.bianproductquantity
val lbpproductoriginalprice = itemView.bianproductoriginalprice
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BianProductsAdapter.ViewHolder {
val v : View= LayoutInflater.from(parent.context).inflate(R.layout.lo_b_products,parent,false)
return BianProductsAdapter.ViewHolder(v)
}
override fun onBindViewHolder(holder: BianProductsAdapter.ViewHolder, position: Int) {
val df = DecimalFormat("###,###,##0.00")
val bianproduct : LV_BProducts = bianproducts[position]
holder.lbpid.text = bianproduct.lvbp_id.toString()
holder.lbpproductname.text = bianproduct.lvbp_product_name.toString()
holder.lbpproductunit.text = bianproduct.lvbp_unit.toString()
holder.lbpproductquantity.text = bianproduct.lvbp_quantity.toString()
holder.lbpproductoriginalprice.text = "$"+ df.format(bianproduct.lvbp_original_price.toFloat())
}
override fun getItemCount(): Int {
return bianproducts.size
}
}
and this is Activity.kt`
class BProductsActivity : AppCompatActivity() {
inner class MyPrintDocumentAdapter(private var context: Context)
: PrintDocumentAdapter() {
private var pageHeight: Int = 0
private var pageWidth: Int = 0
private var myPdfDocument: PdfDocument? = null
private fun drawPage(
page: PdfDocument.Page,
pagenumber: Int
) {
var pagenum = pagenumber
val canvas = page.canvas
pagenum++
val titleBaseLine = 72
val leftMargin = 54
val paint = Paint()
paint.color = Color.BLACK
val pageInfo = page.info
}
private fun pageInRange(pageRanges: Array<PageRange>, page: Int): Boolean {
for (i in pageRanges.indices) {
if (page >= pageRanges[i].start && page <= pageRanges[i].end)
return true
}
return false
}
override fun onLayout(
oldAttributes: PrintAttributes?,
newAttributes: PrintAttributes?,
cancellationSignal: android.os.CancellationSignal?,
callback: LayoutResultCallback?,
extras: Bundle?
) {
myPdfDocument = newAttributes?.let { PrintedPdfDocument(context, it) }
val height = newAttributes?.mediaSize?.heightMils
val width = newAttributes?.mediaSize?.heightMils
height?.let {
pageHeight = it / 1000 * 72
}
width?.let {
pageWidth = it / 1000 * 72
}
if (cancellationSignal != null) {
if (cancellationSignal.isCanceled) {
if (callback != null) {
callback.onLayoutCancelled()
}
return
}
}
if (totalpages > 0) {
val builder =
PrintDocumentInfo.Builder("print_output.pdf").setContentType(
PrintDocumentInfo.CONTENT_TYPE_DOCUMENT
)
.setPageCount(totalpages)
val info = builder.build()
if (callback != null) {
callback.onLayoutFinished(info, true)
}
} else {
if (callback != null) {
callback.onLayoutFailed("Page count is zero.")
}
}
}
override fun onWrite(
pages: Array<out PageRange>?,
destination: ParcelFileDescriptor?,
cancellationSignal: android.os.CancellationSignal?,
callback: WriteResultCallback?
) {
for (i in 0 until totalpages) {
if (pageInRange(pages as Array<PageRange>, i)) {
val newPage = PdfDocument.PageInfo.Builder(
pageWidth,
pageHeight, i
).create()
if (cancellationSignal != null) {
if (cancellationSignal.isCanceled) {
if (callback != null) {
callback.onWriteCancelled()
}
myPdfDocument?.close()
myPdfDocument = null
return
}
}
val page = myPdfDocument?.startPage(newPage)
val content: View = mybprv.get(i) //mybprv is the ID of my recyclerview
val measureWidth = View.MeasureSpec.makeMeasureSpec(
page!!.canvas.width,
View.MeasureSpec.EXACTLY
)
val measuredHeight = View.MeasureSpec.makeMeasureSpec(
page.canvas.height,
View.MeasureSpec.EXACTLY
)
content.measure(measureWidth, measuredHeight)
content.layout(0, 0, page.canvas.width, page.canvas.height)
if (page != null) {
content.draw(page.canvas)
}
myPdfDocument?.finishPage(page)
}
}
try {
if (destination != null) {
myPdfDocument?.writeTo(
FileOutputStream(
destination.fileDescriptor
)
)
}
} catch (e: IOException) {
if (callback != null) {
callback.onWriteFailed(e.toString())
}
return
} finally {
myPdfDocument?.close()
myPdfDocument = null
}
if (callback != null) {
callback.onWriteFinished(pages)
}
}
}
fun printDocument(view: View) {
val printManager = this.getSystemService(Context.PRINT_SERVICE) as PrintManager
val jobName = this.getString(R.string.app_name) + " Document"
printManager.print(jobName, MyPrintDocumentAdapter(this), null)
}
companion object{
lateinit var bpdbHandler: DBHandler
private var totalpages =0
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_b_products)
bpdbHandler = DBHandler(this,null,null,1)
populateList()
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
//return super.onCreateOptionsMenu(menu)
menuInflater.inflate(R.menu.addbianproduct,menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId==R.id.bainproductpage){
printDocument(mybprv) // mybprv is the id of my recyclerview
}
return super.onOptionsItemSelected(item)
}
override fun onResume() {
super.onResume()
populateList()
}
private fun populateList() {
val productslist : ArrayList<LV_BProducts>? = intent.getStringExtra("bid")?.let { bpdbHandler.getBianProducts(this, it) }
val adapter = productslist?.let { BianProductsAdapter(this, it) }
val rv : RecyclerView = findViewById(R.id.mybprv)
rv.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL,false)
rv.adapter = adapter
rv.isNestedScrollingEnabled = false
if (productslist != null) {
totalpages = productslist.size
}
}
}
I get the exact records I want from the query and I can show all these records data in the recyclerview. My only problem is printing the recyclerview.
the number of pages printed = the number of rows returned by my query = the number of rows in my recyclerview
However, only visible rows which are row 1 and 2 get printed and the remaining pages are either a repetation of row 2 or empty
All your help is highly appreciated.
P.S: I know my code looks messy because it is a mix of two weeks searching and applying solutions from multiple sources until I got stuck where I am now.

LongClickListerner Not Responding (Kotlin/RecyclerView

I have implemented a onClicklistener in my recycleview which works but the onLongClickListener is not responding? I have added the code in the Adapter, which is being called from a fragment. The onClickListener works well. Whn I click onLongClick -> it needs to display an AlertDialog, but in this case on running the app, there are no errors and no longclick too. This is in Kotlin, what am I doing wrong - any thoughts please?
class UserMsgAdapter(
mContext: Context,
userMsgList: List<MessageList>,
mUsers: List<Users>,
isChatCheck: Boolean
): RecyclerView.Adapter<UserMsgAdapter.ViewHolder?>()
{
private val mContext: Context
private val userMsgList: List<MessageList>
private val mUsers:List<Users>
private var isChatCheck: Boolean
init{
this.mUsers = mUsers
this.userMsgList = userMsgList
this.mContext = mContext
this.isChatCheck = isChatCheck
}
var lastMsg: String = ""
var timeMsg: Long = 0
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
val view: View = LayoutInflater.from(mContext).inflate(
R.layout.user_search_item_layout,
viewGroup,
false
)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val message: MessageList? = userMsgList[position]
//Accessing the receiverId from the ChatList
val receiverId = message!!.getId()
val ref = FirebaseDatabase.getInstance().reference.child("Users").child(receiverId!!)
ref.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(p0: DataSnapshot) {
val user = p0.getValue(Users::class.java)
holder.userNameText.text = user!!.getUserName()
Picasso.get().load(user.getProfile())
.placeholder(R.drawable.ic_baseline_whatshot_24).fit().centerCrop().into(
holder.profileImageView
)
//Showcasing Last Message
if (isChatCheck) {
retrieveLastMessage(
user.getUID(),
holder.lastMessagetxt,
holder.timestamptxt,
holder.new_message_count
)
} else {
holder.lastMessagetxt.visibility = View.GONE
}
//Calling the Message Activity
holder.itemView.setOnClickListener {
val intent = Intent(mContext, MessageActivity::class.java)
intent.putExtra("visit_id", user.getUID())
mContext.startActivity(intent)
}
//Menu on Search Fragment
holder.itemView.setOnLongClickListener {
val options = arrayOf<CharSequence>(
"Delete Chat",
"Visit Profile"
)
val builder: AlertDialog.Builder = AlertDialog.Builder(mContext)
builder.setTitle("What would you like to do?")
builder.setItems(options, DialogInterface.OnClickListener { _, which ->
if (which == 0) {
val intent = Intent(mContext, MessageActivity::class.java)
intent.putExtra("visit_id", user.getUID())
mContext.startActivity(intent)
}
if (which == 1) {
val intent = Intent(mContext, VisitUserProfile::class.java)
intent.putExtra("visit_id", user.getUID())
mContext.startActivity(intent)
}
})
builder.show()
true
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}
override fun getItemCount(): Int {
return userMsgList.size
}
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView)
{
var userNameText: TextView = itemView.findViewById(R.id.username)
var profileImageView: ShapeableImageView = itemView.findViewById(R.id.profile_image)
var lastMessagetxt: TextView = itemView.findViewById(R.id.last_message)
var timestamptxt: TextView = itemView.findViewById(R.id.time_stamp)
var new_message_count: TextView = itemView.findViewById(R.id.new_message_count)
}
//print last message and timestamp
private fun retrieveLastMessage(
messageUserId: String?, lastMessagetxt: TextView,
timestamptxt: TextView, new_message_count: TextView,
)
{
lastMsg = "defaultMsg"
timeMsg = 0
var countUnreadMessages = 0
val firebaseUser = FirebaseAuth.getInstance().currentUser
val reference = FirebaseDatabase.getInstance().reference.child("Chats")
reference.addValueEventListener(object : ValueEventListener {
override fun onDataChange(p0: DataSnapshot) {
for (dataSnapshot in p0.children) {
val message: Message? = dataSnapshot.getValue(Message::class.java)
if (firebaseUser != null && message != null) {
if (message.getReceiver() == firebaseUser.uid && message.getSender() == messageUserId ||
message.getReceiver() == messageUserId && message.getSender() == firebaseUser.uid
) {
lastMsg = message.getMessage()!!
timeMsg = message.getTimestamp()!!
}
if (message.getReceiver() == firebaseUser.uid && message.getSender() == messageUserId && !message.isIsSeen()) {
countUnreadMessages += 1
}
}
}
when (lastMsg) {
"defaultMsg" -> lastMessagetxt.text = ""
"Shared an image with you." -> lastMessagetxt.text = "Shared an image"
else -> lastMessagetxt.text = lastMsg
}
//Display count of unread messages
if (countUnreadMessages != 0) {
new_message_count.text = countUnreadMessages.toString()
new_message_count.setBackgroundResource(R.drawable.new_chat_bg)
} else {
new_message_count.setBackgroundResource(0)
new_message_count.text = ""
}
countUnreadMessages = 0
//Display formatted date and time
val time = dateFormatter(timeMsg)
when (time) {
"01-01-1970" -> timestamptxt.text = ""
else -> timestamptxt.text = time
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}
}

Categories

Resources