Program Tip

ListView getChildAt는 보이는 자식에 대해 null을 반환합니다.

programtip 2020. 11. 10. 22:10
반응형

ListView getChildAt는 보이는 자식에 대해 null을 반환합니다.


listview / getChildAt 메서드에서 이상한 동작이 발생합니다.

데이터베이스에서 변경된 아이콘의 HashSet, iconsToUpdate가 있습니다. 새 아이콘을 반영하기 위해 아이콘을 업데이트해야하는지 확인하기 위해 보이는 행을 반복하고 싶습니다. 현재보기에없는 아이콘은 렌더링 할 때 제대로 그려 지므로 테스트 할 필요가 없습니다.

내 문제는 getChildAt이 안되는 것처럼 보일 때 null을 반환한다는 것입니다. getChildAt은 현재 보이는 뷰만 반환 할 수 있지만 보이는 행 중 일부에 대해서는 null을 반환한다는 것을 알고 있습니다.

다음은 보이는 행을 반복하는 코드입니다.

Logger.debug("First visible index: " + f_listView.getFirstVisiblePosition());
Logger.debug("Last visible index: " + f_listView.getLastVisiblePosition());
for (int i = f_listView.getFirstVisiblePosition(); i <= f_listView.getLastVisiblePosition(); i++) {
    String tag = "asdf"; // Remove when bug is fixed.
    if (f_listView == null) {
        Logger.debug("f_listView is null");
    } else if (f_listView.getChildAt(i) == null) {
        Logger.debug("Child at index " + i + " is null");
    } else {
        tag = (String) f_listView.getChildAt(i).getTag();
        Logger.debug("Successful at index " + i + ", tag is: " + tag);
    }
    if (iconsToUpdate.contains(tag)) {
        setIcon(i, f_aim.getInHouseIcon(tag));
    }
}

다음은이 루프 실행에 해당하는 로그입니다.

D/...: First visible index: 3
D/...: Last visible index: 8
D/...: Successful at index 3, tag is: ...
D/...: Successful at index 4, tag is: ...
D/...: Successful at index 5, tag is: ...
D/...: Child at index 6 is null
D/...: Child at index 7 is null
D/...: Child at index 8 is null

내가 이것을 실행할 때 행 3-8을보고 있기 때문에 처음과 마지막으로 보이는 인덱스가 올바르게보고되고 있다는 점에 유의해야합니다. 6, 7, 8 행이 제대로 렌더링되고 있습니다. null 인 경우 어떻게 표시됩니까?

또한 이것이 중요한지 모르겠지만 목록보기의 맨 위에있을 때 행 5가 마지막으로 보이는 행입니다.

이 행이 null로 반환되는 이유에 대한 정보는 크게 감사하겠습니다.

감사!


listView.getChildAt (i)는 0이 맨 처음 표시되는 행이고 (n-1)이 마지막으로 표시되는 행인 경우 작동합니다 (여기서 n은 표시되는 뷰 수).

get last / first visible은 보유한 dataAdapter의 위치를 ​​반환합니다. 따라서 위치 3에서 시작하여 6 개의 가시적 뷰로 보이는 것이므로 위치 6-8을 얻으면 null이됩니다.

귀하의 예에서 getChildAt (0)은 위치 3을 반환합니다. 일반적으로 수행하는 작업은 값이 필요한 경우 나중에 dataAdapter를 조회 할 수 있도록 뷰에 위치를 저장하는 것입니다.

for 루프가 다음과 같이 보일 것이라고 생각합니다.

for (int i = 0; i <= f_listView.getLastVisiblePosition() - f_listView.getFirstVisiblePosition(); i++) 

도움이 되었기를 바랍니다.


시험

f_listView.getChildAt(positionOfChildYouWantGet - f_listView.getFirstVisiblePosition());

당신이 호출 할 때 listView1.getLastVisiblePosition()listView1.getFirstVisiblePosition()는이 listview목록보기에 일부라도 표시되는 항목의 위치를 반환합니다. 예를 들어, 첫 번째 항목은 절반이 표시되고 마지막 항목은 절반이 표시 될 수 있습니다. 이 경우 목록보기에서 항목의 일부를 볼 수 있지만 어댑터는 아직 getView()항목에 대한 함수를 호출하지 않았 으므로 항목은 여전히 ​​null로 간주됩니다.


제 경우에는 a가 listView있고 첫 번째 항목이 완전히 표시되지만 getFirstVisiblePosition()결과는 1입니다!

