bas
bas

Reputation: 15722

Android Kotlin Recyclerview inside fragment is null

I can't get my Recycleview inside my fragment to work. I've tried moving the recyclerview adapter and layout code to onViewCreated but that didn't work either.

Does anybody have an idea to what the problem could be?

Main Activity

...
 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(toolbar)
        loadFragment(NewsFragment()) // Show the news fragment by default
        initBottomNavigation()
}
...
private fun loadFragment(fragment: Fragment) {
        val transaction = supportFragmentManager.beginTransaction()
        transaction.replace(R.id.fragment_container, fragment)
        transaction.addToBackStack(null)
        transaction.commit()
}
...

NewsAdapter

class NewsAdapter(private val newsItems: List<NewsItem>) :
    RecyclerView.Adapter<NewsAdapter.ViewHolder>() {

    private lateinit var context: Context

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        context = parent.context

        return ViewHolder(
            LayoutInflater.from(context).inflate(R.layout.news_list_item, parent, false)
        )
    }

    override fun getItemCount(): Int = newsItems.size

    override fun onBindViewHolder(holder: ViewHolder, position: Int) =
        holder.bind(newsItems[position])

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        fun bind(newsItem: NewsItem) {

        }
    }
}

fragment_news.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
    tools:context=".NewsFragment">

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

        <include
            layout="@layout/news_list_item"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </androidx.recyclerview.widget.RecyclerView>

</FrameLayout>

NewsFragment

class NewsFragment : Fragment() {

    private val newsItems = arrayListOf<NewsItem>()
    private val newsAdapter = NewsAdapter(newsItems)

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        if (container != null) {
            container.rootView.rvNewsItems.layoutManager =
                LinearLayoutManager(context, RecyclerView.VERTICAL, false)
            container.rootView.rvNewsItems.adapter = newsAdapter
        }

        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_news, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        btnLike.setOnClickListener {
            val color = ResourcesCompat.getColor(resources, R.color.colorPrimary, null);
            btnLike.setColorFilter(color)
        }
    }

}

build.gradle

apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "com.example.johanvanderlindenapp"
        minSdkVersion 21
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.core:core-ktx:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

    //Navigation
    implementation "androidx.navigation:navigation-fragment-ktx:2.1.0"
    implementation "androidx.navigation:navigation-ui-ktx:2.1.0"

    // Material widgets
    implementation "com.google.android.material:material:1.0.0"

    // ViewModel and LiveData
    def lifecycle_version = "2.1.0"
    implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"

    implementation 'androidx.recyclerview:recyclerview:1.1.0'
}

EDIT I have removed the include inside the recycleview shown above, still receive the error.

Upvotes: 0

Views: 541

Answers (3)

bas
bas

Reputation: 15722

Using vindViewById instead of synthetic turned out to solve the problem.

My news fragment now looks like this:

class NewsFragment : Fragment() {

    private val newsItems = arrayListOf<NewsItem>()
    private val newsAdapter = NewsAdapter(newsItems)

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        val view = inflater.inflate(R.layout.fragment_news, container, false)
        val rvNewsItems = view.findViewById(R.id.rvNewsItems) as RecyclerView

        rvNewsItems.layoutManager = LinearLayoutManager(context)
        rvNewsItems.adapter = newsAdapter

        return view
    }

}

Upvotes: 1

Christilyn Arjona
Christilyn Arjona

Reputation: 2283

You cannot use the <include /> tag to show your list items. Your ViewHolder class takes care of instantiating your list items for you. Simply remove the include tag in your fragment_news.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
    tools:context=".NewsFragment">

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

    </androidx.recyclerview.widget.RecyclerView>

</FrameLayout>

Also, make sure your newsItems is not empty. Otherwise, it will show you an empty view. If you wish to add items to your newsItems, don't forget to call notifyDataSetChanged() in your adapter to reflect the changes.

Upvotes: 0

enderkoca
enderkoca

Reputation: 146

Try this

    <FrameLayout 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"
    tools:context=".NewsFragment">

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/rvNewsItems"
    android:scrollbars="vertical"
    android:layout_width="match_parent"
    android:orientation="vertical"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
    android:layout_height="match_parent" >

</androidx.recyclerview.widget.RecyclerView>





class NewsFragment : Fragment() {

    private val newsItems = arrayListOf<NewsItem>()
    private val newsAdapter : NewsAdapter? = null

    override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?): View? {

        container.rootView.rvNewsItems.adapter = newsAdapter
        container.rootView.rvNewsItems.adapter as NewsAdapter).submitList(newsItems)

    }

    // Inflate the layout for this fragment
    return inflater.inflate(R.layout.fragment_news, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    btnLike.setOnClickListener {
        val color = ResourcesCompat.getColor(resources, R.color.colorPrimary, null);
        btnLike.setColorFilter(color)
    }
}

Upvotes: 0

Related Questions