繁体   English   中英

如何将片段上下文传递给适配器?

[英]How can I pass the fragment context to the adapter?

我正在做一个项目,现在坚持了 3 天。 该项目使用适配器和片段读取 json。

json: https ://opendata.visitflanders.org/accessibility/activities/sport_v2.json

fragment_list_of_sports.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".ListOfSportsFragment">

    <!-- TODO: Update blank fragment layout -->


    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="List of sports and locations"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.022" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rvSportList"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <Button
        android:id="@+id/btnBack"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Back"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.049"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.976" />
</androidx.constraintlayout.widget.ConstraintLayout>

ListOfSportsFragment.kt:

package vives.be.bedoerikproject

import SportsAdapter
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.get
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.fragment_list_of_sports.*
import kotlinx.android.synthetic.main.fragment_list_of_sports.view.*
import org.json.JSONException
import org.json.JSONObject

class ListOfSportsFragment : Fragment() {

     override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val view = inflater.inflate(R.layout.fragment_list_of_sports, container, false)

        val sportList: ArrayList<SportModelClass> = ArrayList()

        try {
            // As we have JSON object, so we are getting the object
            //Here we are calling a Method which is returning the JSON object
            val obj = JSONObject("Sports.json")
            // fetch JSONArray named users by using getJSONArray
            val sportsArray = obj.getJSONArray("sports")
            // Get the users data using for loop i.e. id, name, email and so on

            for (i in 0 until sportsArray.length()) {
                // Create a JSONObject for fetching single User's Data
                val sport = sportsArray.getJSONObject(i)
                // Fetch id store it in variable
                val id = sport.getInt("business_product_id")
                val name = sport.getString("name")
                val city_name = sport.getString("city_name")
                val postal_code = sport.getInt("postal_code")
                val website = sport.getString("website")
                val phone = sport.getString("phone1")
                val email = sport.getString("email")

                // Now add all the variables to the data model class and the data model class to the array list.
                val sportDetails =
                    SportModelClass(id, name, postal_code, city_name, phone, email, website)

                // add the details in the list
                sportList.add(sportDetails)
            }
        } catch (e: JSONException) {
            //exception
            e.printStackTrace()
        }

       // Set the LayoutManager that this RecyclerView will use.
        rvSportList.layoutManager = LinearLayoutManager(activity) //rv = reciycleview
        // Adapter class is initialized and list is passed in the param.
        val itemAdapter = SportsAdapter(requireContext(), sportList)
        // adapter instance is set to the recyclerview to inflate the items.
        rvSportList.adapter = itemAdapter

        return view
    }
}

运动适配器:

import vives.be.bedoerikproject.SportModelClass
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import vives.be.bedoerikproject.R
import kotlinx.android.synthetic.main.sport_model_layout.view.*

class SportsAdapter(val context: Context, val items: ArrayList<SportModelClass>) :
    RecyclerView.Adapter<SportsAdapter.ViewHolder>() {
    /**
     * Inflates the item views which is designed in xml layout file
     *
     * create a new
     * {@link ViewHolder} and initializes some private fields to be used by RecyclerView.
     */
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(
            LayoutInflater.from(context).inflate(
                R.layout.sport_model_layout,
                parent,
                false
            )
        )
    }

    /**
     * Binds each item in the ArrayList to a view
     *
     * Called when RecyclerView needs a new {@link ViewHolder} of the given type to represent
     * an item.
     *
     * This new ViewHolder should be constructed with a new View that can represent the items
     * of the given type. You can either create a new View manually or inflate it from an XML
     * layout file.
     */
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {

        val item = items.get(position)
        holder.name.text = item.name
        holder.city_name.text = item.city_name
        holder.postal_code.text = item.postal_code.toString()
        holder.website.text = item.website
        holder.phone1.text = item.phone1
        holder.email.text = item.email
    }

    /**
     * Gets the number of items in the list
     */
    override fun getItemCount(): Int {
        return items.size
    }

    /**
     * A ViewHolder describes an item view and metadata about its place within the RecyclerView.
     */
    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        // Holds the TextView that will add each item to
        val name = view.name
        val city_name = view.city_name
        val postal_code = view.postal_code
        val website = view.website
        val phone1 = view.phone1
        val email = view.email
    }
}

