Why are my firebase images not being displayed in the RecyclerView? - android

JSON:
people
uid /// the actual uid of each user not a child named uid
imageUrl
Below is the relevant code:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_homepage)
val user = FirebaseAuth.getInstance().currentUser
if (user != null) {
val query = FirebaseDatabase.getInstance().reference.child("people").child("imageUrl")
val options = FirebaseRecyclerOptions.Builder<DataSnapshot>()
.setQuery(query, DataSnapshot::class.java)
.build()
Log.d("DataSnapshot1", options.toString())
class PhotoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val photoImageView = itemView.findViewById<ImageView>(R.id.image_view)
}
val adapter = object : FirebaseRecyclerAdapter<DataSnapshot, PhotoViewHolder>(options) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PhotoViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.item_photo, parent, false)
return PhotoViewHolder(view)
}
override fun onBindViewHolder(holder: PhotoViewHolder, position: Int, model: DataSnapshot) {
Log.d("DataSnapshot", model.toString())
val imageUrl = model.child("imageUrl").getValue(String::class.java)
if (imageUrl != null) {
Log.d("ImageUrl", imageUrl)
Glide.with(holder.itemView.context)
.load(imageUrl)
.into(holder.photoImageView)
}
}
}
val recyclerView = findViewById<RecyclerView>(R.id.cycle)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = adapter
adapter.startListening()
}
}
What I know: The problem is not in the XMLs of this page or the image to be displayed on the recycler view. Also, ("ImageUrl") and "DataSnapshot" don't print out. But "DataSnapshot1" does print out.

I assume you're trying to list all the items under the people node?
In that case, you need to update your query to:
val query = FirebaseDatabase.getInstance().reference.child("people")
I don't think FirebaseUI supports DataSnapshot as a model class, so I would suggest creating a separate class to hold the data. I have created a Person class as an example:
data class Person(var imageUrl: String? = null)
And then your options would become:
val options = FirebaseRecyclerOptions.Builder<Person>()
.setQuery(query, Person::class.java)
.build()
And your adapter:
val adapter = object : FirebaseRecyclerAdapter<Person, PhotoViewHolder>(options) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PhotoViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.item_photo, parent, false)
return PhotoViewHolder(view)
}
override fun onBindViewHolder(holder: PhotoViewHolder, position: Int, model: Person) {
val imageUrl = model.imageUrl
if (imageUrl != null) {
Log.d("ImageUrl", imageUrl)
Glide.with(holder.itemView.context)
.load(imageUrl)
.into(holder.photoImageView)
}
}
}

Related

Layout inflater is not inflating view

