尽管已经声明了文本,但 TextView 出现空错误

Posted

技术标签:

【中文标题】尽管已经声明了文本,但 TextView 出现空错误【英文标题】:TextView null error despite text already declared 【发布时间】:2019-05-17 03:23:36 【问题描述】:

我试图在我的RecyclerView 中显示Strings 的数组,但即使如此,我也会遇到与空值相关的错误。我已经扫描了代码,但我看不出我做错了什么。在部署过程中,logcat 返回此错误:

txtTitle 不能为空

class MyFragment : androidx.fragment.app.Fragment() 
    private val ITEMTYPE = 100
    private val HEADERTYPE = 101
    private val INFOTYPE = 102

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? 
        return inflater.inflate(R.layout.fragment_rv, container, false)
    

    private lateinit var mRecyclerView: RecyclerView
    private lateinit var dataTitle: ArrayList<CharSequence>
    private lateinit var dataRating: ArrayList<String>
    private lateinit var dataDescription: ArrayList<String>
    private lateinit var mAdapter: RecyclerView.Adapter<com.companyname.appname.MyFragment.ViewHolder>

    override fun onActivityCreated(savedInstanceState: Bundle?) 
        val v = view

        mRecyclerView = v!!.findViewById(R.id.my_recyclerview)

        // set the linear layout manager
        mRecyclerView.layoutManager = LinearLayoutManager(activity, RecyclerView.VERTICAL, false)

        // SpannableStrings
        // dynamically change SpannableString colour using defined attribute
        val attrS = intArrayOf(R.attr.spannablestringtextColor)
        val ta = activity!!.theme.obtainStyledAttributes(attrS)
        val colorSS = ta.getColor(0, Color.BLACK) //Color.BLACK - default value (colour will change automatically depending on chosen theme)
        ta.recycle()


        // SpannableString (start)
        val ssb1 = SpannableStringBuilder()

        val str1a = SpannableString(getString(R.string.placeholder1_placeholder2_placeholder3,
                " ", getString(R.string.product_a), " "))
        str1a.setSpan(BackgroundColorSpan(Color.BLACK), 0, str1a.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
        str1a.setSpan(ForegroundColorSpan(ContextCompat.getColor(context!!, R.color.green)), 0, str1a.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
        ssb1.append(str1a)

        val str1b = SpannableString(" " + getString(R.string.producta_feature))
        str1b.setSpan(ForegroundColorSpan(colorSS), 0, str1b.length, 0)
        ssb1.append(str1b)
        // SpannableString (end)


        // init data
        dataTitle = ArrayList()
        dataTitle.add(ssbA)
        dataTitle.add(getString(R.string.title_b))

        dataRating = ArrayList()
        dataRating.add(getString(R.string.rating_a))
        dataRating.add(getString(R.string.rating_b))

        dataDescription = ArrayList()
        dataDescription.add(getString(R.string.description_a))
        dataDescription.add(getString(R.string.description_b))


        // create the adapter
        mAdapter = createAdapter()

        // set the adapter
        mRecyclerView.adapter = mAdapter

        super.onActivityCreated(savedInstanceState)
    

    private fun createAdapter(): RecyclerView.Adapter<com.companyname.appname.MyFragment.ViewHolder> 
        return object : RecyclerView.Adapter<com.companyname.appname.MyFragment.ViewHolder>() 
            override fun onCreateViewHolder(parent: ViewGroup, type: Int): com.companyname.appname.MyFragment.ViewHolder 
                return when (type) 
                    HEADERTYPE -> com.companyname.appname.MyFragment.ViewHolder(inflateHelper(R.layout.rv_header, parent))

                    INFOTYPE -> com.companyname.appname.MyFragment.ViewHolder(inflateHelper(R.layout.rv_info, parent))

                    ITEMTYPE -> com.companyname.appname.MyFragment.ViewHolder(inflateHelper(R.layout.rv_item, parent))

                    else -> com.companyname.appname.MyFragment.ViewHolder(inflateHelper(R.layout.rv_item, parent))
                
            

            override fun onBindViewHolder(viewHolder: com.companyname.appname.MyFragment.ViewHolder, position: Int) 
                val rlProductInformation = viewHolder.itemView.findViewById<RelativeLayout>(R.id.rl_product_information)

                when (getItemViewType(position)) 
                    HEADERTYPE -> 
                        val buyButton = viewHolder.itemView.findViewById<Button>(R.id.buy_product)
                        buyButton.setText(R.string.buy)
                    
                    INTROTYPE -> 
                        val tvIntroA = viewHolder.itemView.findViewById<TextView>(R.id.tv_product_intro_A)

                        val tvIntroB = viewHolder.itemView.findViewById<TextView>(R.id.tv_product_intro_B)
                    
                    ITEMTYPE -> 
                        val itemA = dataTitle[position]
                        val itemB = dataRating[position]
                        val itemC = dataDescription[position]

                        viewHolder.tvTitle.text = itemA
                        viewHolder.tvSubtitle.text = itemB
                        viewHolder.tvDescription.text = itemC
                    
                
            

            override fun getItemCount(): Int 
                return dataTitle.size + 2
            

            override fun getItemViewType(position: Int): Int 
                return when (position) 
                    0 -> HEADERTYPE
                    else -> ITEMTYPE
                
            
        
    

    private fun inflateHelper(resId: Int, parent: ViewGroup): View 
        return LayoutInflater.from(activity).inflate(resId, parent, false)
    

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
    internal class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) 
        var tvTitle: TextView = itemView.findViewById(R.id.tv_product_title) as TextView
        var tvSubtitle: TextView = itemView.findViewById(R.id.tv_product_rating) as TextView
        var tvDescription: TextView = itemView.findViewById(R.id.tv_product_description) as TextView

        init 
            tvTitle; tvSubtitle; tvDescription
        
    

RecyclerView XML

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linearLayout_recyclerView"
    android:orientation="vertical"
    android:layout_
    android:layout_>

    <androidx.recyclerview.widget.RecyclerView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/my_recyclerview"
        android:clipToPadding="false"
        android:layout_
        android:layout_
        android:scrollbars="vertical"
        android:scrollbarSize="3dp">
    </androidx.recyclerview.widget.RecyclerView>
</LinearLayout>

RecyclerView 项目 XML

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cv_product"
    android:layout_
    android:layout_
    app:contentPadding="16dp"
    android:layout_marginBottom="30dp">

    <LinearLayout
        android:id="@+id/ll_cv_product"
        android:layout_
        android:layout_
        android:orientation="vertical">


        <LinearLayout
            android:id="@+id/cv_product_title"
            android:layout_
            android:layout_
            android:orientation="horizontal"
            android:layout_marginBottom="2dp">

            <TextView
                android:id="@+id/tv_product_title"
                android:layout_
                android:layout_
                style="@android:style/TextAppearance.Large" />
        </LinearLayout>

        <RelativeLayout
            android:id="@+id/rl_product_information"
            android:layout_
            android:layout_>

            <TextView
                android:id="@+id/tv_product_new"
                android:layout_
                android:layout_
                android:text="@string/board"
                android:textColor="?android:attr/textColorPrimary"
                style="@android:style/TextAppearance.Large"
                android:layout_below="@+id/cv_product_title"/>

            <TextView
                android:id="@+id/tv_product_rating"
                android:layout_
                android:layout_
                android:layout_marginStart="10dp"
                android:textColor="?android:attr/textColorPrimary"
                style="@android:style/TextAppearance.Large"
                android:layout_below="@+id/cv_product_title"
                android:layout_toEndOf="@+id/tv_product_new" />

            <TextView
                android:id="@+id/tv_product_description"
                android:layout_
                android:layout_
                android:textColor="?android:attr/textColorPrimary"
                style="@android:style/TextAppearance.Medium"
                android:layout_below="@+id/tv_product_rating" />
        </RelativeLayout>
    </LinearLayout>
</androidx.cardview.widget.CardView>

【问题讨论】:

【参考方案1】:

您应该将 RecyclerView 初始化代码放在 onViewCreated 中。代码很难阅读,但错误表明 tv_product_title 是在项目的相应布局 xml 中定义的。

【讨论】:

你的意思是所有与RecyclerView相关的代码吗? 是的,那么您在方法参数列表中就有了视图。但是没有找到 TextView 的主要问题。也许您有多个用于不同 API 级别的文件。或者你拼错了 id.. 可以在这里添加xml吗? 是androidx没关系。我无法发现您的问题,但令人怀疑的是为什么您在卡片视图和线性布局“@+id/cv_product”中具有相同的 ID。在 Kotlin 中不需要 find view by id 的另一个一般性评论。通常,当您有不同的视图类型和 xml 时,请为它们使用不同的视图持有者。 TextView 应该在 ViewHolder 类中膨胀,而不是在 onBindViewHolder 中。当您需要节省内存时,这样做的方式会破坏 recyclerview 的所有目的。 我修复了重复 ID 问题。不幸的是,我还没有看到在 ViewHolder 类中为 TextView 充气的 Kotlin 教程。我一直致力于节省内存。

以上是关于尽管已经声明了文本,但 TextView 出现空错误的主要内容,如果未能解决你的问题,请参考以下文章

如何在不同的屏幕尺寸和密度下保持 TextView 中的文本大小一致?

Android:隐藏自定义TextView的文本

SQLite 片段函数实现不会在 TextView 中将文本格式化为 HTML

如何在具有动态高度的文本视图中显示 html?

Android 实现视图文本TextView的展开与收缩功能

尽管声明了属性,但 href 标记的高度为 0