SportModelClass.kt:

package vives.be.bedoerikproject

class SportModelClass (
    val business_product_id : Int,
    val name : String,
    val postal_code : Int,
    val city_name : String,
    val phone1 : String,
    val email : String,
    val website : String
    )

我在第 60 行的 ListOfSportsFragment 中收到一个错误: E/AndroidRuntime: FATAL EXCEPTION: main Process: vives.be.bedoerikproject, PID: 7302 java.lang.NullPointerException: Attempt to invoke virtual method 'androidx.recyclerview.widget.RecyclerView$LayoutManager androidx.recyclerview.widget.RecyclerView.getLayoutManager()' on a null object reference at vives.be.bedoerikproject.ListOfSportsFragment.onCreateView(ListOfSportsFragment.kt:60) at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2995) at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:523) at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:261) at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1840) at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1764) at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1701) at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:488) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7656) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) Disconnected from the target VM, address: 'localhost:52495', transport: 'socket' E/AndroidRuntime: FATAL EXCEPTION: main Process: vives.be.bedoerikproject, PID: 7302 java.lang.NullPointerException: Attempt to invoke virtual method 'androidx.recyclerview.widget.RecyclerView$LayoutManager androidx.recyclerview.widget.RecyclerView.getLayoutManager()' on a null object reference at vives.be.bedoerikproject.ListOfSportsFragment.onCreateView(ListOfSportsFragment.kt:60) at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2995) at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:523) at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:261) at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1840) at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1764) at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1701) at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:488) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7656) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) Disconnected from the target VM, address: 'localhost:52495', transport: 'socket'

您可以在 xml 文件中设置布局管理器。

...
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/rvSportList"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"/>
...

而且您不必将上下文传递给您的适配器,您可以像这样在 onCreateViewHolder 中访问上下文

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    return ViewHolder(
        LayoutInflater.from(parent.context).inflate(
            R.layout.sport_model_layout,
            parent,
            false
        )
    )
}

像这样使用 requireActivity() :

 rvSportList.layoutManager = LinearLayoutManager(requireActivity())

您能否尝试将代码从 onCreateView 移动到片段上的 onViewCreated fun 并使用“context”而不是“requireContext()”。 希望它有帮助。

只有在片段onCreateView()返回后,您才能像这样使用合成视图绑定。

使用诸如rvSportList.layoutManager = LinearLayoutManager(activity) //rv = reciycleview类的合成方法将视图设置代码移动到例如onViewCreated()

另外值得注意的是,提供合成视图绑定的 kotlin-android-extensions 插件已被弃用。 考虑改用视图绑定

这是你的错误:

java.lang.NullPointerException: Attempt to invoke virtual method
'androidx.recyclerview.widget.RecyclerView$LayoutManager
androidx.recyclerview.widget.RecyclerView.getLayoutManager()'
on a null object reference at
vives.be.bedoerikproject.ListOfSportsFragment.onCreateView(ListOfSportsFragment.kt:60)

它试图在应该RecyclerView的东西上调用方法( getLayoutManager() ),但它不是 - 它是空的。 不能在空对象上调用方法,所以你得到NullPointerException

这是第 60 行,日志告诉您正在发生错误:

rvSportList.layoutManager = LinearLayoutManager(activity) //rv = reciycleview

因此,如果问题是在 null RecyclerView上调用方法,并且它发生在该行上,那么rvSportList不是RecyclerView ,它是null


您从您正在使用的 Kotlin 综合扩展中获得了神奇的rvSportList变量,该扩展已被弃用了很长时间。 您应该改用View Binding - 但与此同时,试试这个 - 查找视图的基本方法:

val rvSportList = view.findViewById<RecyclerView>(R.id.rvSportList)
rvSportList.layoutManager = LinearLayoutManager(requireContext())
// etc

您能否尝试将代码从 onCreateView 移动到片段上的 onViewCreated fun 并使用“上下文”

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM