尝试listview.getChildAt()时java.lang.NullPointerException

时间:2014-10-22 12:33:34

标签: java android listview menuitem

ListView具有正确的值:

public class FragmentTab1 extends SherlockFragment {

ListView list;
LazyAdapter adapter;

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    list = (ListView) getActivity().findViewById(android.R.id.list); //also I tried view.findViewById(android.R.id.list)
    ............

    adapter = new LazyAdapter(getActivity(), mSource);
    list.setAdapter(adapter);
} 
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
    View rootView = inflater.inflate(R.layout.fragmenttab1, container, false);
    return rootView;

}

当我尝试:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId(); //correct
    int itemCount = list.getCount();  // 10 ps as show Logcat
    if (R.id.save == id) {
        CheckBox cb;
        for(int i = itemCount - 1; i >= 0; i--) {
            cb = (CheckBox)list.getChildAt(i).findViewById(R.id.checkBox1);  //Error here
        }
    }
    return true;
}

xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<CheckBox
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Save to database"
    android:id="@+id/checkBox1" />  // same id

接下来是

和适配器:

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;

public LazyAdapter(Activity a, ArrayList<Data> mObjects1) {
    activity = a;
    mObjects = mObjects1;
    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;
    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);
    text.setText(item.getmTitle());
    bitmapArray.add(imageLoader.getBitmap());
    imageLoader.DisplayImage(item.getmImageUrl(), image);
    return vi;
}

我收到了正确的ListView,但是当我尝试从操作栏点击“保存”按钮时收到错误。 可能,我应该在适配器中初始化CheckBox? 有人可以帮帮我吗?

3 个答案:

答案 0 :(得分:0)

如果子项不可见,

list.getChildAt(i)将为null。因此在使用前请检查null。

因此您无法以这种方式检索所有已检查的项目。

请发布完整的.xml和<Data>的定义。

答案 1 :(得分:0)

我认为你会得到一个indexoutofbounds,但因为它是null,这可能就是原因:ListView getChildAt returning null for visible children

此外,在for循环中放置一个日志语句以显示所有相关变量的值,因此:i和itemCount等。

并在循环之前设置一个断点并运行调试模式以逐步检查值,因为它循环通过,你会看到我的值导致调试器中的nullpointer,或者如果你错过它,它将在logcat的

答案 2 :(得分:0)

我知道这是很老的帖子。但是我回答是因为人们仍然在寻找ListView getChildAt()空指针异常的解决方法。

这是因为ArrayApdater因为高度而正在REMOVING和RECYCLING ListView上尚未显示的视图。因此,如果您有10个项目视图,并且ListView可以在当时显示4 - 5:

  • 适配器删除位置5到9的项目视图,这样任何adapter.getChildAt(5... to 9)的尝试都会导致空指针异常

  • 适配器还可以循环项目视图,因此当您向下滚动到5到9时,您在位置3上所做的任何引用都将丢失,并且您在位置3上进行的任何输入也会丢失(EditText,当您向下滚动到5到9时,复选框等将被回收,并且将在稍后的另一个位置(从位置1,2或3等)重新使用具有相同值的复选框

我发现控制它的唯一方法是忘记获取视图并拥有:

  • 属性HashMap<Integer, Boolean> cbValues或您希望处理要用于列表中每个项目的值的任何类型。对于item->getId()position等项,第一种类型必须是唯一的。在构造函数中使用新的HashMap<>()初始化它;
  • 为输入视图添加InputListener,为EditText添加addTextChangedListener,为Checkbox添加setOnCheckedChangeListener等。)在输入时,更新HashMap密钥(item.getId()position)和值(editable.toString()truefalse)。防爆。在@Override public void onCheckedChanged上,输入布尔结果cbValues.put(item.getId(), b);
  • 阻止适配器使用循环使用的convertView,删除条件if(convertView == null),以便适配器始终为全新的视图实例充气。因为视图实例每次都是新的,所以每次都必须从HashMap设置值,就好像它已经包含键if(cbValues.containsKey(item.getId())){cbItem.setChecked(cbValue.get(cbItem.getId()))};一样。可能在这种情况下,没有大量的项目,因此平滑滚动不会是必须的。

  • 最后创建公共方法以获取Adapter之外的值传递item->getId() Integer作为参数。例如:&#39; public bool getCheckboxValueForItemId(int itemId){return cbValues.get(itemId); }。然后,从“适配器”

  • 中选择项目将很容易

以下是最后的代码:

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);
}

}