hguser
hguser

Reputation: 36020

CustomDialog from DialogFragment in android

I am trying to build a dialog like this(google map layer choose dialog):

enter image description here

And this is my core codes:

public class MapLayerSourceChooseDialog extends DialogFragment {
    private MapLayerSelectedListener mListener;
    private LayerAdapter mLayerAdapter;

    public void setLayerSelectListener(MapLayerSelectedListener listener) {
        mListener = listener;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mLayerAdapter = new LayerAdapter(getActivity(), R.layout.common_dialog_maplayer, new ArrayList<MapLayer>());
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle("Layers").setAdapter(mLayerAdapter, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {

                if (mListener != null) {
                    MapLayer layer = mLayerAdapter.getItem(which);
                    mListener.OnMapLayerSelected(which, layer);
                }
            }
        });
        Log.d("map", "dialog on create");
        return builder.create();
    }

    public void updateData(List<MapLayer> layers) {
        mLayerAdapter.updateItems(layers);
    }

    private class LayerAdapter extends ArrayAdapter<MapLayer> {
        private List<MapLayer> mItems;

        public LayerAdapter(Context context, int resource, List<MapLayer> items) {
            super(context, resource, items);
            mItems = items;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder = null;
            if (convertView == null || convertView.getTag() == null) {
                convertView = getActivity().getLayoutInflater().inflate(R.layout.common_dialog_maplayer, parent, false);

                holder = new ViewHolder();
                holder.iconView = (ImageView) convertView.findViewById(R.id.map_layer_icon);
                holder.nameView = (TextView) convertView.findViewById(R.id.map_layer_name);
                holder.checkView = (ImageView) convertView.findViewById(R.id.map_layer_check);

                convertView.setTag(holder);
            } else
                holder = (ViewHolder) convertView.getTag();

            MapLayer layer = getItem(position);
            holder.iconView.setImageDrawable(getResources().getDrawable(layer.drawable));
            holder.nameView.setText(layer.name);
            holder.checkView.setVisibility(layer.isActive ? View.VISIBLE : View.GONE);

            return convertView;
        }

        public void updateItems(List<MapLayer> layers) {
            mItems.clear();
            mItems.addAll(layers);
            // notifyDataSetChanged();
        }
    }

    private static class ViewHolder {
        ImageView iconView;
        TextView nameView;
        ImageView checkView;
    }

    interface MapLayerSelectedListener {
        void OnMapLayerSelected(int index, String name);
    }
}

caller(at another activity):

mapLayerSourceChooseDialog.updateData(layers);
mapLayerSourceChooseDialog.show(getSupportFragmentManager(), null);

But I always get the NPE, I wonder if I use the dialog in a wrong way?

Can anyone check it for me ?

Upvotes: 0

Views: 168

Answers (1)

MH.
MH.

Reputation: 45493

The problem is that you're assuming mLayerAdapter will have been initialised by the time you call mapLayerSourceChooseDialog.updateData(layers). That's not correct. After you instantiate MapLayerSourceChooseDialog, onCreate() will not be called immediately.

Two obvious options:

  1. Supply the List<MapLayer> as argument to the fragment. Use the setArguments() and getArguments() methods on MapLayerSourceChooseDialog. Your MapLayar objects will have to be at least Serializable, but preferably implement Parcelable. Note that you probably don't want to go down this path if your objects are fairly complex and/or the size of the list is reasonably large.
  2. Define a listener interface with a getter that returns List<MapLayer>, which the Activity hosting the fragment should implement. In MapLayerSourceChooseDialog you can then cast the activity and call the getter to retrieve the data. This approach could be faster to implement but may break if your activity doesn't correctly retain the List<MapLayer> on configuration changes.

An example of both approaches can be found in the documentation for DialogFragment.

Upvotes: 1

Related Questions