Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Country, state and city spinner not working correctly

I've been working on a registration form app with few spinner widgets being used in it. The spinners are to be used to select Country, State and City. Hence, these spinners need to be interconnected somehow (The code below would show how I have tried to achieve that).

Form code:

fragment_register.xml

<?xml version="1.0" encoding="utf-8"?>

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

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_marginLeft="40dp"
android:layout_marginRight="40dp"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nestedScrollingEnabled="true">


<TextView
    android:text="Student Registration Form"
    android:textSize="22sp"
    android:textAlignment="center"
    android:layout_marginBottom="20dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

    <Spinner
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/country_spinner"
        android:foregroundTint="#222"
        android:background="#001c47"
        android:layout_marginBottom="20dp" />

    <Spinner
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/state_spinner"
        android:foregroundTint="#222"
        android:background="#001c47"
        android:layout_marginBottom="20dp" />

    <Spinner
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/city_spinner"
        android:foregroundTint="#222"
        android:background="#001c47"
        android:layout_marginBottom="20dp" />

</LinearLayout>
</ScrollView>

The code above has more widgets which you might find in the java file; I haven't included them in above code as it would make it too long.

RegisterFragement.java

import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.SharedPreferences;
import android.nfc.Tag;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;


import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.AppCompatButton;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;


public class RegisterFragment extends Fragment  implements View.OnClickListener, Spinner.OnItemSelectedListener{

private AppCompatButton btn_register;
private EditText et_email,et_password,et_name;
private TextView tv_login;
private ProgressBar progress;
//Declaring the Spinners
private Spinner country_spinner;
private Spinner state_spinner;
private Spinner city_spinner;


//An ArrayList for Spinner Items
private ArrayList<String> results;
// countGetData: It will keep a count of how many times get data has been run and for 0 times
// it would set the spinners to default state
private int countGetData;
ArrayList student1 = new ArrayList();


//JSON Array
private JSONArray resultArray;


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.fragment_register,container,false);
    initViews(view);
    return view;

}

private void initViews(View view){

    btn_register = (AppCompatButton)view.findViewById(R.id.btn_register);
    tv_login = (TextView)view.findViewById(R.id.tv_login);
    et_name = (EditText)view.findViewById(R.id.et_name);
    et_email = (EditText)view.findViewById(R.id.et_email);
    et_password = (EditText)view.findViewById(R.id.et_password);

    progress = (ProgressBar)view.findViewById(R.id.progress);

    btn_register.setOnClickListener(this);
    tv_login.setOnClickListener(this);
    //Initializing the ArrayList
    results = new ArrayList<String>();
    // Initializing countGetData
    countGetData = 0;

    //Initializing Spinner
    country_spinner = (Spinner) view.findViewById(R.id.country_spinner);
    state_spinner = (Spinner) view.findViewById(R.id.state_spinner);
    city_spinner = (Spinner) view.findViewById(R.id.city_spinner);


    //Adding an Item Selected Listener to our Spinner
    //As we have implemented the class Spinner.OnItemSelectedListener to this class iteself we are passing this to setOnItemSelectedListener
    country_spinner.setOnItemSelectedListener(this);
    state_spinner.setOnItemSelectedListener(this);
    city_spinner.setOnItemSelectedListener(this);
    university_spinner.setOnItemSelectedListener(this);
    college_spinner.setOnItemSelectedListener(this);
    ca_spinner.setOnItemSelectedListener(this);


    getData("getCountries", "", 0);
}


@Override
public void onClick(View v) {

    switch (v.getId()){
        case R.id.tv_login:
            goToLogin();
            break;

        case R.id.btn_register:

            String name = et_name.getText().toString();
            String email = et_email.getText().toString();
            String password = et_password.getText().toString();

            if(!name.isEmpty() && !email.isEmpty() && !password.isEmpty()) {

                progress.setVisibility(View.VISIBLE);
                registerProcess(name,email,password);

            } else {

                Snackbar.make(getView(), "Fields are empty !", Snackbar.LENGTH_LONG).show();
            }
            break;

    }

}