스크롤하여 첫 번째 항목을 절반으로 표시 한 다음 0 인 getView쇼를 표시 하면 더 이상해집니다 getFirstVisiblePosition().

이 내 코드 :

public View getView(final int position, View convertView, final ViewGroup parent) {
        row = convertView;
        final AtomPaymentHolder holder = new AtomPaymentHolder();

        LayoutInflater inflater = ((Activity) context).getLayoutInflater();
        row = inflater.inflate(layoutResourceId, parent, false);
        row.setTag(items.get(position));
        holder.songitem = items.get(position);
        final int firstPosition = MainActivity.listviewSong.getFirstVisiblePosition() - MainActivity.listviewSong.getHeaderViewsCount(); 
        final int lastPosition = MainActivity.listviewSong.getLastVisiblePosition();

        if(MusicService.indexService>= firstPosition && MusicService.indexService<= lastPosition){
            MainActivity.listviewSong.getChildAt(MusicService.indexService-firstPosition).setBackgroundColor(getContext().getResources().getColor(R.color.pressed_color));
        }

(다음 항목을 선택하고 스크롤하면 잘 작동합니다)


부분적으로 보일 수 있습니다. 그러나 getView ()가 뷰를 재활용하려고 할 때 완전히 표시되는 뷰를 가져 오면 다른 뷰는 null로 간주됩니다. 예를 들어 목록을 스크롤하고 상단 항목이 부분적으로 표시되고 하단이 부분적으로 표시되므로 null이지만 여전히 표시되는 경우입니다.


OnListItemClickListener ()에서 시도했지만 실패했습니다. 마침내 나는 listview에 대한 사용자 정의 어댑터를 약간 수정했습니다. 여기 getView ()에서는 자주 목록에 추가 한 항목에 clickListener를 적용합니다. n 거기에서 필요한 모든 기능을 수행합니다. 다음은 목록 n에 이미지보기를 추가하여 이미지보기에 리스너를 적용하는 코드입니다.

I Think it will help those who want to change the color when specific List Item is >selected. Go For it..

In getView() of customized Adapter //---------------------------------code------------------------------------------

LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

View rowView = inflater.inflate(R.layout.icon_image_layout, parent, false); ImageView imageView = (ImageView) rowView.findViewById(R.id.Icon_ImageView); imageView.setClickable(true); final int pos=position; imageView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub // TODO Auto-generated method stub try{ if(previous_view!=null) previous_view.setBackgroundColor(Color.WHITE); }catch (Exception e) { System.out.println("Exception Occurs Previous View"); } v.setBackgroundColor(Color.RED); MainActivity.imageView.setImageResource(MainActivity.Image_Name[pos]); previous_view=v; return false; } });

I know this is very old post. But I'm answering because people are still looking for a work around on ListView getChildAt() null pointer exception.

This is because the ArrayApdater is REMOVING and RECYCLING the views that are not visible yet on the ListView because of height. So that if you have 10 item views, and ListView can display 4 - 5 at a the time :

The Adapter REMOVE the item views at position 5 to 9, so that any attempt to adapter.getChildAt(5... to 9) will cause null pointer exception

The Adapter also RECYCLE the item view, so that any reference you made on position 3 for example will be lost when you scroll down to 5 to 9, and also any Input that you make on position 3 (EditText, Checkbox, etc.) will be recycled when you scroll down to 5 to 9 and will be reused at another position later (ex position 1, 2 or 3, etc.) with the same value

The only way I found to control this is to forget about getting the View and to have :

Attribute HashMap<Integer, ImageView> iconViews or any type you want for handling the values you want to use for each item on the list. The first type must be unique for item like item->getId() or position. Initialize it with new HashMap<>() in the Constructor; in getViews make iconViews.put(position, iconView); Prevent Adapter from using recycled convertView, remove condition if(convertView == null) so that adapter always inflate a brand new view instance. Because the view instance is new each time, you must set the value from HashMap each time also like if it already contains the key if(iconViews.containsKey(position)){iconView = iconViews.get(position))};. Probably in this case there is not tons of Items, so that smooth scrolling won't be a must.

And finally create public methods to get the Values outside of Adapter passing item->getId() Integer as parameter. Ex : public ImageView getIconViewAt(int position) { return iconViews.get(position); } . It will be easy then to select Item from Adapter

See more from my answer.


Isn't it because you are saying

f_listView.getChildAt(i) 

And you should be retrieving the item at that position?

f_listView.getItemAtPosition(i) 

참고URL : https://stackoverflow.com/questions/6766625/listview-getchildat-returning-null-for-visible-children

반응형