Когда я использовал onViewCreated во фрагменте, произошла ошибка позднего инициализации

#kotlin #android-recyclerview #fragment

Вопрос:

Существует много ошибок в компоновке ресайклера. В частности, я думаю, что исключение nullpointrexception является самой большой ошибкой. Просмотрев несколько документов, я изменил onCreate в активности фрагмента на onViewCreated, и исключение nullpointrexception было решено. Однако произошла другая ошибка, и ошибка заключалась в том, что экземпляр свойства инициализации был инициализирован с опозданием.

это ошибка

 E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.notei, PID: 21857
kotlin.UninitializedPropertyAccessException: lateinit property instance has not been initialized
    at com.example.myrecyclerview.App$Companion.getInstance(App.kt:7)
    at com.example.myrecyclerview.MyViewHolder.bind(MyViewHolder.kt:40)
    at com.example.myrecyclerview.MyRecyclerAdapter.onBindViewHolder(MyRecyclerAdapter.kt:39)
    at com.example.myrecyclerview.MyRecyclerAdapter.onBindViewHolder(MyRecyclerAdapter.kt:11)
    at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:7254)
    at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:7337)
    at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:6194)
    at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6460)
    at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6300)
    at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6296)
    at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2330)
    at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1631)
    at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1591)
    at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:668)
    at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4309)
    at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:4012)
    at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4578)
    at android.view.View.layout(View.java:20672)
    at android.view.ViewGroup.layout(ViewGroup.java:6194)
    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
    at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
    at android.view.View.layout(View.java:20672)
    at android.view.ViewGroup.layout(ViewGroup.java:6194)
    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
    at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
    at android.view.View.layout(View.java:20672)
    at android.view.ViewGroup.layout(ViewGroup.java:6194)
    at androidx.coordinatorlayout.widget.CoordinatorLayout.layoutChild(CoordinatorLayout.java:1213)
    at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayoutChild(CoordinatorLayout.java:899)
    at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:919)
    at android.view.View.layout(View.java:20672)
    at android.view.ViewGroup.layout(ViewGroup.java:6194)
    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
    at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
    at android.view.View.layout(View.java:20672)
    at android.view.ViewGroup.layout(ViewGroup.java:6194)
    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
    at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
    at android.view.View.layout(View.java:20672)
    at android.view.ViewGroup.layout(ViewGroup.java:6194)
    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
    at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
    at android.view.View.layout(View.java:20672)
    at android.view.ViewGroup.layout(ViewGroup.java:6194)
    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
    at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
    at android.view.View.layout(View.java:20672)
    at android.view.ViewGroup.layout(ViewGroup.java:6194)
    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
    at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
    at com.android.internal.policy.DecorView.onLayout(DecorView.java:753)
    at android.view.View.layout(View.java:20672)
    at android.view.ViewGroup.layout(ViewGroup.java:6194)
    at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2792)
    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2319)
    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1460)
    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7183)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:949)
    at android.view.Choreographer.doCallbacks(Choreographer.java:761)
    at android.view.Choreographer.doFrame(Choreographer.java:696)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:935)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:193)
    at android.app.ActivityThread.main(ActivityThread.java:6669)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
 

и это приложение.kt

 package com.example.myrecyclerview

import android.app.Application

class App: Application() {
    companion object {
        lateinit var instance: App
            private set
    }

    override fun onCreate() {
        super.onCreate()
        instance = this
    }
}
 

а это MyViewHolder.kt

 package com.example.myrecyclerview

import android.util.Log
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.example.notei.R
import kotlinx.android.synthetic.main.layout_recycler_item.view.*

// 커스텀 뷰홀더
class MyViewHolder(itemView: View,
                   recyclerviewInterface: MyRecyclerviewInterface):
                    RecyclerView.ViewHolder(itemView),
                    View.OnClickListener{

    val TAG: String = "로그"

    private val usernameTextView = itemView.user_name_txt
    private val profileImageView = itemView.profile_img

    private var myRecyclerviewInterface: MyRecyclerviewInterface? = null

    //기본 생성자
    init {
        Log.d(TAG, "MyViewHolder - init() called")

        itemView.setOnClickListener(this)
        this.myRecyclerviewInterface = recyclerviewInterface
    }

    //데이터와 뷰를 묶는다.
    fun bind(myModel: MyModel) {
        Log.d(TAG, "MyViewHolder - bind() called")

        // 텍스트뷰와 실제 텍스트 데이터를 묶는다.
        usernameTextView.text = myModel.name

        // 이미지뷰와 실제 이미지 데이터를 묶는다.
        Glide
            .with(App.instance)
            .load(myModel.profileImage)
//            .centerCrop()
            .placeholder(R.mipmap.ic_launcher) //값이 없을 때
            .into(profileImageView)
    }

    override fun onClick(v: View?) {
        Log.d(TAG, "MyViewHolder - onClick() called")
        this.myRecyclerviewInterface?.onItemClicked(adapterPosition)
    }
}
 

and This is MyRecyclerAdapter.kt

 package com.example.myrecyclerview

import android.content.ContentValues.TAG
import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.example.notei.R

class MyRecyclerAdapter(myRecyclerviewInterface: MyRecyclerviewInterface): RecyclerView.Adapter<MyViewHolder>() {

    val TAG: String = "로그"

    private var modelList = ArrayList<MyModel>()

    private var myRecyclerviewInterface: MyRecyclerviewInterface? = null

    // 생성자
    init {
        this.myRecyclerviewInterface = myRecyclerviewInterface
    }