private void getData(String urlPart1,String urlPart2, long itemId) {
    //Creating a string request
    StringRequest stringRequest = new StringRequest(Config.DATA_URL+urlPart1+"&"+urlPart2+"="+itemId,
            new Response.Listener<String>() {
                @Override
                public void onResponse(String response) {
                    JSONObject j = null;
                    try {
                        //Parsing the fetched Json String to JSON Object
                        j = new JSONObject(response);

                        //Storing the Array of JSON String to our JSON Array
                        resultArray = j.getJSONArray(Config.JSON_ARRAY);

                        //Calling method getStudents to get the students from the JSON Array
                        getResults(resultArray);

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

                }
            });

//Creating a request queue
        RequestQueue requestQueue = Volley.newRequestQueue(getActivity().getApplicationContext());
    //Adding request to the queue
    requestQueue.add(stringRequest);

}

private void getResults(JSONArray j) {
    //Traversing through all the items in the json array
    for (int i = 0; i < j.length(); i++) {
        try {
            //Getting json object
            JSONObject json = j.getJSONObject(i);

            //Adding the name of the student to array list
            results.add(json.getString(Config.TAG_NAME));
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    if(countGetData == 0) {
        student1.add("Select This");
        //Setting adapter to show the items in the spinner
        country_spinner.setAdapter(new ArrayAdapter<String>(getActivity().getApplicationContext(), android.R.layout.simple_spinner_dropdown_item, results));
        state_spinner.setAdapter(new ArrayAdapter<String>(getActivity().getApplicationContext(), android.R.layout.simple_spinner_dropdown_item, student1));
        city_spinner.setAdapter(new ArrayAdapter<String>(getActivity().getApplicationContext(), android.R.layout.simple_spinner_dropdown_item, student1));
        countGetData += 1;
    }
}



//this method will execute when we pic an item from the spinner
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

    if(country_spinner.getSelectedItem().toString().equals("Austria")){
        long itemId = country_spinner.getSelectedItemId();
        getData("getStates","countryId",itemId);
        state_spinner.setAdapter(new ArrayAdapter<String>(getActivity().getApplicationContext(), android.R.layout.simple_spinner_dropdown_item, results));
    }
    else{
        long itemId = country_spinner.getSelectedItemId();
        getData("getStates","countryId",itemId);
        state_spinner.setAdapter(new ArrayAdapter<String>(getActivity().getApplicationContext(), android.R.layout.simple_spinner_dropdown_item, results));
    }


}
}

There is a PHP API which returns the json for Country, State or City based on the url. For ex.: http://www.example.com/location_api/api.php?type=getCountries http://www.example.com/location_api/api.php?type=getStates&countryId=12 http://www.example.com/location_api/api.php?type=getCities&stateId=1

In onItemSelected I'm trying to dynamically set spinners with respect to the previous spinner. For ex., I'm setting the state spinner whenever a country spinner item is selected. I'm checking this through a if-else block; if condition checks if Austria(one of the countries in the list; random choice) is selected then set the state spinner else also set the state spinner. This way I end up setting the state spinner according to the country spinner element.

To specify to the API which country is being chosen I'm using the itemId which contains the Id of the selected item in country spinner. long itemId = country_spinner.getSelectedItemId();

Then when I have the Id I call the getData method which sets the result ArraryList and I assign it to the spinner state.

getData("getStates","countryId",itemId); state_spinner.setAdapter(new ArrayAdapter<String>(getActivity().getApplicationContext(), android.R.layout.simple_spinner_dropdown_item, results));

The above code is making the app crash at run time with following error(only part of it which I think might be useful, full Logcat file here: Link):

--------- beginning of crash 04-13 21:05:09.782 9288-9600/com.gouravchawla.loginregistration E/AndroidRuntime: FATAL EXCEPTION: Thread-503 Process: com.gouravchawla.loginregistration, PID: 9288 java.lang.NegativeArraySizeException: -110 at com.android.volley.toolbox.DiskBasedCache.streamToBytes(DiskBasedCache.java:316) at com.android.volley.toolbox.DiskBasedCache.get(DiskBasedCache.java:117) at com.android.volley.CacheDispatcher.run(CacheDispatcher.java:101)

Throwing OutOfMemoryError "Failed to allocate a 1667853436 byte allocation with 777786 free bytes and 381MB until OOM"

like image 441
Gourav Chawla Avatar asked Apr 13 '16 15:04

Gourav Chawla


People also ask

How to use dropdown in android?

You can add a dropdown menu to your Android application in a few simple steps. For starters, you need to edit the XML files. Integrate the dropdown menu into them using Android Studio's drag-and-drop feature. Next, you have to create a string array to add all the relevant items to your dropdown menu.

Which of the following look like a dropdownlist in android?

Spinner is a widget similar to a drop-down list for selecting items. In this tutorial, we show you how to do the following tasks : Render a Spinner in XML, and load the selection items via XML file also. Render another Spinner in XML, and load the selection items via code dynamically.


2 Answers

in your code you would have to change the adapter of the spinner which is dependent on the other spinners for example.

City spinner adapter change depending on State spinner adapter so does the
Statespinner adapter change depending on Countryspinner adapter,

I have written a sample code that would demonstrate how this can be achieved, I have written a generic code that others can understand while reading the answer feel free to suggest and change it as it fits your requirement.

Code is also available on Github, and another example that would help you download JSON data from network it uses, OkHttp, GSON and apache-common-io, code

public class SpinnerCountryActivity extends AppCompatActivity {

    private Spinner country_Spinner;
    private Spinner state_Spinner;
    private Spinner city_Spinner;

    private ArrayAdapter<Country> countryArrayAdapter;
    private ArrayAdapter<State> stateArrayAdapter;
    private ArrayAdapter<City> cityArrayAdapter;

    private ArrayList<Country> countries;
    private ArrayList<State> states;
    private ArrayList<City> cities;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_spinner_country);

        initializeUI();
    }

    private void initializeUI() {
        country_Spinner = (Spinner) findViewById(R.id.SpinnerCountryActivity_country_spinner);
        state_Spinner = (Spinner) findViewById(R.id.SpinnerCountryActivity_state_spinner);
        city_Spinner = (Spinner) findViewById(R.id.SpinnerCountryActivity_city_spinner);

        countries = new ArrayList<>();
        states = new ArrayList<>();
        cities = new ArrayList<>();

        createLists();

        countryArrayAdapter = new ArrayAdapter<Country>(getApplicationContext(), R.layout.simple_spinner_dropdown_item, countries);
        countryArrayAdapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item);
        country_Spinner.setAdapter(countryArrayAdapter);

        stateArrayAdapter = new ArrayAdapter<State>(getApplicationContext(), R.layout.simple_spinner_dropdown_item, states);
        stateArrayAdapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item);
        state_Spinner.setAdapter(stateArrayAdapter);

        cityArrayAdapter = new ArrayAdapter<City>(getApplicationContext(), R.layout.simple_spinner_dropdown_item, cities);
        cityArrayAdapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item);
        city_Spinner.setAdapter(cityArrayAdapter);

        country_Spinner.setOnItemSelectedListener(country_listener);
        state_Spinner.setOnItemSelectedListener(state_listener);
        city_Spinner.setOnItemSelectedListener(city_listener);

    }

    private AdapterView.OnItemSelectedListener country_listener = new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            if (position > 0) {
                final Country country = (Country) country_Spinner.getItemAtPosition(position);
                Log.d("SpinnerCountry", "onItemSelected: country: "+country.getCountryID());
                ArrayList<State> tempStates = new ArrayList<>();

                tempStates.add(new State(0, new Country(0, "Choose a Country"), "Choose a State"));

                for (State singleState : states) {
                    if (singleState.getCountry().getCountryID() == country.getCountryID()) {
                        tempStates.add(singleState);
                    }
                }

                stateArrayAdapter = new ArrayAdapter<State>(getApplicationContext(), R.layout.simple_spinner_dropdown_item, tempStates);
                stateArrayAdapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item);
                state_Spinner.setAdapter(stateArrayAdapter);
            }

            cityArrayAdapter = new ArrayAdapter<City>(getApplicationContext(), R.layout.simple_spinner_dropdown_item, new ArrayList<City>());
            cityArrayAdapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item);
            city_Spinner.setAdapter(cityArrayAdapter);
        }

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

        }
    };

    private AdapterView.OnItemSelectedListener state_listener = new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            if (position > 0) {
                final State state = (State) state_Spinner.getItemAtPosition(position);
                Log.d("SpinnerCountry", "onItemSelected: state: "+state.getStateID());
                ArrayList<City> tempCities = new ArrayList<>();

                Country country = new Country(0, "Choose a Country");
                State firstState = new State(0, country, "Choose a State");
                tempCities.add(new City(0, country, firstState, "Choose a City"));

                for (City singleCity : cities) {
                    if (singleCity.getState().getStateID() == state.getStateID()) {
                        tempCities.add(singleCity);
                    }
                }

                cityArrayAdapter = new ArrayAdapter<City>(getApplicationContext(), R.layout.simple_spinner_dropdown_item, tempCities);
                cityArrayAdapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item);
                city_Spinner.setAdapter(cityArrayAdapter);
            }
        }

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

        }
    };

    private AdapterView.OnItemSelectedListener city_listener = new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

        }

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

        }
    };

    private void createLists() {
        Country country0 = new Country(0, "Choose a Country");
        Country country1 = new Country(1, "Country1");
        Country country2 = new Country(2, "Country2");

        countries.add(new Country(0, "Choose a Country"));
        countries.add(new Country(1, "Country1"));
        countries.add(new Country(2, "Country2"));

        State state0 = new State(0, country0, "Choose a Country");
        State state1 = new State(1, country1, "state1");
        State state2 = new State(2, country1, "state2");
        State state3 = new State(3, country2, "state3");
        State state4 = new State(4, country2, "state4");

        states.add(state0);
        states.add(state1);
        states.add(state2);
        states.add(state3);
        states.add(state4);

        cities.add(new City(0, country0, state0, "Choose a City"));
        cities.add(new City(1, country1, state1, "City1"));
        cities.add(new City(2, country1, state1, "City2"));
        cities.add(new City(3, country1, state2, "City3"));
        cities.add(new City(4, country2, state2, "City4"));
        cities.add(new City(5, country2, state3, "City5"));
        cities.add(new City(6, country2, state3, "City6"));
        cities.add(new City(7, country2, state4, "City7"));
        cities.add(new City(8, country1, state4, "City8"));
    }

    private class Country implements Comparable<Country> {

        private int countryID;
        private String countryName;


        public Country(int countryID, String countryName) {
            this.countryID = countryID;
            this.countryName = countryName;
        }

        public int getCountryID() {
            return countryID;
        }

        public String getCountryName() {
            return countryName;
        }

        @Override
        public String toString() {
            return countryName;
        }


        @Override
        public int compareTo(Country another) {
            return this.getCountryID() - another.getCountryID();//ascending order
//            return another.getCountryID()-this.getCountryID();//descending  order
        }
    }

    private class State implements Comparable<State> {

        private int stateID;
        private Country country;
        private String stateName;

        public State(int stateID, Country country, String stateName) {
            this.stateID = stateID;
            this.country = country;
            this.stateName = stateName;
        }

        public int getStateID() {
            return stateID;
        }

        public Country getCountry() {
            return country;
        }

        public String getStateName() {
            return stateName;
        }

        @Override
        public String toString() {
            return stateName;
        }

        @Override
        public int compareTo(State another) {
            return this.getStateID() - another.getStateID();//ascending order
//            return another.getStateID()-this.getStateID();//descending order
        }
    }

    private class City implements Comparable<City> {

        private int cityID;
        private Country country;
        private State state;
        private String cityName;

        public City(int cityID, Country country, State state, String cityName) {
            this.cityID = cityID;
            this.country = country;
            this.state = state;
            this.cityName = cityName;
        }

        public int getCityID() {
            return cityID;
        }

        public Country getCountry() {
            return country;
        }

        public State getState() {
            return state;
        }

        public String getCityName() {
            return cityName;
        }

        @Override
        public String toString() {
            return cityName;
        }

        @Override
        public int compareTo(City another) {
            return this.cityID - another.getCityID();//ascending order
//            return another.getCityID() - this.cityID;//descending order
        }
    }
}

