I have a class called AddZoneDialog which extends DialogFragment. In this class I'm trying to populate a GridView with images I have stored in an xml file called arrays.xml.
I've used TypedArray to retrieved the entries in the xml file. I pass that array to the custom ImageAdapter (called ZoneIconAdapter) to fill the GridView. The problem is, I keep getting NullPointerExceptions on the line
holder.iv.setImageResource(imgs.getResourceId(position, -1));
To test the usage of the TypedArray using getResourceId(...), I placed an ImageView in the DialogFragment itself outside of the GridView and populated it with an image manually using:
(ImageView) iv = (ImageView) view.findViewById(R.id.ivIcon);
I then used the same syntax I used in the ZoneIconAdapter to add an image to it:
iv.setImageResource(imgs.getResourceId(0, -1));
and the correct image displayed. The image adapter is in a package called com.my.project.model and so I did import com.my.project.R In the adapter, it still gives the Null error if I try to hard code the resource:
holder.iv.setImageResource(R.drawable.bed1);
My code is as follows: 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;
}
}
Class - 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>
One last thing: to test the GridView and ZoneIconAdapter, I replaced the ImageView in zone_icon_list.xml with a TextView and in the Adapter class I changed the ViewHolder to have a TextView instead of the ImageView and used:
...
holder.tv = (TextView) convertView.findViewById(R.id.tvTest);
...
holder.tv.setText("image " + position);
to see if the GridView would populate with just a TextView, and it worked just fine. I've been working on this all day and have gone through about all of the stackoverflow entries I could find and I am burnt out. I feel it has to be something stupid I'm overlooking, but just not sure.
Well, this one is a bit embarrassing. In the custom grid adapter view, I put the code:
<ImageView
android:name="@+id/..."
instead of
<ImageView
android:id="@+id/..."
So I was getting a null value for the view with the ID I was requesting.