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

listviewitem null 에러

0 추천

listviewitem에서 값을 받아오는 작업에서 에러가 납니다. gettitle()에서 null값이 에러라는데 어떻게 고쳐야할지 모르겠습니다. 고수님들 부탁드립니다.

 

ListViewItem

ListViewItem 받는 엑티비티

 

Error

listviewitem click

__AS (230 포인트) 님이 2022년 3월 17일 질문
__AS님이 2022년 3월 18일 수정

3개의 답변

+1 추천
아래 라인이 에러인 것 같네요.

intent.getParcelableExtra("title");

intent에서 ListViewItem타입을 읽으려고 했는데, 왜 title에서 읽고 있는지 좀 의아하네요.  이전 화면에서  ListViewItem을 넘긴 건 가져와야 하는데, title을 읽어 들이고 있네요.

이전화면에서 ListViewItem 전달하는 부분과 해당 데이터를 읽는 부분을 일치시키셔야 겠네요.
spark (227,930 포인트) 님이 2022년 3월 17일 답변
listview onitemclick에서 받는 부분을 사진으로 추가했습니다. 바꿔야한다면 title말고 gettitle부분을 받아야하는건가요?
0 추천

#1. 잠시만 아래 코드가 무얼하는지 생각해 보세요.

intent.putExtra("title", ListViewItem.get(0).getTitle());


#2. 답을 하실 수 있다면, 다음 코드도 무얼 하는지 생각해 보세요.

for (int i = 0; i < ListViewItem.size(); i++) {
    intent.putExtra("title", ListViewItem.get(i).getTitle());
}


#1은 ListViewItem의 첫번째 아이템의 타이틀을 intent의 "title"이라는 키값이 넣는 코드입니다.
#2는 ListViewItem의 모든 아이템의 타이틀을 루프를 돌면서 intent의 "title"이라는 업데이트하는 코드입니다.

#2의 결과는 "title"이라는 키값에 한개의 아이템에 대한 타이틀만 저장이 되겠죠?

만약, 둘 중의 하나라도 틀리셨다면, 자바 기초를 다시 공부하시기 바래요. 

그런데 액티비티에서는, 아래처럼 ListViewItem 전체를 읽어오려고 하는데,  잘못 읽고 있습니다.

ListViewItem item = intent.getParcelableExtra("title");

ListViewItem은 리스트로 보이는데, intent.getParcelableExtra("title")는 아이템을 딱 하나만 읽을 수 있는 메소드입니다. 
잠시 개발자 문서를 보시고 https://developer.android.com/reference/android/content/Intent#getParcelableExtra(java.lang.String)

getParcelableExtra가 뭘하는 메소드인지 확인해 보세요. 

확인하셨다면, 위처럼 읽어오면 어떤 데이터가 읽힐까요?

이전 화면에서 아이템을 선택할 때  Intent에 데이터를 어떻게 전달하셨죠? 아래처럼 하셨죠?

for (int i = 0; i < ListViewItem.size(); i++) {
    intent.putExtra("title", ListViewItem.get(i).getTitle());
}

님이 전달한 건, ListViewItem이라는 리스트에 들어 있는 모든 아이템을 돌면서 title이라는 String 필드를 "title"이라는 키값에 할당했죠?
그럼, 액티비티에서 

intent.getParcelableExtra("title") 

를 호출하게 되면,  Parcelable 타입이 아니므로, null이 들어오게 됩니다. 만약 앞에서 전달한 타이틀을 읽어 들이려면,

intent.getStringExtra("title")

이렇게 하셨어야 겠죠? 이렇게 하면 ListViewItem의 맨마지막 아이템의 title필드가 읽히겠죠?

이해가 안가신다면, 다음을 읽지 마사고 처음부터 반복해서 읽으세요.

spark (227,930 포인트) 님이 2022년 3월 19일 답변
0 추천

님의 코드로 볼 때 님이 하고 싶은 거는, 리스트에서 선택한 아이템 하나를 다음 액티비티에 넘기는 겁니다. 따라서 앞 화면에서는 선택한 아이템을 넘기시고, 액티비티에서는 선택된 아이템을 읽어오셔야 합니다.

해결방법을 알려드릴게요. 먼저 Readability를 위해 변수의 이름을 변경하세요.

ListViewItem -> Post
listViewItems -> posts

그리고 Post클래스는 Parcelable 인터페이스가 구현되어 있어야 합니다. (개인적으로 이런 클래스는 그냥  Serializable을 사용해도 충분합니다.)
 

먼저, ListActivity에서 선택한 Post를 ComponentActivity에 넘기는 코드입니다. ListActivity의 이름을 PostListActivity 정도롤 하면 더 이해하기가 쉬울 것 같네요.

public PostListActivity .... {
   private List<Post> posts = new ArrayList<>();


   ...

   // listviewitem click
   listView.setOnItemClickListener(...{
        PostDetailsActivity.navigate(this, posts.get(position)));
   });
}

 

다음은 ComponentActivity에서 선택한 Post를 읽어오는 코드입니다. ComponentActivity는 클래스 이름을 보고 뭘하는지 알 수가 없으므로, PostDetailsActivty정도로 하면 좋을 것 같습니다.

public class PostDetailsActivity ... {
   private static final String POST = "post";

   public static void navigate(Context context, Post post) {
        Intent intent = new Intent(activity, ComponentActivity.class);
        intent.putExtra(PostDetailsActivity.POST, post);
        context.startActivity(intent);
   }

   protected void onCreate(Bundle savedInstance() {
          super.onCreate(savedInstance);
          ...
   
         bindPostArg();
    }

    private void bindPostArg() {
        Post post = getPostArg();
         title.setText(post.getTitle());
    }

    @NonNull
    private Post getPostArg() {
         Post result = (Post) getIntent().getParcelableExtra(POST);
         if (result == null) throw IllegalArgumentException("Intent에 post가 존재하지 않습니다.");

         return result;
    } 
}

PostListActivity에서  PostDetailsActivity.POST라는 키에 Post 객체를 넘겨줬고 PostDetailsActivity에서도 마찬가지로 intent에 POST키에서 Parcel타입을 읽어와서 Post타입으로 형변환을 해줬습니다.

 

이 문제를 해결하시면서, intent를 이용해 데이터를 주고 받은 부분을 제대로 이해하시고 넘어가시면 좋을 것 같습니다. 왜 사용하는지, 어떻게 사용하는지. Parcelable과 Serializable의 뭐고 어떻게 다른지 등등요.

spark (227,930 포인트) 님이 2022년 3월 19일 답변
spark님이 2022년 3월 19일 수정
...