This code uses three Data Model classes Country, State and City all of them implement Comparable<T> so that their instance can be sorted with respect to their ids in a List, You may want to use Comprator<T> here to sort by the alphabetical order.

I have used AdapterView.OnItemSelectedListener to track the changes in the Spinner widget that subsequent spinner adapter can be changed.

I have added some test data to demonstrate how code works

Country              Country1                   Country2  
                  ______|_____                 _____|_________
                  |           |               |               |
State          state1       state2         state3          state4
               __|___       ___|___        __|___          __|____
               |    |       |     |        |    |          |     |
City        city1 city2   city3 city4   city5 city6      city7 city8 

enter image description here

like image 110
Pankaj Nimgade Avatar answered Sep 30 '22 10:09

Pankaj Nimgade


Try this way it will work

string.xml

<resources>



    <string name="app_name">Spinner</string>

    <string name="hello_world">Hello world!</string>

    <string name="title_activity_main">MainActivity</string>



    <string-array name="country_array">

    <item>India</item>

    <item>Pakisthan</item>

    <item>Sri Lanka</item>

    </string-array>

    <string-array name="city_india">

    <item>Mumbai</item>

    <item>Chennai</item>

    <item>Kolkata</item>

    <item>Bangalore</item>

    </string-array>

    <string-array name="city_pakisthan">

    <item>Karachi</item>

    <item>Lahore</item>

    <item>Faisalabad</item>

    <item>Rawalpindi</item>

    </string-array>

    <string-array name="city_srilanka">

    <item>Colombo</item>

    <item>Dehiwala-Mount Lavinia</item>

    <item>Moratuwa</item>

    <item>Kotte</item>

    </string-array>

    </resources>

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:gravity="left" >



