wanderingProgrammer
wanderingProgrammer

Reputation: 191

Spinner with custom objects list inside custom Dialog Fragment not working

I am at my wits end here. I have been working on this android view where I want to use a dialog box to get the user to fill out a form (essentially). The form contains two list items (which I want to display using the two spinners). The contents of the second list will be populated based on the selected item from List 1. Once both the Spinners have an item selected, I use a recycler view to display further fields to be filled. These fields will be decided based on the item selected in List 2.

My current predicament is that I cannot get the dialog to show me the first list of items. The dialog and the spinner inside it render fine when prompted. But the spinner is always empty.

Here's my code. I'll begin with the markup for the spinner.xml layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="10dp"
        android:textSize="14sp"
        android:textColor="@android:color/black"/>
</LinearLayout>

The layout for my custom dialog:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/properties_ll"
    android:background="@color/translucent_green">
    <Spinner
        android:layout_width="120dp"
        android:layout_height="40dp"
        android:clickable="true"
        android:id="@+id/material_types_dd"
        android:spinnerMode="dropdown"/>
    <Spinner
        android:layout_width="120dp"
        android:layout_height="40dp"
        android:clickable="true"
        android:id="@+id/materials_dd"
        android:spinnerMode="dropdown"/>
    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/material_detials_rv"/>
</LinearLayout>

The custom dialog class (all the HTTP calls using Volley are working and have been thoroughly tested, so I know the problem isn't there):

public class TacDetailsDialogFragment extends DialogFragment {

    private static final String TAG = TacDetailsDialogFragment.class.getSimpleName();


    @BindView(R.id.properties_ll)
    LinearLayout properties;

    @BindView(R.id.material_types_dd)
    Spinner materialtypesDD;

    @BindView(R.id.materials_dd)
    Spinner materialsdd;

    @BindView(R.id.material_detials_rv)
    RecyclerView materialDetailsRecycler;

    private List<BaseModel> materials;
    private List<BaseModel> materialTypes;
    private BaseModel selectedMaterial;
    private BaseModel selectedMaterialType;
    private List<BaseModel> selectedMaterialFields;
    private List<List<BaseModel>> selectedMaterialFieldUnits;

    ProgressBarHelper progressBarHelper;

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        LayoutInflater inflater = getActivity().getLayoutInflater();

        builder.setView(inflater.inflate(R.layout.tac_details_dialog, null))
                .setPositiveButton(
                    R.string.ok,
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {

                        }
                    }
                )
                .setNegativeButton(
                    "Cancel",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            TacDetailsDialogFragment.this.getDialog().cancel();
                        }
                    }
                );
        View view = inflater.inflate(R.layout.tac_details_dialog, null);
        ButterKnife.bind(this, view);

        progressBarHelper = new ProgressBarHelper(this.getActivity());
        getMaterialTypes();
        materialtypesDD.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                Log.d(TAG, materialTypes.get(position).toString());
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });

