i want to get recyclerview in my homefragment end set into elements from firestore firebase
my problem with get elements from firestore! maybe whos know how to search a problem because elements doesnt come frome firestore!
HomeFragment
class HomeFragment : Fragment() {
private val TAG = "HomeFragment"
private val firebaseRepository: FirebaseNoteRepo = FirebaseNoteRepo()
private var noteList: List<NotesModel> = ArrayList()
private val notesListAdapter: NotesListAdapterClass = NotesListAdapterClass(noteList)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_home, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
init(view)
}
private fun init(view: View) {
if(firebaseRepository.getUser() == null){
Log.d(TAG,"Error log user")
}else{ loadNotesData()}
note_list_recycler_view.layoutManager = LinearLayoutManager(context)
note_list_recycler_view.adapter = notesListAdapter
add_note_fab.setOnClickListener {
noteCreateDialog(view)
}
}
private fun loadNotesData() {
firebaseRepository.getNoteList().addOnCompleteListener {
if (it.isSuccessful){
noteList = it.result!!.toObjects(NotesModel::class.java)
notesListAdapter.notesListItem = noteList
notesListAdapter.notifyDataSetChanged()
}else{
Log.d(TAG,"Error: ${it.exception!!.message}")
}
}
}
my NotesModel
data class NotesModel(
val title: String = "",
val date: com.google.firebase.Timestamp? = null,
val post_type: Long = 0
)
my repository
FirebaseNoreRepo
class FirebaseNoteRepo {
private val firebaseAuth: FirebaseAuth = FirebaseAuth.getInstance()
private val firebaseFirestore: FirebaseFirestore = FirebaseFirestore.getInstance()
fun getUser(): FirebaseUser? {
return firebaseAuth.currentUser
}
fun getNoteList(): Task<QuerySnapshot> {
Log.d("HomeFragment"," ad "+ firebaseFirestore.collection("Notes").get().toString())
return firebaseFirestore
.collection("Notes")
.orderBy("title", Query.Direction.ASCENDING)
.get()
}
and my adapter
class NotesListAdapterClass (var notesListItem: List<NotesModel>):
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.note_layout,parent,false)
return ViewHolderNotes(view)
}
override fun getItemViewType(position: Int): Int {
return if (notesListItem[position].post_type == 1L){
POST_TYPE1
}else{
POST_TYPE1
}
}
override fun getItemCount(): Int {
Log.d("HomeFragment","notesListAdapter size : "+notesListItem.size)
return notesListItem.size
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (getItemViewType(position) == POST_TYPE1){
(holder as ViewHolderNotes).bind(notesListItem[position])
}
}
class ViewHolderNotes(itemView: View):RecyclerView.ViewHolder(itemView){
fun bind(notesModel: NotesModel){
itemView.note_title.text = notesModel.title
}
}
}
in my adapter i have Log.d he say me size of list of item ( is always equal 0), in firestore i have 2 elements. i dont understand why in log i have 0!
Database sceenshot
Related
I am trying to get data in recyclerview of fragment from realtime database.
Here is the code of Home Fragment I used to get data from realtime database:-
class HomeFragments : Fragment() {
private var recyclerView: RecyclerView? = null
private var typesAdapter: SU_Types_adapter? = null
private var type: MutableList<SU_Type_Model>? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
recyclerView = rv_home_fragment
recyclerView?.setHasFixedSize(true)
recyclerView?.layoutManager = GridLayoutManager(activity, 2)
type = ArrayList()
typesAdapter = activity?.let { SU_Types_adapter(it, type as ArrayList<SU_Type_Model>, true) }
recyclerView?.adapter = typesAdapter
val typesRef = FirebaseDatabase.getInstance().getReference().child("SU_Types").orderByChild("type")
typesRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (snapshot in dataSnapshot.children) {
typesAdapter?.notifyDataSetChanged()
val su_type = snapshot.getValue(SU_Type_Model::class.java)
if (su_type != null) {
(type as ArrayList<SU_Type_Model>)?.add(su_type)
}
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_home_fragments, container, false)
}
}
Here is the adapter code that I use to get the database data:-
class SU_Types_adapter(
private var mContext: Context,
private var mTypes: List<SU_Type_Model>,
private var isActivity: Boolean = false
) : RecyclerView.Adapter<SU_Types_adapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view =
LayoutInflater.from(mContext).inflate(R.layout.rv_home_fragment_adapter, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val su_type = mTypes[position]
Picasso.get().load(su_type.getImageUrl()).into(holder.ImageIv)
holder.ImgId.text = su_type.gettype()
}
override fun getItemCount(): Int {
return mTypes.size
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var ImageIv: ImageView? = itemView.su_type_iv
var ImgId: TextView = itemView.su_type_tv
}
}
Here is the model code:-
class SU_Type_Model {
private var ImageUrl: String = ""
private var type: String = ""
constructor()
constructor(
ImageUrl: String,
type: String
) {
this.ImageUrl = ImageUrl
this.type = type
}
fun getImageUrl(): String {
return ImageUrl
}
fun setImageUrl(ImageUrl: String) {
this.ImageUrl = ImageUrl
}
fun gettype(): String {
return type
}
fun settype(type: String) {
this.type = type
}
}
here is snapshot of [database image.]
json file code is:-
{
"SU_Types": {
"asdfadsfa": {
"ImageUrl": "\"https://firebasestorage.googleapis.com/v0/b/ehi-10.appspot.com/o/Types%2FAdvertising%2F1113-lalbaugcha-raja-wallpaper-07.jpg?alt=media&token=c2d78337-e66b-43cf-bed5-8e65cf94c342\"",
"type": "\"sing\""
}
}
}
I was able to get the data in activity using similar code but I am unable to get the data in Fragment. Can someone please help me?
Instead of activity use context:-
recyclerView?.layoutManager = GridLayoutManager(context, 2)
typesAdapter = context?.let { SU_Types_adapter(it, type as ArrayList<SU_Type_Model>, true) }
and make changes for getting recyclerview:-
recyclerView = view.findViewById(R.id.rv_home_fragment)
I'm using a RecyclerView to show some info from Firebase, with kotlin in Android Studio.
But when I click on the RecyclerView, it return the position as -1, so the page that opens that item is always empty...
This is my code from setOnClickListener on the ViewHolder:
class CustomViewHolder(view: View): RecyclerView.ViewHolder(view){
val titulo = view.findViewById<TextView>(R.id.txtTitle)
val localizacao = view.findViewById<TextView>(R.id.txtDescription)
//val urlPag = view.findViewById<TextView>(R.id.record_amount)
//val descricao = view.findViewById<TextView>(R.id.record_date)
val img = view.findViewById<ImageView>(R.id.imageItem)
init {
view.setOnClickListener{
val position: String = CustomViewHolder(it).bindingAdapterPosition.toString()
val intent = Intent(view.context, NotificationActivity::class.java).apply {
putExtra("id", position)
println(position)
}
view.context.startActivity(intent)
}
}
}
This is the fragment were the recyclerView is:
class InboxFragment : Fragment() {
private var listData: List<Notifications>? = null
private var adapter: MainAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_inbox, container, false)
val rv = view.findViewById<RecyclerView>(R.id.recyclerView)
rv.setHasFixedSize(true)
rv.layoutManager = LinearLayoutManager(context)
listData = ArrayList()
val nm = FirebaseDatabase.getInstance().getReference("notifications")
nm.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
if (dataSnapshot.exists()) {
for (npsnapshot in dataSnapshot.children) {
val l: Notifications? = npsnapshot.getValue(Notifications::class.java)
if (l != null) {
(listData as ArrayList<Notifications>).add(l)
}
}
adapter = MainAdapter(listData)
rv.adapter = adapter
}
}
override fun onCancelled(databaseError: DatabaseError) {}
})
return view
}
}
This is the adapter:
class MainAdapter(var listData: List<Notifications>?) : RecyclerView.Adapter<CustomViewHolder>(){
override fun getItemCount(): Int {
return listData!!.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder {
//create view
val layoutInflater = LayoutInflater.from(parent.context)
val cellForRow = layoutInflater.inflate(R.layout.inforow, parent, false)
return CustomViewHolder(cellForRow)
}
override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
val ld: Notifications = listData!![position]
holder.titulo.text = ld.titulo
holder.localizacao.text = ld.localizacao
Picasso.get().load(ld.img).into(holder.img)
}
}
Can someone please help?
This question has been asked multiple times, but the proposed solutions do not function in my specific case.
When the onProjectImageViewClick function is executed I receive the following error:
java.lang.IllegalStateException: Fragment HomeFragment{191080d} (9545b64c-bf0a-4464-8a71-b8c474526181)} not associated with a fragment manager.
One of the proposed solutions was to use the code below to navigate, but since my fragment is detached I can't navigate to the other fragment.
view?.post {
findNavController().navigate(R.id.fragment_project_info)
}
Also, when I troubleshoot using println(Homefragment().isAdded), it returns false, therefore I can't use the solution written above.
Before implementing the firebase database (only using placeholders for my recyclerview), I could navigate to my fragment_project_info.
My Fragment:
class HomeFragment : Fragment(), HomeProjectListAdapter.OnItemClickListener {
private lateinit var auth: FirebaseAuth
private lateinit var databaseReference: DatabaseReference
lateinit var listener: ValueEventListener
var recentPostRef = FirebaseDatabase.getInstance().getReference("projects").limitToLast(50)
val TAG = "loadPostData Result"
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_home, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
auth = Firebase.auth
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
postQueryValueListener()
}
override fun onStart() {
super.onStart()
val currentUser = auth.currentUser
updateUI(currentUser)
}
override fun onProjectImageViewClick(position: Int, projectData: ProjectData) {
findNavController().navigate(R.id.fragment_project_info)
}
private fun updateUI(currentUser: FirebaseUser?){
if(currentUser == null){
upload_button.visibility = View.GONE
projects_button.visibility = View.GONE
}
}
private fun postQueryValueListener() {
listener = recentPostRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (postSnapshot in dataSnapshot.children) {
var list = ArrayList<ProjectData>()
for (dataSnapshot1 in dataSnapshot.children) {
val p: ProjectData? = dataSnapshot1.getValue(ProjectData::class.java)
if (p != null) {
list.add(p)
}
}
var adapter = HomeProjectListAdapter(list, HomeFragment())
recycler_view.adapter = adapter
recycler_view.layoutManager = LinearLayoutManager(context)
recycler_view.hasFixedSize()
}
}
override fun onCancelled(databaseError: DatabaseError) {
Log.w(TAG, "loadPost:onCancelled", databaseError.toException())
}
})
}
override fun onStop() {
super.onStop()
recentPostRef.removeEventListener(listener)
}
}
Here is my adapter:
class HomeProjectListAdapter(
private val projectList: List<ProjectData>,
private val listener: HomeFragment
) : RecyclerView.Adapter<HomeProjectListAdapter.ProjectListViewHolder>() {
val TAG = "loadUserData Result"
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProjectListViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.layout_project_card,
parent, false)
return ProjectListViewHolder(itemView)
}
override fun onBindViewHolder(holder: ProjectListViewHolder, position: Int) {
val currentItem = projectList[position]
Glide.with(holder.projectImageView.context)
.load(currentItem.mainImageURL)
.into(holder.projectImageView)
}
override fun getItemCount() = projectList.size
inner class ProjectListViewHolder(itemView: View): RecyclerView.ViewHolder(itemView),
View.OnClickListener{
var projectImageView: ImageView = itemView.project_card_image
init {
projectImageView.setOnClickListener(this)
}
override fun onClick(v: View?) {
val position = adapterPosition
val projectData: ProjectData = projectList[position]
if (position != RecyclerView.NO_POSITION){
if (v != null) {
if(v.id == R.id.project_card_image) {
listener.onProjectImageViewClick(position, projectData)
}
}
}
}
}
interface OnItemClickListener {
fun onProjectImageViewClick(position: Int, projectData: ProjectData)
}
}
When you run HomeProjectListAdapter(list, HomeFragment()), you're passing in a brand new instance of HomeFragment. That brand new instance is never attached to a FragmentManager.
Instead, you need to pass in your current fragment instance:
var adapter = HomeProjectListAdapter(list, this#HomeFragment)
I use Firebase Realtime Database. I have RecycleViewAdapter class, a Fragment which shows the recycleview, a ViewHolder class which gives data to the fragment (I use LiveData) and there is a Repository class which communicates with the firebase database.
class Post(
var title: String = "",
var dateStr: String = "",
var desc: String = "",
var id: String = "")
class PostsFireBaseRepository(val bucketListViewModel: BucketListViewModel) {
private val path: String = "posts"
init {
initPostsListener()
}
fun getAllPosts() {
var data = mutableListOf<Post>()
FirebaseDatabase.getInstance().reference
.child(FirebaseAuth.getInstance().currentUser?.uid.toString())
.child(path)
.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (ds in dataSnapshot.children) {
val newPost = dataSnapshot.getValue<Post>(Post::class.java)
if (newPost != null) {
data.add(newPost)
}
}
bucketListViewModel.allPosts.value = data
bucketListViewModel.dataChanged()
}
override fun onCancelled(error: DatabaseError) {
}
})
}
class BucketListViewModel() : ViewModel() {
private val repository: PostsFireBaseRepository
var recyclerViewAdapter: BucketListRecyclerViewAdapter? = null
var allPosts: MutableLiveData<MutableList<Post>> = MutableLiveData<MutableList<Post>>()
init {
repository = PostsFireBaseRepository(this)
repository.getAllPosts()
}
fun dataChanged() {
recyclerViewAdapter?.notifyDataSetChanged()
}
}
class BucketListFragment : Fragment(), DatePickerDialogFragment.OnDateSelectedListener,
BucketListRecyclerViewAdapter.PostItemClickListener {
private lateinit var bucketListViewModel: BucketListViewModel
private lateinit var recyclerViewAdapter: BucketListRecyclerViewAdapter
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_bucketlist, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupRecyclerView()
bucketListViewModel = ViewModelProvider(requireActivity()).get(BucketListViewModel::class.java)
bucketListViewModel.allPosts.observe(viewLifecycleOwner) { posts ->
recyclerViewAdapter.addAll(posts)
}
}
BucketListRecyclerViewAdapter
class BucketListRecyclerViewAdapter() : RecyclerView.Adapter<BucketListRecyclerViewAdapter.ViewHolder>() {
interface PostItemClickListener {
fun onItemLongClick(position: Int, view: View, post: Post?): Boolean
fun onItemClick(position: Int, view: View, post: Post?): Boolean
}
private var postList = mutableListOf<Post>()
private var lastDeleted: Post? = null
private var lastDeletedPos: Int? = null
var postClickListener: PostItemClickListener? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.bucketlist_post_row, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val post = postList[holder.adapterPosition]
holder.post = post
holder.tvTitle.text = post.title
holder.tvDesc.text = post.desc
holder.tvRowDate.text = post.dateStr
}
override fun getItemCount() = postList.size
fun addItem(post: Post) {
postList.add(post)
notifyItemInserted(postList.size-1)
}
fun addAll(posts: List<Post>) {
postList.clear()
postList.addAll(posts)
notifyDataSetChanged()
}
In your onDataChange method you will need to inform that adapter that its data is changed, otherwise it won't repaint the UI element. To do this, you call notifyDataSetChanged() on the adapter after you've updated the data source for that adapter.
So something like:
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (ds in dataSnapshot.children) {
val newPost = dataSnapshot.getValue<Post>(Post::class.java)
if (newPost != null) {
data.add(newPost)
}
}
bucketListViewModel.allPosts.value = data
adapter.notifyDataSetChanged();
}
Exactly how to reach the adapter depends on your code. For example, in your case you may have to add a method to the BucketListViewModel that you call from onDataChange and that then calls the adapter.
I am using MVVM with Room persistence and livedata. I am fetching the data from local database and want to show in the form of list in the recyclerView and my recyclerView is not showing anything.
My adapter is like any other regular adapter
RecyclerView Code
class MyInformationAdapter : RecyclerView.Adapter<MyInformationAdapter.ViewHolder>() {
private var myList: List<PersonInformation> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val view = layoutInflater.inflate(R.layout.my_adapter_data, parent, false)
return ViewHolder(view)
}
override fun getItemCount(): Int = myList.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
var myDataClass: PersonInformation = myList[position]
holder.name.text = myDataClass.name
holder.fName.text = myDataClass.fatherName
holder.email.text = myDataClass.email
holder.contact.text = myDataClass.contactNo.toString()
}
fun updateTheState(myList: List<PersonInformation>){
this.myList = myList
notifyDataSetChanged()
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var name: TextView = itemView.findViewById(R.id.yourName)
var fName: TextView = itemView.findViewById(R.id.yourFatherName)
var email: TextView = itemView.findViewById(R.id.yourEmail)
var contact: TextView = itemView.findViewById(R.id.yourContact)
}
}
RecyclerView Activity Code
class FinalActivity : AppCompatActivity() {
private var myDataList : List<PersonInformation> = ArrayList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_final)
setAdapter()
}
private fun setAdapter() {
val adapter = MyInformationAdapter()
val layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager
recyclerView.adapter = adapter
adapter.updateTheState(myDataList)
}
}
*Fragment as a View of MVVM *
class PersonalInformationFragment : Fragment() {
private var viewModel: PersonInformationViewModel? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_personal_information, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
btn.setOnClickListener {
viewModel = ViewModelProviders.of(this)[PersonInformationViewModel::class.java]
viewModel?.getAllData()?.observe(this, Observer {
this.setAllData(it)
})
val intent = Intent(activity, FinalActivity::class.java)
startActivity(intent)
}
}
private fun setAllData(personInformation: List<PersonInformation>) {
val setData = PersonInformation(
name.text.toString(),
fName.text.toString(),
email.text.toString(),
contact.text.toString().toInt()
)
viewModel?.setTheData(setData)
}
}