<TextView

android:id="@+id/textView"

android:layout_width="130dp"

android:layout_height="50dp"

android:layout_alignParentTop="true"

android:layout_centerHorizontal="true"

android:layout_marginTop="15dp"

android:gravity="center"

android:text="Select County and City"

android:textSize="15dp"

/>



<Spinner

android:id="@+id/spinnerCountry"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_below="@+id/textView"

android:layout_centerHorizontal="true"

android:layout_marginTop="28dp"

android:entries="@array/country_array" />



<Spinner

android:id="@+id/spinnerCity"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_alignLeft="@+id/spinnerCountry"

android:layout_below="@+id/spinnerCountry"

android:layout_marginTop="42dp"

android:entries="@array/city_india" />



</RelativeLayout>

MainActivity.java

import android.app.Activity;

    import android.os.Bundle;

    import android.view.View;

    import android.widget.AdapterView;

    import android.widget.AdapterView.OnItemSelectedListener;

    import android.widget.ArrayAdapter;

    import android.widget.Spinner;



    public class MainActivity extends Activity implements OnItemSelectedListener {



     Spinner spinnerCountry, spinnerCity;



     @Override

     protected void onCreate(Bundle savedInstanceState) {

      super.onCreate(savedInstanceState);

      setContentView(R.layout.activity_main);

      spinnerCountry = (Spinner) findViewById(R.id.spinnerCountry);

      spinnerCity = (Spinner) findViewById(R.id.spinnerCity);

      spinnerCountry.setOnItemSelectedListener(this);

     }



     @Override

     public void onItemSelected(AdapterView<?> parent, View arg1, int pos,

       long arg3) {

      parent.getItemAtPosition(pos);

      if (pos == 0) {

       ArrayAdapter<CharSequence> adapter = ArrayAdapter

         .createFromResource(this, R.array.city_india,

           android.R.layout.simple_spinner_item);

       spinnerCity.setAdapter(adapter);

      } else if (pos == 1) {

       ArrayAdapter<CharSequence> adapter = ArrayAdapter

         .createFromResource(this, R.array.city_pakisthan,

           android.R.layout.simple_spinner_item);

       spinnerCity.setAdapter(adapter);

      } else if (pos == 2) {

       ArrayAdapter<CharSequence> adapter = ArrayAdapter

    .createFromResource(this, R.array.city_srilanka,

           android.R.layout.simple_spinner_item);

       spinnerCity.setAdapter(adapter);

      }

     }



     @Override

     public void onNothingSelected(AdapterView<?> arg0) {

     }

    }
like image 37
Aditya Vyas-Lakhan Avatar answered Sep 30 '22 12:09

Aditya Vyas-Lakhan