在getView(...)中自定义ImageAdapter for GridView NullPointerException

时间:2014-08-16 03:42:22

标签: gridview typedarray

我有一个名为AddZoneDialog的类,它扩展了DialogFragment。在这个类中,我正在尝试使用存储在名为arrays.xml的xml文件中的图像填充GridView。

我使用TypedArray检索xml文件中的条目。我将该数组传递给自定义ImageAdapter(称为ZoneIconAdapter)以填充GridView。问题是,我一直在行

上获得NullPointerExceptions
holder.iv.setImageResource(imgs.getResourceId(position, -1));

为了使用getResourceId(...)测试TypedArray的用法,我将ImageView放在GridView外部的DialogFragment中,并使用以下方法手动填充图像:

(ImageView) iv = (ImageView) view.findViewById(R.id.ivIcon);

然后我使用了与ZoneIconAdapter中使用的相同语法向其添加图像:

iv.setImageResource(imgs.getResourceId(0, -1));

显示正确的图像。 图像适配器位于名为com.my.project.model的包中,所以我输入了com.my.project.R 在适配器中,如果我尝试对资源进行硬编码,它仍然会出现Null错误:

holder.iv.setImageResource(R.drawable.bed1);

我的代码如下: Class - ZoneIconAdapter:

public class ZoneIconAdapter extends BaseAdapter {
private static final String LOGTAG = "HOMECONTROL";

Context context;
TypedArray imgs;

public ZoneIconAdapter(Context c, TypedArray a){
    this.context = c;
    imgs = a;
}

@Override
public int getCount() {
    //return imgIds.length;
    return imgs.length();
}

@Override
public Object getItem(int index) {
    return imgs.getResourceId(index, -1);
}

@Override
public long getItemId(int index) {
    return index;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;

    if(convertView == null){

        LayoutInflater inflater = ((Activity) context).getLayoutInflater();
        convertView = inflater.inflate(R.layout.zone_icon_list, parent, false);

        holder = new ViewHolder();
        holder.iv = (ImageView) convertView.findViewById(R.id.ivIcon);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();

    }

    Log.w(LOGTAG, "(ZoneIconAdapter) pos: "+ position + " drawable : " +          imgs.getDrawable(position) + " res: " + 
            imgs.getResourceId(position, -1));
    holder.iv.setImageResource(imgs.getResourceId(position, -1));  // ***NULL ERROR ***

    return convertView;
}

private class ViewHolder {
    ImageView iv;
}

}

类 - AddZoneDialog.java

 public class AddZoneDialog extends DialogFragment {
private static final String LOGTAG = "HOMECONTROL";

public static final String EXTRA_ZONE_NAME = "homecontrol.zonename";
public static final String EXTRA_NAME_LIST = "homecontrol.namelist";
public static final String EXTRA_IMG_LIST = "homecontrol.imglist";

private ZoneList zoneList;  
private EditText etZoneName;
private GridView gvIcons;
TypedArray ids;


public AddZoneDialog newInstance(ZoneList zones){
    Bundle args = new Bundle();
    args.putSerializable(EXTRA_NAME_LIST, zones);

    AddZoneDialog newDialog = new AddZoneDialog();
    newDialog.setArguments(args);

    return newDialog;
}

@Override
public Dialog onCreateDialog(Bundle savedState) {
    View v = getActivity().getLayoutInflater()
            .inflate(R.layout.frag_add_zone_dialog, null);

    zoneList =  (ZoneList) getArguments().getSerializable(EXTRA_NAME_LIST);
    gvIcons = (GridView) v.findViewById(R.id.gvZonesIcons);
    etZoneName = (EditText) v.findViewById(R.id.etZonesPopupName);
    etZoneName.requestFocus();

    ImageView iv = (ImageView) v.findViewById(R.id.ivIcon);

    ZoneIconAdapter iconAdapter = new ZoneIconAdapter(getActivity(), ids);
    gvIcons.setAdapter(iconAdapter);

    ids = getActivity().getResources().obtainTypedArray(R.array.zone_icons);
    iconAdapter.notifyDataSetChanged();
    Log.w(LOGTAG, "SIZE OF IDS: " + ids.length());

    iv.setImageResource(ids.getResourceId(0, -1));  // *****THIS WORKS*****

    return new AlertDialog.Builder(getActivity())
        .setView(v)
        .setTitle(R.string.zones_add_dialog_title)
        .setPositiveButton(R.string.ok, new AlertDialog.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                sendResult(Activity.RESULT_OK);
            }
        })
        .setNegativeButton(R.string.cancel, null)
        .create();
}



@Override
public void onActivityCreated(Bundle bundle) {
    getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);

    super.onActivityCreated(bundle);
}

public void sendResult(int resultCode){
    String newName = etZoneName.getText().toString();
    if ((newName.length() < 1) || (newName == null) || (newName == "")){
        Toast.makeText(getActivity(), "You must enter a name.", Toast.LENGTH_SHORT).show();
        return;
    }
    else{
        if (nameOnList(newName)){
            Toast.makeText(getActivity(), "That name is already in use.  Please enter another name.",
                    Toast.LENGTH_LONG).show();
            return;
        }
    }

    if(getTargetFragment() == null)
        return;

    Intent i = new Intent();
    i.putExtra(EXTRA_ZONE_NAME, newName);

    getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode, i);
}

boolean nameOnList(String name){
    for (int i = 0; i < zoneList.size(); i++){
        if (zoneList.get(i).getName().equals(name))
            return true;
    }
    return false;
}

@Override
public void onStop() {
    ids.recycle();
    super.onStop();
}
}

XML - zone_icon_list.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<!-- <com.example.homecontrol.views.DynamicImageView  -->
<ImageView
    android:name="@+id/ivIcon"
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:scaleType="centerCrop" />

</LinearLayout>

XML - frag_add_zone_dialog.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp" >

<TextView 
    android:id="@+id/tvZonesEnterName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/zones_enter_name"/>
<EditText
    android:id="@+id/etZonesPopupName"
    android:layout_width="fill_parent"
    android:layout_height="match_parent"
    android:inputType="text"
    android:hint="@string/zones_name_hint"
    android:singleLine="true" />
<TextView 
    android:id="@+id/tvZonesSelectIcon"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:text="@string/zones_select_icon" />
 <ImageView
    android:id="@+id/ivIcon"
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:scaleType="centerCrop" />

<GridView
    android:id="@+id/gvZonesIcons"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:numColumns="auto_fit"
    android:stretchMode="columnWidth"
    android:gravity="center"
    android:layout_gravity="center_horizontal" />

</LinearLayout>

最后一件事:为了测试GridView和ZoneIconAdapter,我用zoneView替换了zone_icon_list.xml中的ImageView,在Adapter类中,我将ViewHolder改为使用TextView而不是ImageView并使用:

...
holder.tv = (TextView) convertView.findViewById(R.id.tvTest);
...
holder.tv.setText("image " + position);

看看GridView是否只使用TextView填充,它运行得很好。 我整天都在研究这个问题并且已经完成了我能找到的所有stackoverflow条目并且我被烧毁了。我觉得它必须是一种我忽略的愚蠢,但不确定。

1 个答案:

答案 0 :(得分:1)

嗯,这个有点尴尬。在自定义网格适配器视图中,我输入了代码:

<ImageView
    android:name="@+id/..."

而不是

<ImageView
    android:id="@+id/..."

所以我使用我请求的ID为视图获取空值。