I feel that in this code my layout is not being attached.I verified by toast,log.d but nothing worked.Here this I am using for a recycler view view holder.Code is below
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(mContext).inflate(R.layout.posts_layout,parent,false)
return ViewHolder(view)
}
and onBindViewHolder.I user log to check if this method is being used but,its not used
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
firebaseUser = FirebaseAuth.getInstance().currentUser!!
Log.d("binded", true.toString())
val post = mPost[position]
getPublisherInfo(holder.profileImage ,holder.userName , holder.userFullName ,post.getpublisher())
Glide.with(mContext).load(post.getpostId()).placeholder(R.drawable.image).into(holder.postImage)
}
I also checked if my list size id 0 for it to not come.For it use used log and it showed the list size 5 which is correct.This meant that my data is being retrieved from database.So it think that the my layout inflater is not working.The code for it is.
private fun readPosts() {
val postsRef = FirebaseDatabase.getInstance().reference.child("Posts")
postsRef.addValueEventListener(object : ValueEventListener{
#SuppressLint("NotifyDataSetChanged")
override fun onDataChange(snapshot: DataSnapshot) {
postList.clear()
for(snapshot in snapshot.children){
val post = snapshot.getValue(Post::class.java)
for (uid in (followingList as ArrayList<String>)) {
if (post!!.getpublisher().equals(uid)) {
postList.add(post)
}
Log.d("added", postList.size.toString())
Log.d("added", postList.toString())
postAdapter.notifyDataSetChanged()
}
}
}
override fun onCancelled(error: DatabaseError) {}
})
}
My entire adapter code is
package com.u_me_pro.free.Adapters
class PostAdapter(private val mContext: Context,private val mPost: List<Post>) :
RecyclerView.Adapter<PostAdapter.ViewHolder>() {
private lateinit var firebaseUser : FirebaseUser
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(mContext).inflate(R.layout.posts_layout,parent,false)
Log.d("attached layout","true")
return ViewHolder(view)
}
class ViewHolder(#NonNull itemView: View) : RecyclerView.ViewHolder(itemView){
var description: TextView = itemView.findViewById(R.id.description)
var userName: TextView = itemView.findViewById(R.id.user_name_post)
var userFullName: TextView = itemView.findViewById(R.id.user_full_name_post)
var commentCount: TextView = itemView.findViewById(R.id.comment_count)
var likeCount: TextView = itemView.findViewById(R.id.love_count)
var profileImage: RoundedImageView = itemView.findViewById(R.id.user_profile_image_post)
var postImage: RoundedImageView = itemView.findViewById(R.id.post_image)
var like: CardView = itemView.findViewById(R.id.post_image_like)
var comment: CardView = itemView.findViewById(R.id.post_image_comment)
var save: CardView = itemView.findViewById(R.id.post_image_save)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
firebaseUser = FirebaseAuth.getInstance().currentUser!!
Log.d("binded", true.toString())
val post = mPost[position]
getPublisherInfo(holder.profileImage ,holder.userName , holder.userFullName ,post.getpublisher())
Glide.with(mContext).load(post.getpostId()).placeholder(R.drawable.image).into(holder.postImage)
}
override fun getItemCount(): Int {
return mPost.size
}
private fun getPublisherInfo(profileImage: RoundedImageView, userName: TextView, userFullName: TextView, publisherId: String) {
val usersRef = FirebaseDatabase.getInstance().reference.child("Users").child(publisherId)
Log.d("publisher id",publisherId)
usersRef.addValueEventListener(object :ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()){
val user = snapshot.getValue(User::class.java)
userName.text = user!!.getFullname()
userFullName.text = user.getFullname()
Glide.with(mContext).load(user.getImage()).placeholder(R.drawable.profile).into(profileImage)
}
}
override fun onCancelled(error: DatabaseError) {
Log.d(TAG, error.getMessage());
}
})
}
}
Please help me out soon.
Thanks!
You're updating the post list and notifying the adapter of a change but it doesn't appear that you're ever actually passing in the updated list to the adapter.
postAdapter.notifyDataSetChanged()
Won't do anything if the actual data in your adapter hasn't changed.
You should add a way to update your post list in the adapter such as
fun setPostData(posts: List<Post>) {
this.adapterPosts = posts
notifyDataSetChanged() // Either call this here or where you were before
}
This would also require you to create a new variable to hold the passed-in list
private var adapterPosts = mPosts

RecyclerView make endless scrolling with JSON

I'm trying to make my Android App (I'm only experienced in iOS).
I created a RecyclerView that gets the data from a web. I tried everything to implement endless scrolling to load more items, but when I call the function to get the items, the entire RecyclerView loads again and no attach the new results on the bottom.
This is my code:
ConversationUser.kt
data class ConversationUser(
val message_nickname: String,
val message_image_thumb: String,
val message_large_thumb: String,
val message_modified: String,
val message_status: String,
val message_unread: Int,
val conv_id: String,
val message_dest: String) {
}
ConversacionesActivity.kt
class ConversacionesActivity : AppCompatActivity() {
// MARK: Variables
var user_token = ""
var user_id = ""
override fun onCreate(savedInstanceState: Bundle?) {
// User Defaults
val sharedPreferences = getSharedPreferences("Preferences", Context.MODE_PRIVATE)
user_token = sharedPreferences.getString("user_token", "")!!
user_id = sharedPreferences.getString("user_id", "")!!
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_conversaciones)
recyclerConv.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))
getConversationsData()
recyclerConv.setLoadingListener(object : LoadingListener {
override fun onRefresh() {
//refresh data here
}
override fun onLoadMore() {
// load more data here
getConversationsData()
}
})
}
fun getConversationsData() {
val httpAsync = "https://mywebsite.com/conversations/${user_token}"
.httpPost()
.responseString { request, response, result ->
when (result) {
is Result.Failure -> {
val ex = result.getException()
println(ex)
}
is Result.Success -> {
val data = result.get()
runOnUiThread {
val conversaciones = processJson(data)
show(conversaciones)
return#runOnUiThread
}
}
}
}
httpAsync.join()
}
fun processJson(json: String): List<ConversationUser> {
val gson: Gson = GsonBuilder().create()
val conversaciones: List<ConversationUser> = gson.fromJson(
json,
Array<ConversationUser>::class.java
).toList()
return conversaciones
}
fun show(conversaciones: List<ConversationUser>) {
recyclerConv.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
recyclerConv.adapter = AdaptadorConv(conversaciones, this, user_token, user_id)
}
AdaptadorConv.kt
class AdaptadorConv(
val conversaciones: List<ConversationUser> = ArrayList(),
val context: Context,
val user_token: String,
val user_id: String) : RecyclerView.Adapter<AdaptadorConv.ConvViewHolder>() {
override fun onBindViewHolder(holder: ConvViewHolder, position: Int) {
holder.convName.text = conversaciones[position].message_nickname
holder.convTime.text = conversaciones[position].message_modified
}
override fun getItemCount(): Int {
return conversaciones.size - 1
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ConvViewHolder {
val view: View = LayoutInflater.from(parent.context).inflate(
R.layout.conversaciones,
parent,
false
)
return ConvViewHolder(view)
}
class ConvViewHolder(vista: View): RecyclerView.ViewHolder(vista) {
val convImg: ImageView = itemView.findViewById(R.id.convImg)
val convStatus: ImageView = itemView.findViewById(R.id.convStatus)
val convName: TextView = itemView.findViewById(R.id.convName)
val convUnread: TextView = itemView.findViewById(R.id.convUnread)
val convTime: TextView = itemView.findViewById(R.id.convTime)
}
Thanks for any help or hint.
Please check your show () method, you are creating new Adapter every time with the new dataset. You have to append the new items to the adapter's list and adapter should be set to list once. Helpful tutorial can be found at here.

how to show only limited amount of items from it the app using adapter

So I need to show only three objects from my Firebase database on the screen. How can this be implemented?
I retrieve my data using this logic with adapter.
retrieveData()
setData(recyclerView)
private fun setData(rec_view:RecyclerView) {
val query = FirebaseDatabase.getInstance().reference.child("News")
val options = FirebaseRecyclerOptions.Builder<News>()
.setQuery(query, News::class.java)
.build()
adapter = object:FirebaseRecyclerAdapter<News, NewsViewHolder>(options){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NewsViewHolder {
Log.d("onCreateViewHolder_n", "onCreateViewHolder")
val newsView = LayoutInflater
.from(parent.context)
.inflate(R.layout.new_card_new, parent, false)
return NewsViewHolder(newsView)
}
override fun onBindViewHolder(holder: NewsViewHolder, position: Int, model: News) {
holder.setIsRecyclable(false)
holder.title.text = model.text
holder.timestamp.text = model.timestamp
holder.setNewsClickListener(object: NNewsClickListener {
override fun onClick(view: View, position: Int) {
startActivity(Intent(Intent.ACTION_VIEW).setData(Uri.parse(model.link)));
}
})
}
}
rec_view.adapter = adapter
}
private fun retrieveData() {
items.clear()
val db = FirebaseDatabase.getInstance()
.reference
.child("News")
db.addListenerForSingleValueEvent(object :ValueEventListener{
override fun onCancelled(error: DatabaseError) {
Log.d("ERROR", "" + error.message)
}
override fun onDataChange(snapshot: DataSnapshot) {
for(item_newsSnapShot in snapshot.children)
{
val item_news = item_newsSnapShot.getValue(News::class.java)
items.add(item_news!!)
}
}
})
}
I found out somewhere that I should use getItemCount() or something like this but I'm not sure. If you have any questions regarding my problem, feel free to ask.
If the rest of your code already works, you can limit Firebase to retrieving only 3 items with:
val db = FirebaseDatabase.getInstance()
.reference
.child("News")
.limitToFirst(3)
I recommend checking out the documentation on sorting and filtering data.

Delete item in Arraylist in RecyclerView within Adapter

I'm having trouble to delete one item in my Arraylist from Firebase Database using RecyclerView. There is an AlertDialog which I can see when I'm clicking on it, but it doesn't delete the Item. I think the problem is, that I cannot get the postID correctly. But I tried it in many ways, and within the database Reference I wasn't able to do it right.
This is where I add the Post to the database:
val ref = FirebaseDatabase.getInstance().reference.child("Posts")
val postId = ref.push().key
And here you can see my PostsAdapter
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(mContext).inflate(R.layout.posts_layout, parent, false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return mPosts.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
FirebaseUser = FirebaseAuth.getInstance().currentUser
val posts = mPosts[position]
holder.title.text = posts.getTitle()
holder.content.text = posts.getContent()
holder.deletePost.text = posts.getPostId()
ownerInfo(holder.name, posts.getOwner())
}
inner class ViewHolder(#NonNull itemView: View) : RecyclerView.ViewHolder(itemView),
View.OnClickListener {
override fun onClick(p0: View?) {
val intent = Intent(itemView.context, DeletePostActivity::class.java)
// here pass id through intent
intent.putExtra("postId", R.id.deletePost)
itemView.context.startActivity(intent)
}
var title: TextView
var content: TextView
var owner: TextView
var name: TextView
var deletePost: Button
init{
title = itemView.findViewById(R.id.post_title)
content = itemView.findViewById(R.id.post_content)
owner = itemView.findViewById(R.id.post_owner)
name = itemView.findViewById(R.id.post_owner)
deletePost = itemView.findViewById(R.id.post_delete)
deletePost.setOnClickListener{
AlertDialog.Builder(mContext)
.setTitle("Löschen")
.setMessage("Wollen Sie diesen Post wirklich löschen?")
.setCancelable(true)
.setPositiveButton("Ja") { dialog, which ->
notifyItemRemoved(adapterPosition)
notifyItemRangeChanged(adapterPosition, mPosts.size)
val postsRef = FirebaseDatabase.getInstance().reference.child("Posts").child("postID")
postsRef.child("postID").removeValue()
}
.create()
.show()
}
}
}
Actually you are not passing any postID to delete. Check below
Instead of
val postsRef = FirebaseDatabase.getInstance().reference.child("Posts").child("postID")
postsRef.child("postID").removeValue()
use
val postsRef = FirebaseDatabase.getInstance().reference.child("Posts").child(deletePost.text)
postsRef.removeValue()

Get clicked item in recyclerview adapter

I want to create an android app with Kotlin. In this app, i use swagger also to get all the web service in a file.
I want to create an interface, the description is as follows:
A RecyclerView horizontal that contains all the list of categories
comes from a web service apiMobileProductCategoriesGetAllPost.
after that, when i click on a which category, a RecyclerView(Grid)
appear that contains all the product by category id.
I want to know how can i get the category id when i click on item,and how to use it in the activity
The following the RecyclerView category adapter:
class CategoryAdapter(private val categories: Array<ProductCategoryData>) :
RecyclerView.Adapter<CategoryAdapter.ViewHolder>(), View.OnClickListener {
private var onItemClickListener: OnItemClickListener? = null
override fun onClick(v: View?) {
if (v != null) {
onItemClickListener?.onItemClick(v, ProductCategoryData())
}
}
fun setOnItemClickListener(onItemClickListener: OnItemClickListener) {
this.onItemClickListener = onItemClickListener
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.category_item, parent, false)
view.setOnClickListener(this)
return ViewHolder(view)
}
override fun getItemCount() = categories.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val itemCategory: ProductCategoryData = categories[position]
holder.categoryId.text = itemCategory.id.toString()
println(holder.categoryId.text)
println(itemCategory.name?.get("En").toString())
holder.categoryName.text = itemCategory.name?.get("En").toString()
println(itemCategory.id)
if (itemCategory.logo != null) {
Picasso.get()
.load("..../T/${itemCategory.logo}")
.into(holder.categoryImage, object : com.squareup.picasso.Callback {
override fun onError(e: Exception?) {
holder.categoryImage.setImageResource(R.drawable.homecraftdefault)
}
override fun onSuccess() {
Picasso.get().load("....T/${itemCategory.logo}")
.into(holder.categoryImage)
}
})
holder.itemView.setOnClickListener {
onItemClickListener?.onItemClick(holder.itemView,itemCategory)
}
}
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
val categoryName: TextView = itemView.categoryName
val categoryImage: ImageView = itemView.categoryImage
val categoryId: TextView = itemView.categoryId
override fun onClick(v: View?) {
if (v != null) {
onItemClickListener?.onItemClick(v, ProductCategoryData())
}
}
}
interface OnItemClickListener {
fun onItemClick(view : View, viewModel:ProductCategoryData)
}
}
The following code is relative to the activity:
class CategoryByProduct : AppCompatActivity(), CategoryAdapter.OnItemClickListener {
override fun onItemClick(view: View, viewModel: ProductCategoryData) {
var params = "CategoryProductID";"5cc057458c4d9823743736d2"
println(viewModel.id)
val products = mobileApi!!.apiMobileProductsGetAllPost(params, 0, 50, "", "")
recyclerViewProductByCategory.apply {
recyclerViewProductByCategory.layoutManager = GridLayoutManager(this#CategoryByProduct, 2)
recyclerViewProductByCategory.adapter = ProductAdapter(products)
} }
var mobileApi: MobileApi? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.list_product_by_category)
mobileApi = MobileApi()
val params = HashMap<String, String>()
GlobalScope.launch(Dispatchers.IO) {
val categories = mobileApi!!.apiMobileProductCategoriesGetAllPost(params, 0, 50, "", "")
withContext(Dispatchers.Main) {
recyclerViewCategories.apply {
recyclerViewCategories.layoutManager =
LinearLayoutManager(this#CategoryByProduct, OrientationHelper.HORIZONTAL, false)
recyclerViewCategories.adapter = CategoryAdapter(categories)
}
}
}
}
}
First of all , never put your onclick in onBindViewHolder That's not a good practice, after that i think you need to get the ID of the category i will give you simple example in all of the Adapter Class
class NewsAdapter (val context: Context, private val arrayList: ArrayList <NewsModel>):
RecyclerView.Adapter <NewsAdapter.Holder> () {
companion object {
// val TAG: String = OperationAdapter::class.java.simpleName
}
override fun onCreateViewHolder (parent: ViewGroup, viewType: Int): Holder {
return Holder (LayoutInflater.from (parent.context ).inflate (R.layout.newslist , parent, false))
}
override fun getItemCount (): Int = arrayList. size
override fun onBindViewHolder (holder: Holder, position: Int) {
val mynews = arrayList[position]
holder.setData(mynews , position)
}
inner class Holder (itemView: View): RecyclerView.ViewHolder (itemView) {
private var currentnews: NewsModel? = null
private var currentPosition: Int = 0
init {
//The click listener
itemView.newscardview.setOnClickListener {
//do it here
Toast.makeText(this,currentnews!!.id,Toast.LENGTH_SHORT).show()
}
//the end of the init
}
//getting data from model and bind it into View
fun setData(news: NewsModel?, position: Int) {
news?.let {
itemView.newsid.text = news.id
itemView.newstitle.text = news.title
itemView.body.text = news.body
itemView.txtdate.text = news.ndate
}
this.currentnews = news
this.currentPosition = position
}
}
}
In this example you will get the news ID when you click newscardview, i hope to understand it
In your Activity
put this code in onCreate
//set up the recycleview
mRecyclerView.setHasFixedSize (true)
mRecyclerView. layoutManager = LinearLayoutManager(this)
mRecyclerView is my RecycleView
also call your Adapter class in anywhere you want
//adapter
val adapter = NewsAdapter (this,arrayList)
adapter.notifyDataSetChanged()
mRecyclerView.adapter = adapter
you get the position of the category inside a viewholder by calling adapterPosition and with this you can get the category from your list you provide to your adapter in the constructor (categories[adapterPosition])
In your case it is very simple.Try these:-
holder.tv_broadcast_title.text=broadList[position].name
where broadlist is my array list created in the adapter itself.In this list the json data is getting stored from api.
internal var broadList = ArrayList<Model>()
and .name is the name of key to fetch name from json data.
holder.categoryName.text = itemCategory.name?.get("En").toString()
in your case do something like this:-
itemCategory[position].name
To get data from adapter to activity, you can make an interface in the adapter or globally and from the activity you can pass that interface in adapter's constructor and use that to get data. I am giving you an example.
interface ProductCategoryListner {
fun getProductCategory(viewModel:ProductCategoryData)
}
Not in adapter's constructor add this interface.
class CategoryAdapter(private val categories: Array<ProductCategoryData>,private val productCategoryListner: ProductCategoryListner):
RecyclerView.Adapter<CategoryAdapter.ViewHolder>(), View.OnClickListener {
Now you can use this to pass data in the activity when you click on view.
productCategoryListner.getProductCategory(categories[adapterPosition])

Categories

Resources