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

r7knjye2  于 2022-11-14  发布在  Android
关注(0)|答案(5)|浏览(164)

我正在做一个项目,现在在这上面坚持了3天。这个项目读取了一个JSON,使用了一个适配器,还有碎片。
json:https://opendata.visitflanders.org/accessibility/activities/sport_v2.json的子目录
运动项目片段列表.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
    )

我在ListOfSportsFragment的第60行看到一个错误,这个错误是: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'

x33g5p2x

x33g5p2x1#

您可以在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
        )
    )
}
hc8w905p

hc8w905p2#

你能试着把你的代码从onCreateView移到onViewCreated fun并使用'context'而不是'requireContext()'吗?希望能帮上忙。

tcomlyy6

tcomlyy63#

按如下方式使用requireActivity():

rvSportList.layoutManager = LinearLayoutManager(requireActivity())
vwoqyblh

vwoqyblh4#

只有在片段onCreateView()返回后,才能像这样使用合成视图绑定。
使用合成代码(如rvSportList.layoutManager = LinearLayoutManager(activity) //rv = reciycleview)将视图设置代码移动到onViewCreated()
另外值得注意的是,提供合成视图绑定的kotlin-android-extensions插件已被弃用,请考虑改用view binding

ruarlubt

ruarlubt5#

这是您的错误:

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)

它试图调用一个方法(getLayoutManager()),但是它不是RecyclerView,它是null。不能调用null对象上的方法,所以你得到NullPointerException
这是第60行,其中日志告诉您发生了错误:

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

所以如果问题是在一个空的RecyclerView上调用方法,并且它发生在那一行,那么rvSportList就不是RecyclerView,它是 null
您将从Kotlin合成扩展中获得神奇的rvSportList变量,该扩展已经被弃用很长时间了。您应该使用View Binding来代替-但同时,请尝试以下方法-找到视图的基本方法:

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

相关问题