    // 뷰홀더가 생성 되었을때
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {

        // 연결할 레이아웃 설정
        return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.layout_recycler_item, parent, false), this.myRecyclerviewInterface!!)
    }

    // 목록의 아이템 수
    override fun getItemCount(): Int {
        return this.modelList.size
    }

    // 뷰와 뷰홀더가 묶였을 때(재활용되었을 때)
    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        Log.d(TAG, "MyRecyclerAdapter - onBindVIewHolder() called / position: $position")
        holder.bind(this.modelList[position])

    }

    // 외부에서 데이터 넘기기
    fun submitList(modelList: ArrayList<MyModel>) {
        this.modelList = modelList
    }
}
 

and This is Fragment_1.kt

     package com.example.notei


import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.myrecyclerview.MyModel
import com.example.myrecyclerview.MyRecyclerAdapter
import com.example.myrecyclerview.MyRecyclerviewInterface
import kotlinx.android.synthetic.main.activity_home.*
import kotlinx.android.synthetic.main.fragment_1.*


class Fragment_1: Fragment(R.layout.fragment_1), MyRecyclerviewInterface {
    val TAG: String = "로그"

    //데이터 담을 배열
    var modelList = ArrayList<MyModel>()
    private lateinit var myRecyclerAdapter: MyRecyclerAdapter


    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        //recyclerview adapter
        Log.d(TAG, "MainActivity - onCreate() called")

        Log.d(TAG, "MainActivity - 반복문 돌리기 전 this.modelList.size : ${this.modelList.size}")


        // 10번 반복
        for (i in 1..10) {
            val myModel = MyModel(name = "장인수 $i", profileImage = "https://edcan.kr/static/media/EDCAN_LOGO.2b1b47ce.svg")
            this.modelList.add(myModel)
        }

        Log.d(TAG, "MainActivity - 반복문 돌린 후 this.modelList.size : ${this.modelList.size}")

        // 어답터 인스턴스 생성
        myRecyclerAdapter = MyRecyclerAdapter(this)

        myRecyclerAdapter.submitList(this.modelList)


        // 리사이클러뷰 설정
        my_recycler_view.apply {

            // 리사이클러뷰 방향 등 설정
            layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)

            // 어답터 장착
            adapter = myRecyclerAdapter
        }
    }

    override fun onItemClicked(position: Int) {
        Log.d(TAG, "MainActivity - onItemClicked() called / position $position")

        var name: String? = null

        // 값이 비어있으면 ""를 넣는다.
        // unwrapping - 언랩핑

        val title: String = this.modelList[position].name ?: ""
//
//        val title: String = name ?: "ㅎㅎ"

        AlertDialog.Builder(requireContext())
            .setTitle(title)
            .setMessage("$title 의 코딩:")
            .setPositiveButton("오케이") {
                    dialog, id -> Log.d(TAG, "MainActivity - 다이얼로그 확인 버튼 클릭했음")
            }
            .show()
    }
}
 

and This is fragment_1.xml

 <?xml version="1.0" encoding="utf-8"?>

<FrameLayout
    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=".HomeActivity"
    android:orientation="vertical">

    <androidx.recyclerview.widget.RecyclerView
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        android:id="@ id/my_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>
 

and This is layout_recycler_item.xml

     <?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_margin="20dp"
    app:cardCornerRadius="20dp"
    app:cardElevation="20dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="20dp">
        <ImageView
            android:id="@ id/profile_img"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:src="@mipmap/ic_launcher"
            />
        <TextView
            android:id="@ id/user_name_txt"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="장인수"
            android:textSize="30sp"
            android:layout_marginStart="20dp"
            android:layout_gravity="center_vertical"
            />
    </LinearLayout>

</androidx.cardview.widget.CardView>
 

)Для тех, кто в этом нуждается.
приложение/сборка.gradle

 plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-android-extensions' //add
}

apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions' //android 4.1 down:D


android {

    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.example.notei"
        minSdkVersion 21
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }

    viewBinding {
        enabled = true
    }
}

dependencies {
    // firebase add
    implementation platform('com.google.firebase:firebase-bom:28.1.0')
    implementation 'com.google.firebase:firebase-analytics-ktx'
    implementation 'com.google.firebase:firebase-auth:21.0.1'
    implementation 'com.google.firebase:firebase-firestore-ktx:23.0.1'
    implementation 'com.google.firebase:firebase-storage-ktx'


    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"

    implementation 'androidx.core:core-ktx:1.5.0'
    implementation 'androidx.appcompat:appcompat:1.3.0'
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    implementation 'androidx.viewpager2:viewpager2:1.0.0-alpha04' //viewpager2
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'//viewpager2
    implementation 'androidx.recyclerview:recyclerview:1.1.0' //recyclerview
    implementation "android.arch.lifecycle:extensions:1.1.1"
    implementation 'com.google.android.material:material:1.3.0-alpha03' //Material Design
    testImplementation 'junit:junit:4. '

    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'

    // imageView url 사용하기


    implementation 'com.squareup.picasso:picasso:2.71828'

    // 리사이클러뷰
    implementation "androidx.recyclerview:recyclerview:1.2.0" //recyclerView
    implementation "androidx.recyclerview:recyclerview-selection:1.1.0"//recyclerView

    // 카트뷰
    implementation "androidx.cardview:cardview:1.0.0" //cardview

    // 글라이드 - 이미지 처리
    implementation 'com.github.bumptech.glide:glide:4.12.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'

}

//add
// Task 'wrapper' not found in project ':app'. 라는 오류가 나와서 추가함 구글 검색해보니가 하라고 카더라
task wrapper(type: Wrapper) {
    gradleVersion = '2.0'
}
 

Я хочу, чтобы recyclerLayout был напечатан на fragment_1.xml

Огромное спасибо!

Комментарии:

1. В этом случае вы должны использовать view.context с Glide, а не App.instance

2. Не могли бы вы сказать мне конкретно?

3. Что касается ошибки, вы забыли указать приложение в качестве класса приложения в манифесте?