java.lang.NullPointerException when try listview.getChildAt()

前端 未结 3 1365
猫巷女王i
猫巷女王i 2021-01-25 07:12

There is ListView with correct values:

public class FragmentTab1 extends SherlockFragment {

ListView list;
LazyAdapter adapter;

@Override
public void onViewCre         


        
相关标签:
3条回答
  • 2021-01-25 08:04

    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, Boolean> cbValues 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;
    • Add InputListener for Input Views, (addTextChangedListener for EditText, setOnCheckedChangeListener for Checkbox, etc.) And on input, update the HashMap key (item.getId() or position) and value (editable.toString() or true or false). Ex. on @Override public void onCheckedChanged, put boolean result cbValues.put(item.getId(), b);
    • 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(cbValues.containsKey(item.getId())){cbItem.setChecked(cbValue.get(cbItem.getId()))};. 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 bool getCheckboxValueForItemId(int itemId) { return cbValues.get(itemId); }` . It will be easy then to select Item from Adapter

    Here is the Codes at the end :

    public class LazyAdapter extends BaseAdapter {
    
    
    private Activity activity;
    ArrayList<Bitmap> bitmapArray = new ArrayList<Bitmap>();
    private ArrayList<Data> mObjects;
    private static LayoutInflater inflater=null;
    public ImageLoader imageLoader;
    
    HashMap<Integer, Boolean> cbValues;
    
    public LazyAdapter(Activity a, ArrayList<Data> mObjects1) {
        activity = a;
        mObjects = mObjects1;
        cbValues = new HashMap<>();
        inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        imageLoader=new ImageLoader(activity.getApplicationContext());
    }
    
    public int getCount() {
        return mObjects.size();
    }
    
    public Object getItem(int position) {
        return position;
    }
    
    public long getItemId(int position) {
        return position;
    }
    
    public View getView(int position, View convertView, ViewGroup parent) {
        Data item = mObjects.get(position);
        View vi=convertView;
        // Remove convertView condition
        //if(convertView==null)
    
        vi = inflater.inflate(R.layout.item_internet, null);
        TextView text=(TextView)vi.findViewById(R.id.title1);
        ImageView image=(ImageView)vi.findViewById(android.R.id.icon);
        Checkbox cbItem = (Checkbox) vi.findViewById(android.R.id.checkbox1);
        text.setText(item.getmTitle());
        bitmapArray.add(imageLoader.getBitmap());
        imageLoader.DisplayImage(item.getmImageUrl(), image);
    
        if(cbValues.containsKey(item.getId())) {
            cbItem.setChecked(cbValue.get(cbItem.getId()))};
        }
    
        cbItem.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
               cbValues.put(item.getId(), b);
           }
        });
    
        return vi;
    }
    
    // itemId : unique identifier for an Item, not the position of Item in Adapter
    public bool getCheckboxValueForItemId(int itemId) {
        return cbValues.get(itemId);
    }
    
    }
    
    0 讨论(0)
  • 2021-01-25 08:07

    list.getChildAt(i) will be null if the child item is not visible. So check for null before use.

    So you cannot retrieve all checked items in this way.

    Please post complete .xml and the definition of <Data>.

    0 讨论(0)
  • 2021-01-25 08:17

    I'd think you'd get an indexoutofbounds but since it's null, this might be why: ListView getChildAt returning null for visible children

    Also, put a log statement in your for loop to display the value of all variables concerned, so: i and itemCount etc.

    And set a breakpoint just before the loop and run debug mode to step over to check the values as it loops through and you'll see what i value caused the nullpointer in the debugger or if you miss it, it will be in logcat

    0 讨论(0)
提交回复
热议问题