마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

네비게이션 드로어 텍스트뷰 오류....

0 추천
이런식으로 네비게이션 헤더부분에 텍스트뷰를 넣어서

실행을하면 파이어베이스에서 데이터를 꺼내와서 텍스트뷰에 넣어서 이름이 보이도록 하려고하는데 

이 부분에서 계속 오류가 납니다.

supportActionBar!!.setDisplayHomeAsUpEnabled(true)  // 왼쪽 버튼 사용 여부 true
        supportActionBar!!.setHomeAsUpIndicator(R.drawable.ic_menu_black_24dp)  // 왼쪽 버튼 이미지 설정
        supportActionBar!!.setDisplayShowTitleEnabled(false)    // 타이틀 안보이게 하기
        navigationView_4.setNavigationItemSelectedListener(this)
        val textView: TextView = findViewById(R.id.header_name)
        textView.text = "내이름"

이런식으로 textView.text = "내이름" 처럼 임시로 문자열을 넣었는데 어플이 중지되면서 실행이 안됩니다.

파이어베이스의 값을 옮겨서 넣었을때는 처음에는 되었는데 뒤로갔다 다시 들어가면 값이 null값이 되면서 오류가 나서 textView?.text = 식으로 할때는 null값이 들어가서 레이아웃에 설정했떤 "이름"이라는 값만 텍스트 뷰에 나왔는데 이런 문제를 해결하고싶습니다.

val myname : DatabaseReference = FirebaseDatabase.getInstance().getReference("/User/$id/name")
           myname.addValueEventListener(object : ValueEventListener{
               override fun onDataChange(datasnapshot: DataSnapshot?) {
                   val value = datasnapshot?.value
                   header_name.text ="$value"
               }
               override fun onCancelled(p0: DatabaseError?) {
                   println("Failed to read value.")
               }
           })

이건 파이어베이스에서 데이터를 갖고와서 텍스트 뷰에 넣는 방식인데, 이를 사용할시 네비게이션 드로어 텍스트뷰에 잘 나오는데 특정 엑티비티 들어간 후 뒤로가기 눌렀을 때 아래와 같은 오류가 나면서 어플이 중지됩니다.

 

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.user.jsoup, PID: 3273
    java.lang.IllegalStateException: header_name must not be null
        at com.example.user.jsoup.LOBY$onCreate$1.onDataChange(LOBY.kt:60)
        at com.google.android.gms.internal.firebase_database.zzfc.zza(Unknown Source)
        at com.google.android.gms.internal.firebase_database.zzgx.zzdr(Unknown Source)
        at com.google.android.gms.internal.firebase_database.zzhd.run(Unknown Source)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6119)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
V/FA: Activity resumed, time: 32635142
Application terminated.

 

LOBY.kt:60 줄은

val value = datasnapshot?.value

입니다.

 val myname : DatabaseReference = FirebaseDatabase.getInstance().getReference("/User/$id")
       myname.addListenerForSingleValueEvent(object : ValueEventListener{
           override fun onCancelled(error: DatabaseError) {
               error?.toException()?.printStackTrace()
           }
           override fun onDataChange(p0: DataSnapshot?) {
               for (snapshot in p0!!.children){
                   if (snapshot.key.equals("name")) {
                       Log.d("리스트","header_name= $header_name, value = ${snapshot.value}")
                       textView.text = "${snapshot.value}"
                   }
               }
           }
       })

 

nagada32 (290 포인트) 님이 2021년 5월 18일 질문
nagada32님이 2021년 5월 19일 수정

2개의 답변

0 추천

다른 화면에 갔다 올 때 라이프사이클로 인해 뷰가 새로 그려질 때 파이어 베이스 콜백이 먼저 호출될 경우 아직 findviewbyId가 호출되지 못한 상황일 수 있을 것 같다는 추측만 되네요.

val textView: TextView = findViewById(R.id.header_name)

이 분은 lazy init 을 사용하셔서

private val textView: TextView by lazy { findViewById(R.id.header_name) }

처럼 바꾸신 다음 테스트 해보시죠. 위의 코드는 초기화가 먼저 이루어지는 게 보장되므로 시도해 볼 만한 것 같네요.

 

 

spark (227,530 포인트) 님이 2021년 5월 18일 답변
private  val textView: TextView by lazy { findViewById(R.id.header_name) }넣을 시 아래와 같은 오류가 발생합니다

Type inference failed: Not enough information to infer parameter T in
fun <T : View!> findViewById(id: Int): T!
Please specify it explicitly.
코틀린 버전을 좀 낮은 버전을 쓰셔서 그런가요(???). 전혀 문제가 없는 문법인데 말이죠.
private  val textView: TextView by lazy { findViewById<TextView>(R.id.header_name) }
이렇게 해보시죠. 그리고 이건 액티비티의 클래스 멤버 변수로 등록하세요.
문법에는 오류가 안나는데 실행에는 똑같이 오류가 발생하네요..ㅜ
이게 게시글리스트 엑티비티로 전환할때 오류가는데 게시글을 작성하거나 댓글을 작성했을때 게시글리스트 리사이클러뷰에 변화가 생기면서 오류가 발생하는거같습니다. 근데 게시글 삭제나 댓글삭제때는 오류가 발생하지않네요...
딜레이 0.5초를 주고 텍스트뷰에 값을 넣어보니 잘되네요...
말씀해주신거처럼 파이어베이스콜백이 먼저 호출되서 오류가 발생했나봅니다. 감사합니다.
0 추천

XML에 해당 View가 존재하는데 콜백안에서 접근할 때 NullPointerException이 발생하는 것 같네요. 아무래도 라이프사이클 관련 문제로 보입니다. 화면이 이동되고 난 다음에 파이어베이스 콜백이 호출이 되는 것 같은데, 이 때 이전 화면에 있던 프레그먼트가 초기화 되면서 뷰가 실제로 없어진 것은 아니지만 접근할 수 없는 상태가 되는 것 같습니다. 안전한 코드를 위해서 onStop에서파이이베이스 콜백을 제거하고 onStop에서 다시 등록해 주는 게 좋을 것 같습니다.

val myNameCallback = object : ValueEventListener{
          override fun onCancelled(error: DatabaseError) {
              error?.toException()?.printStackTrace()
          }
          override fun onDataChange(p0: DataSnapshot?) {
              for (snapshot in p0!!.children){
                  if (snapshot.key.equals("name")) {
                      Log.d("리스트","header_name= $header_name, value = ${snapshot.value}")
                      textView.text = "${snapshot.value}"
                  }
              }
          }
      }


fun onStart(...) {
     myname.addListenerForSingleValueEvent(myNameCallback)
}

fun onStop() {
    // 콜백을 제거하는 함수를 확인하셔서 사용하세요. 제가 추측해서 적은 겁니다.
    myname.removeListenerForSingleValueEvent(myNameCallback)
}

 

콜백처럼 Asynchronous 로 동작하는 코드가 있는 경우 라이프사이클에 따라 등록/해제 하는 부분을 잘 체크해야 합니다.

 

 

 

spark (227,530 포인트) 님이 2021년 5월 19일 답변
...