//        materialsdd.setOnItemSelectedListener(new ClickToSelectEditText.OnItemSelectedListener() {
//            @Override
//            public void onItemSelectedListener(Object item, int selectedIndex) {
//                getMaterialFields();
//            }
//        });


        return builder.create();
    }

    /* The activity that creates an instance of this dialog must implement
     * this interface in order to receive event callbacks. Each method
     * passes the dialogfrag in case the host needs to query it */
    public interface TacDetailsDialogListener {
        public void onDialogPositiveClick(DialogFragment dialog);
    }

    TacDetailsDialogListener mListener;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try{
            mListener = (TacDetailsDialogListener) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString() + " must implement TacDetailsDialogListener");
        }
    }

    private void initMaterialTypesDD() {
        materialtypesDD.setAdapter(new ArrayAdapter<BaseModel>(getContext(), R.layout.spinner, materialTypes) {
            @Override
            public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
                View view = super.getDropDownView(position, convertView, parent);

//                TextView text = (TextView) view.findViewById(R.id.text1);
//                text.setVisibility(View.VISIBLE);
//                text.setTextColor(Color.BLACK);

                return view;
            }
        });
    }


    private void initMaterialsDD() {
        materialsdd.setAdapter(new ArrayAdapter<>(getContext(), R.layout.support_simple_spinner_dropdown_item, materials));
    }

    private void initMaterialFields() {
        materialDetailsRecycler.setLayoutManager(new LinearLayoutManager(this.getContext(), LinearLayoutManager.VERTICAL, false));
        materialDetailsRecycler.setAdapter(new MaterialDetailRecyclerViewAdapter(selectedMaterialFields, selectedMaterialFieldUnits));
    }

    private void initMaterialTypes(JSONArray data) throws JSONException {
        materialTypes = new ArrayList<BaseModel>();
        for (int i = 0; i < data.length(); i++) {
            materialTypes.add(new BaseModel(data.getJSONObject(i)));
        }
    }

    public void initMaterials(JSONArray data) throws JSONException {
        materials = new ArrayList<BaseModel>();
        for (int i = 0; i < data.length(); i++) {
            materials.add(new BaseModel(data.getJSONObject(i)));
        }
    }


    public void initSelectedMaterialFields(JSONArray data) throws JSONException {
        selectedMaterialFields = new ArrayList<BaseModel>();
        selectedMaterialFieldUnits = new ArrayList<List<BaseModel>>();
        for (int i = 0; i < data.length(); i++) {
            JSONObject field = data.getJSONObject(i);
            selectedMaterialFields.add(new BaseModel(field));

            JSONArray fieldUnits = field.getJSONArray("units");
            List<BaseModel> units = new ArrayList<>();
            for (int j = 0; j < fieldUnits.length(); j++) {
                units.add(new BaseModel(fieldUnits.getJSONObject(j)));
            }
            selectedMaterialFieldUnits.add(units);
        }
    }

    private void getMaterialTypes() {
        VolleySingleton.getInstance(this.getContext()).addToRequestQueue(
                new JsonObjectRequest(
                        Request.Method.GET,
                        getString(R.string.server_ip) + getString(R.string.materialtypes),
                        null,
                        new Response.Listener<JSONObject>() {
                            @Override
                            public void onResponse(JSONObject response) {
                                try {
                                    if (response.getInt("code") == 200) {
                                        initMaterialTypes(response.getJSONArray("data"));
                                        initMaterialTypesDD();
                                    }
                                } catch (JSONException e) {
                                    e.printStackTrace();
                                }

                            }
                        },
                        new Response.ErrorListener() {
                            @Override
                            public void onErrorResponse(VolleyError error) {
                                error.printStackTrace();
                            }
                        }
                )
        );
    }

    private void getMaterials() {
        VolleySingleton.getInstance(this.getContext()).addToRequestQueue(
                new JsonObjectRequest(
                        Request.Method.GET,
                        getActivity().getString(R.string.server_ip) + getActivity().getString(R.string.materials) + selectedMaterialType.getId(),
                        null,
                        new Response.Listener<JSONObject>() {
                            @Override
                            public void onResponse(JSONObject response) {
                                try {
                                    if (response.getInt("code") == 200) {
                                        JSONArray data = response.getJSONArray("data");
                                        initMaterials(data);
                                        initMaterialsDD();
                                    }
                                } catch (JSONException e) {
                                    e.printStackTrace();
                                }
                            }
                        },
                        new Response.ErrorListener() {
                            @Override
                            public void onErrorResponse(VolleyError error) {

                            }
                        }
                )
        );
    }
    private void getMaterialFields() {
        VolleySingleton.getInstance(this.getContext()).addToRequestQueue(
                new JsonObjectRequest(
                        Request.Method.GET,
                        getString(R.string.server_ip) + getString(R.string.materialfields) + selectedMaterial.getId(),
                        null,
                        new Response.Listener<JSONObject>() {
                            @Override
                            public void onResponse(JSONObject response) {
                                try {
                                    if (response.getInt("code") == 200) {
                                        initSelectedMaterialFields(response.getJSONArray("data"));
                                        initMaterialFields();
                                    }
                                } catch (JSONException e) {
                                    e.printStackTrace();
                                }
                            }
                        },
                        new Response.ErrorListener() {
                            @Override
                            public void onErrorResponse(VolleyError error) {

                            }
                        }
                )
        );
    }
}

The custom object, BaseModel:

public class BaseModel implements Listable {
    String name;
    int id;
    int type_id;

    public BaseModel() {}

    public BaseModel(JSONObject jsonObject) {
        try {
            this.name = jsonObject.getString("name");
        } catch (JSONException e) {
            e.printStackTrace();
        }

        try {
            this.id = jsonObject.getInt("id");
        } catch (JSONException e) {
            e.printStackTrace();
        }

        try {
            this.type_id = jsonObject.getInt("type_id");
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public BaseModel(String name) {
        this.name = name;
    }

    public BaseModel(String name, int id) {
        this.name = name;
        this.id = id;
    }

    public BaseModel(String name, int id, int type_id) {
        this.name = name;
        this.id = id;
        this.type_id = type_id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getType_id() {
        return type_id;
    }

    public void setType_id(int type_id) {
        this.type_id = type_id;
    }

    public String toString() {
        return this.name;
    }

    @Override
    public String getLabel() {
        return this.name;
    }

    @Override
    public void setValues(String name, int id) {
        this.name = name;
        this.id = id;
    }
}

And this is how I call the dialog from the main activity:

public void makeTacDetailsAlert() {
        dialog = new TacDetailsDialogFragment();
        dialog.show(this.getSupportFragmentManager(), "TacDetailsDialogFragment");
    }

Idk if the RecyclerView bits are relevant so not including them in this already code-cluttered question.

Over to you, S/O Gods.

Upvotes: 0

Views: 2064

Answers (1)

wanderingProgrammer
wanderingProgrammer

Reputation: 191

Thanks to a good night's sleep, some clearer headed thinking, and @Sam's answer (https://stackoverflow.com/a/14676975/3438497) I have fixed my problem.

Other than ensuring that I was binding my dialog and individual views to the same layout instance (and not different instances), I also needed to create a custom SpinnerAdapter for the BaseModel object as suggested here: https://stackoverflow.com/a/8116756/3438497

Hope this helps out anyone else facing this issue.

Upvotes: 1

Related Questions