-1

I'm using Kotlin with SDK version 29. I searched on several sites but I did not find anything on this subject. I would like to use a recyclerview in my fragment using an adapter, but there is an error that i cannot resolve about my adapter.

Here is the error :

Type mismatch: inferred type is Flux but Context was expected

It is from the next line in the fragment :

adapter = PostsAdapter(this, posts)

Do you know how to set a context ?

There is my code :

The adapter :

Import :

import android.content.Context 
import android.text.format.DateUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.example.givenaskv1.R
import kotlinx.android.synthetic.main.item_post.view.*

Code:

class PostsAdapter (val context: Context, val posts : List<Post>) :
    RecyclerView.Adapter<PostsAdapter.ViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(context).inflate(R.layout.item_post, parent, false)
        return ViewHolder(view)
    }

    override fun getItemCount() = posts.size
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(posts[position])
    }

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(post: Post) {
            itemView.tvUsername.text = post.user?.firstName
            itemView.tvDescription.text = post.description
            Glide.with(context).load(post.imageUrl).into(itemView.ivPost)
            itemView.tvRelativeTime.text = DateUtils.getRelativeTimeSpanString(post.creationTimeMs)
        }
    }
}
 

The fragment :

Import :

import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.givenaskv1.R
import com.example.givenaskv1.models.Post
import com.example.givenaskv1.models.PostsAdapter
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.Query
import kotlinx.android.synthetic.main.fragment_flux.*

Code :

private const val TAG = "Flux"
class Flux : Fragment() {

    private lateinit var firestoreDb : FirebaseFirestore
    private lateinit var posts : MutableList<Post>
    private lateinit var adapter: PostsAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)


    posts = mutableListOf()
    adapter = PostsAdapter(this, posts)  <----- HERE IS THE ERROR
    rvPosts.adapter = adapter
    rvPosts.layoutManager = LinearLayoutManager(this.context)


    firestoreDb = FirebaseFirestore.getInstance()
    val postsReference = firestoreDb.collection("post")
        // .limit() indique le nombre de post MAXIMIM a afficher en même temps, pour éviter le lagg
        .limit(20)
        // .orderBy() filtre selon le critère choisi (ici par ordre chonologique)
        .orderBy("creation_time_ms", Query.Direction.DESCENDING)

    postsReference.addSnapshotListener{ snapshot, exception ->

        if (exception != null || snapshot == null) {
            Log.e(TAG, "Exception when querying posts", exception)
            return@addSnapshotListener
        }
        val postList = snapshot.toObjects(Post::class.java)
        posts.clear()
        posts.addAll(postList)
        adapter.notifyDataSetChanged()

        for (post in postList) {
            Log.i(TAG, "Post ${post}")
        }
    }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_flux, container, false)
    }
}

fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
    tools:context=".Flux.Flux">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rvPosts"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

when i try to replace

adapter = PostsAdapter(this, posts)

with

adapter = PostsAdapter(requireContext(), posts)

There is the following error :

java.lang.IllegalStateException: rvPosts must not be null

Thank you so much !

Yam Re
  • 25
  • 7
  • You need to replace `adapter = PostsAdapter(this, posts)` with `adapter = PostsAdapter(requireContext(), posts)` – Zain Apr 26 '21 at 00:25
  • @Zain When I try this there is the following error : java.lang.IllegalStateException: rvPosts must not be null Maybe because it's a fragment ? – Yam Re Apr 26 '21 at 00:31
  • That null error is because the view is set up in onCreateView, after onCreate is done. That's also a separate issue to this one. – Ryan M Apr 26 '21 at 03:30

1 Answers1

-1

This is due that you get the RecyclerView instance in the fragment onCreate callback before the fragment view get created; As onCreate() callback is triggered before onCreateView() callback

Note: the fragment view is get created and returned by onCreateView().

To solve this transfer the code from onCreate() into onCreateView()

private const val TAG = "Flux"
class Flux : Fragment() {

    private lateinit var firestoreDb : FirebaseFirestore
    private lateinit var posts : MutableList<Post>
    private lateinit var adapter: PostsAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment

        val view = inflater.inflate(R.layout.fragment_flux, container, false)

        posts = mutableListOf()
        adapter = PostsAdapter(requireContext(), posts) 
        
        val rvPosts = view.findViewById<RecyclerView>(R.id.rvPosts)
        rvPosts.adapter = adapter
        rvPosts.layoutManager = LinearLayoutManager(this.context)


        firestoreDb = FirebaseFirestore.getInstance()
        val postsReference = firestoreDb.collection("post")
            // .limit() indique le nombre de post MAXIMIM a afficher en même temps, pour éviter le lagg
            .limit(20)
            // .orderBy() filtre selon le critère choisi (ici par ordre chonologique)
            .orderBy("creation_time_ms", Query.Direction.DESCENDING)

        postsReference.addSnapshotListener{ snapshot, exception ->

        if (exception != null || snapshot == null) {
            Log.e(TAG, "Exception when querying posts", exception)
            return@addSnapshotListener
        }
        val postList = snapshot.toObjects(Post::class.java)
        posts.clear()
        posts.addAll(postList)
        adapter.notifyDataSetChanged()

        for (post in postList) {
            Log.i(TAG, "Post ${post}")
        }
        return view
    }
}
Zain
  • 37,492
  • 7
  • 60
  • 84
  • thank you ! Now the fragment is open but nothng appear Except a new error : E/RecyclerView: No adapter attached; skipping layout , do you know how to solve it ? Thank you again – Yam Re Apr 26 '21 at 01:51
  • This is another error that you may open a new question for :) – Zain Apr 26 '21 at 02:34
  • Yes I will, thank you a lot Zain ! – Yam Re Apr 26 '21 at 02:44