I have a Spinner on my Activity. I use an ArrayList and a custom SpinnerAdapter to populate the list that pops up when the Spinner is pressed.
My problem is the way the Spinner looks on the Activity when it is not pressed. It is all gray. No text is visible. Even after I press the spinner and then choose an item from the resulting list, the Spinner does not populate with text.
Also, when I select an item from the Spinner and then print the selected item position, it prints -1. Many have commented that there is no list of data attached to my spinner, but there obviously is. How else could I press on the Spinner and then choose from a resulting list?
// This sets up the adapter and the arraylist that contains the data
private void setUpAdapter() {
mData = new ArrayList<MyData>();
mAdapter = new MyAdapter(mData);
mSpinner.setAdapter(mAdapter);
mSpinner.setOnItemSelectedListener(new Spinner.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent,
View view, int pos, long id) {
MyData g = (MyData) parent.getItemAtPosition(pos);
// TODO
}
public void onNothingSelected(AdapterView parent) {
// Do nothing.
}
});
}
// this populates the arraylist that is attached to the spinner's adapter
// it is called once an AsyncTask finishes pulling data from a local database
private void populateSpinner(ArrayList<MyData> result) {
if (result != null) {
if (mData == null) {
mData = new ArrayList<MyData>();
}
else {
mData.clear();
}
for (int index = 0; index < result.size(); index++) {
mData.add(result.get(index));
}
mSpinner.setSelected(0);
}
}
// this is the adapter for the spinner
private class MyAdapter implements SpinnerAdapter {
ArrayList<MyData> data;
public MyAdapter(ArrayList<MyData> data){
this.data = data;
}
#Override
public int getCount() {
return data.size();
}
#Override
public Object getItem(int position) {
return data.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return android.R.layout.simple_spinner_dropdown_item;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView v = new TextView(getApplicationContext());
v.setTextColor(Color.BLACK);
v.setText(data.get(position).getName());
v.setPadding(0, 20, 0, 20);
return v;
}
#Override
public int getViewTypeCount() {
return 1;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public boolean isEmpty() {
return false;
}
#Override
public void registerDataSetObserver(DataSetObserver observer) {
// TODO Auto-generated method stub
}
#Override
public void unregisterDataSetObserver(DataSetObserver observer) {
// TODO Auto-generated method stub
}
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return this.getView(position, convertView, parent);
}
}
<Spinner
android:id="#+id/my_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
When I select an item from the Spinner and then print the selected item position, it prints -1
This is because you are referencing BLANK list
mData = new ArrayList<MyData>();
mAdapter = new MyAdapter(mData);
mSpinner.setAdapter(mAdapter);
Set spinner adapter in onPostExecute() of AsynTask.
#Override
protected void onPreExecute() {
mData = new ArrayList<MyData>();
super.onPreExecute();
}
#Override
protected Void doInBackground(String... params) {
//gets "result" to fill mData
return null;
}
#Override
protected void onPostExecute(Void result) {
setUpAdapter();
}
private void setUpAdapter() {
if (result != null) {
if (mData == null) {
mData = new ArrayList<MyData>();
}
else {
mData.clear();
}
for (int index = 0; index < result.size(); index++) {
mData.add(result.get(index));
}
mAdapter = new MyAdapter(mData);
mSpinner.setAdapter(mAdapter);
mSpinner.setSelected(0);
mSpinner.setOnItemSelectedListener(new Spinner.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent,
View view, int pos, long id) {
MyData g = (MyData) parent.getItemAtPosition(pos);
// TODO
}
public void onNothingSelected(AdapterView parent) {
// Do nothing.
}
});
}
Use Activity context instead of the Application context for your spinner. See documentation of getApplicationContext() api to understand its proper usage.
Pass the activity context to MyAdapter and use it in creating the TextView's in getView callback.
mAdapter = new MyAdapter(mData, this); // this is activity context.
In MyAdapter :
public MyAdapter(ArrayList<MyData> data, Context context){
this.data = data;
mContext = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView v = new TextView(mContext);
v.setTextColor(Color.BLACK);
v.setBackgroundColor(Color.WHITE);
v.setText(data.get(position).getName());
v.setPadding(0, 20, 0, 20);
return v;
}
You can set static sizes using the xml attribute android:layout_height.
Using dp unit instead of px is recommended for multiple screen compatibility.
As for the text, try to use android:prompt attribute in your Spinner xml. For the color I'm guessing it's like other widgets, just use android:textColor
THIS code is WORKING, the spinner correctly display the field, however i must say maybe it is not 100% perfect, cause for some reason im unable to leave blank the initial value of the field, it has by default the value of item 0.
package com.cccheck;
public class OneCheckActivity extends Activity {
LayoutInflater factory;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.spinner_view);
ArrayList tdata = new ArrayList<MyData>();
MyData mdata =new MyData();
mdata.setName("");
mdata.setData("-1");
MyData ndata =new MyData();
ndata.setName("ciao belluzzo");
ndata.setData("1");
tdata.add(mdata);
tdata.add(ndata);
mdata= new MyData();
mdata.setName("vai alla fnac");
mdata.setData("2");
tdata.add(mdata);
mSpinner = (Spinner) findViewById(R.id.my_spinner);
factory = LayoutInflater.from(this);
populateSpinner(tdata);
setUpAdapter();
mSpinner.setSelected(false);
try {
mAdapter.notify();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//mAdapter.registerDataSetObserver(new MyObserver());
}
ArrayList<MyData> mData;
MyAdapter mAdapter = new MyAdapter(null);
Spinner mSpinner;
// This sets up the adapter and the arraylist that contains the data
private void setUpAdapter() {
mSpinner.setOnItemSelectedListener(new Spinner.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent,
View view, int pos, long id) {
MyData g = (MyData) parent.getItemAtPosition(pos);
// TODO
Toast.makeText(OneCheckActivity.this , "selected item : " + pos + ", value: " + g.getData(),Toast.LENGTH_LONG).show();
}
#Override
public void onNothingSelected(AdapterView parent) {
// Do nothing.
}
});
}
// this populates the arraylist that is attached to the spinner's adapter
//it is called once an AsyncTask finishes pulling data from a local database
private void populateSpinner(ArrayList<MyData> result) {
if (result != null) {
if (mData == null) {
mData = new ArrayList<MyData>();
}
else {
mData.clear();
}
for (int index = 0; index < result.size(); index++) {
mData.add(result.get(index));
}
mAdapter = new MyAdapter(mData);
mSpinner.setAdapter(mAdapter);
}
}
// this is the adapter for the spinner
private class MyAdapter implements SpinnerAdapter {
ArrayList<MyData> data;
public MyAdapter(ArrayList<MyData> data){
this.data = data;
}
public void updateData(ArrayList<MyData> data){
this.data = data;
}
#Override
public int getCount() {
return data.size();
}
#Override
public Object getItem(int position) {
return data.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return android.R.layout.simple_spinner_dropdown_item;
}
#Override
public LinearLayout getView(int position, View convertView, ViewGroup parent) {
LinearLayout pv = (LinearLayout)(factory.inflate(R.layout.spinner_item, null));
TextView tv = (TextView) pv.findViewById(R.id.textviewid);
tv.setTextColor(Color.BLACK);
MyData item = data.get(position);
tv.setText( item.getName() + " - " + item.getData() + " ");
tv.setPadding(0, 20, 0, 20);
return pv;
}
#Override
public int getViewTypeCount() {
return 1;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public boolean isEmpty() {
return data.isEmpty();
}
#Override
public void registerDataSetObserver(DataSetObserver observer) {
// TODO Auto-generated method stub
}
#Override
public void unregisterDataSetObserver(DataSetObserver observer) {
// TODO Auto-generated method stub
}
#Override
public LinearLayout getDropDownView(int position, View convertView, ViewGroup parent) {
if (convertView instanceof LinearLayout) System.out.println("%%%%%%%%%%%%%%55555 hai ragione");
return this.getView(position, convertView, parent);
}
}
}
use this as layout for spinner_item.xml
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="28px"
android:id="#+id/textviewid"
/>
</LinearLayout>
Related
I have a listView with n number of rows each row contains textview1(for text), textview2(For id) and spinner. I want to select spinner in multiple rows. Here the problem is once i scroll the listView the selection is gone (Recycle listView).
I have store the id in a ArrayList(Which rows spinner selected) and selected position of the spinner. In onScroll method of listView i try to use spinner.setSelection(position); but it won't work.
My sample image
And my source code:
level2.setOnScrollListener(new OnScrollListener() {
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
}
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
for (int i = 0; i < level2.getChildCount(); i++) {
RelativeLayout relative_layout = (RelativeLayout)level2.getChildAt(i);
TextView textview_1 = (TextView)relative_layout.getChildAt(0);
TextView textview_2 = (TextView)relative_layout.getChildAt(1);
Spinner spinner = (Spinner)relative_layout.getChildAt(2);
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView < ? > arg0,
View arg1, int arg2, long arg3) {
//save my id and spinner selection here in a ArrayList
//Here the position is get value from arraylist
spinner.setSelection(position);
}
public void onNothingSelected(AdapterView < ? > arg0) {
// TODO Auto-generated method stub
}
});
}
}
});
It is not complete code it's just piece. Please help me.
Here if u want to set the selected item then you have to use code spinner.setSelection(arg2);, As you have not initialised your position variable and its default value will be 0 , so it would always show the 1st item selected.
I'll solve like this.Try this. This is just example Activity.
public class MainActivity extends Activity {
SpinnerAdapter ratingAdapter;
ListView listView;
List<String> listString;
ArrayAdapter<String> dataAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listString = new ArrayList<String>();
for(int listCount = 0; listCount < 20 ; listCount++){
listString.add("ListCount"+listCount);
}
List<String> spinnerData = new ArrayList<String>();
for (int i = 0; i < listString.size(); i++) {
spinnerData.add("MyTest="+i);
}
dataAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_expandable_list_item_1, spinnerData);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
fillAdapter();
}
private void fillAdapter() {
ratingAdapter = new SpinnerAdapter(getApplicationContext());
listView = (ListView) findViewById(R.id.listView1);
listView.setAdapter(ratingAdapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
class ViewHolder {
Spinner spinner;
}
class SpinnerAdapter extends ArrayAdapter {
Context context;
HashMap<Integer,Integer> selectedItems = new HashMap<Integer, Integer>();
public SpinnerAdapter(Context context) {
super(context, R.layout.item_list_spinner_adaoter, listString);
this.context = context;
}
public int getCount() {
return listString.size();
}
public Object getItem(int position) {
return listString.get(position);
}
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = LayoutInflater.from(context).inflate(R.layout.item_list_spinner_adaoter, null);
holder.spinner = (Spinner) convertView.findViewById(R.id.spinner1);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.spinner.setAdapter(dataAdapter);
if ( selectedItems.get( position ) != null ) {
holder.spinner.setSelection( selectedItems.get( position ) );
}
holder.spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
selectedItems.put( position, arg2 );
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
});
return convertView;
}
}
}
In activity_main.xml:
<ListView
android:id="#+id/listView1"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:stackFromBottom="false"
android:transcriptMode="disabled" >
</ListView>
</LinearLayout>
In item_list_spinner_adaoter.xml:
<Spinner
android:id="#+id/spinner1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
I want to make a listview item selected and the text "select" to be made to "selected", but when i click an item mutiple items get selected if I select an item at position 0 , items get selected at at a pattern, that is 0,7,14,21 and if i change the view to landscape: it will be 0 ,5,10,15, etc.
my main activity is:
public class two extends Activity implements OnQueryTextListener,OnItemClickListener {
GroupAdapter grpAdapter;
public static ArrayList<GroupsModel> arrayOfList;
public static ListView listView;
public static String base_url = "myurl";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.two);
arrayOfList = new ArrayList<GroupsModel>();
listView = (ListView) findViewById(R.id.group_listview);
listView.setOnItemClickListener(this);
listView.setTextFilterEnabled(true);
new ProgressTask(two.this).execute();
}
private class ProgressTask extends AsyncTask<String, Void, Boolean> {
private ProgressDialog dialog;
#SuppressWarnings("unused")
private two activity;
public ProgressTask(two two) {
this.activity = two;
context = two;
dialog = new ProgressDialog(context);
}
private Context context;
protected void onPreExecute() {
this.dialog.setMessage("Progress start");
this.dialog.show();
}
#Override
protected void onPostExecute(final Boolean success) {
if (dialog.isShowing()) {
dialog.dismiss();
}
grpAdapter = new GroupAdapter(two.this, R.layout.two_row,arrayOfList);
listView.setAdapter(grpAdapter);
}
protected Boolean doInBackground(final String... args) {
//arrayOfList = new ArrayList<GroupsModel>();
List<NameValuePair> params = new ArrayList<NameValuePair>();
//params.add(new BasicNameValuePair("",""));
JSONParser jp = new JSONParser();
JSONArray groups_obj = jp.makeHttpRequest(base_url + "groups/all", "GET", params);
for (int i = 0; i < groups_obj.length(); i++) {
GroupsModel group = new GroupsModel();
try {
JSONObject grp = groups_obj.getJSONObject(i);
group.setGroupId(grp.getInt("id"));
group.setGroupname(grp.getString("name"));
arrayOfList.add(group);
}
catch (JSONException e) {
e.printStackTrace();
}
}
return null;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
SearchManager searchManager = (SearchManager) getSystemService( Context.SEARCH_SERVICE );
SearchView searchView = (SearchView) menu.findItem(R.id.menu_item_search).getActionView();
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
searchView.setSubmitButtonEnabled(false);
searchView.setOnQueryTextListener(this);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onQueryTextChange(String newText)
{
// this is your adapter that will be filtered
if (TextUtils.isEmpty(newText))
{
listView.clearTextFilter();
}
grpAdapter.getFilter().filter(newText.toString());
return true;
}
#Override
public boolean onQueryTextSubmit(String query) {
// TODO Auto-generated method stub
return false;
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
// TODO Auto-generated method stub
view.setBackgroundColor(Color.CYAN);
}}
My adapter is:
public class GroupAdapter extends ArrayAdapter<GroupsModel> implements Filterable{
private Context activity;
private ArrayList<GroupsModel> items ;
private List<GroupsModel> arrayList;
private ArrayFilter mFilter;
private int resource;
public GroupAdapter(Activity act, int resource, ArrayList<GroupsModel> arrayList) {
super(act, resource, arrayList);
this.activity = act;
this.resource = resource;
this.items = new ArrayList<GroupsModel>();
this.items.addAll(arrayList);
this.arrayList = new ArrayList<GroupsModel>();
this.arrayList.addAll(arrayList);
}
public View getView(final int position, View convertView,final ViewGroup parent) {
final ViewHolder holder;
LayoutInflater inflater = ((Activity) activity).getLayoutInflater();
if (convertView == null) {
convertView = inflater.inflate(resource,parent, false);
holder = new ViewHolder();
holder.group_name = (TextView) convertView.findViewById(R.id.group_name);
holder.select = (TextView) convertView.findViewById(R.id.select);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
try{
GroupsModel groups = items.get(position);
holder.group_name.setText(groups.getGroupName());
}catch(Exception e){
e.printStackTrace();
}
holder.select.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
// TODO Auto-generated method stub
holder.select.setText("my new text");
}
});
return convertView;
}
public class ViewHolder {
public TextView group_name,select;
}
#Override
public int getCount() {
// Total count includes list items and ads.
return items.size();
}
#Override
public GroupsModel getItem(int position)
{
// TODO Auto-generated method stub
return items.get(position);
}
#Override
public long getItemId(int position)
{
// TODO Auto-generated method stub
return position;
}
#Override
public Filter getFilter() {
if (mFilter == null) {
mFilter = new ArrayFilter();
}
return mFilter;
}
private class ArrayFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence prefix) {
FilterResults results = new FilterResults();
if (arrayList == null) {
synchronized (this) {
arrayList = new ArrayList<GroupsModel>(items);
}
}
if (prefix == null || prefix.length() == 0) {
ArrayList<GroupsModel> list;
synchronized (this) {
list = new ArrayList<GroupsModel>(arrayList);
}
results.values = list;
results.count = list.size();
} else {
String prefixString = prefix.toString().toLowerCase();
ArrayList<GroupsModel> values;
synchronized (this) {
values = new ArrayList<GroupsModel>(arrayList);
}
final int count = values.size();
final ArrayList<GroupsModel> newValues = new ArrayList<GroupsModel>();
for (int i = 0; i < count; i++) {
final String value = values.get(i).getGroupName();
final String valueText = value.toLowerCase();
// First match against the whole, non-splitted value
if (valueText.startsWith(prefixString)) {
newValues.add(values.get(i));
} else {
final String[] words = valueText.split(" ");
final int wordCount = words.length;
// Start at index 0, in case valueText starts with space(s)
for (int k = 0; k < wordCount; k++) {
if (words[k].startsWith(prefixString)) {
newValues.add(values.get(i));
break;
}
}
}
}
results.values = newValues;
results.count = newValues.size();
}
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
items = (ArrayList<GroupsModel>) results.values;
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}}
I cant figure this out. Please help
You need to maintain the selected item in adapter and use it to change the text :
Adapter Code
private int selectedIndex;
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
final ViewHolder holder;
LayoutInflater inflater = ((Activity) activity).getLayoutInflater();
if (convertView == null) {
convertView = inflater.inflate(resource,parent, false);
holder = new ViewHolder();
holder.group_name = (TextView) convertView.findViewById(R.id.group_name);
holder.select = (TextView) convertView.findViewById(R.id.select);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if(selectedIndex!= -1 && position == selectedIndex)
{
convert_view.setBackgroundColor(Color.CYAN);
holder.select.setText("selected");
}
else
{
convert_vie.wsetBackgroundColor(default_color);
holder.select.setText("Select");
}
//Your other code .....
return convertView ;
}
public void setSelectedIndex(position)
{
selectedIndex = position;
}
Now set the selectedIndex variable when a list item clicked.
public class MainActivity extends Activity implements OnItemClickListener
{
// Implemented onItemClickListener
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
adapter.setSelectedIndex(position);
}
}
You can add a member "checked" in GroupsModel, and initial it assign false;
In activity
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
final boolean isChecked = listView.getItem(position).isChecked();
listView.get(position).setChecked(!isChecked);
}
In getView() in adapter:
public View getView(...) {
...
if(getItem(position).isChecked()) {
// You must set root view in holder
holder.getBackground().setBackgroundColor(Color.CYAN);
}
...
}
Your problem is that Android is reusing your views, so when you scroll, the first view disappears and appears at the bottom with the same state.
What you need to do is everytime you check an item, you need to store de id/position of the item checked (maybe ArrayList<Integer>), this way everytime your getView method is getting called you will look at this class/structure you have created and see it the row needs to be checked or not.
Note: If the row is not checked you will have to call to myCheck->setChecked(false); in order to assure that the row is in a coherent state.
You must use a array or option object to record which position is selected.
And detect the array or option object in getView() in adapter.
So, your need move the code: "view.setBackgroundColor(Color.CYAN)" to getView() method.
You have been bitten by what they say "recycling" issues.
When re-using your views, this kind of problems happens.
There are several methods(for example saving checked positions in an arraylist, ...) to deal with it, but in my opinion the simplest and straight forward solution is using tags.
setTag() and getTag()
Here is a tutorial using it.
Hope it helps.
I have registration form and it has two edittexts and one spinner with adapter for gender selection and value from array, when I click register button and select a gender it's going successfully, but when I don't select a gender and click register button it get force close ?
here is my complete code ....
MainActivity
EditText Fullname, Email;
Spinner GenderSpinner;
Button btnReg;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Importing all assets like buttons, text fields
Fullname = (EditText) findViewById(R.id.full_name);
Email = (EditText) findViewById(R.id.Email);
// Gender = (EditText) findViewById(R.id.Gender);
GenderSpinner = (Spinner) findViewById(R.id.Gender);
ArrayAdapter<CharSequence> GenderAdapter = ArrayAdapter
.createFromResource(this, R.array.sex,
android.R.layout.simple_spinner_item);
GenderAdapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
GenderSpinner.setPrompt("SELECT YOUR GENDER");
GenderSpinner.setAdapter(new NothingSelectedSpinnerAdapter(
GenderAdapter, R.layout.gender_nothing_selected, MainActivity.this));
btnReg = (Button) findViewById(R.id.btnReg);
btnReg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
// Read EditText dat
String fullname = Fullname.getText().toString();
String email = Email.getText().toString();
String gender = GenderSpinner.getSelectedItem().toString();
}
});
}
}
NothingSelectedSpinnerAdapter
protected static final int EXTRA = 1;
protected SpinnerAdapter adapter;
protected Context context;
protected int nothingSelectedLayout;
protected int nothingSelectedDropdownLayout;
protected LayoutInflater layoutInflater;
public NothingSelectedSpinnerAdapter(SpinnerAdapter spinnerAdapter,
int nothingSelectedLayout, Context context) {
this(spinnerAdapter, nothingSelectedLayout, -1, context);
}
public NothingSelectedSpinnerAdapter(SpinnerAdapter spinnerAdapter,
int nothingSelectedLayout, int nothingSelectedDropdownLayout,
Context context) {
this.adapter = spinnerAdapter;
this.context = context;
this.nothingSelectedLayout = nothingSelectedLayout;
this.nothingSelectedDropdownLayout = nothingSelectedDropdownLayout;
layoutInflater = LayoutInflater.from(context);
}
#Override
public final View getView(int position, View convertView, ViewGroup parent) {
if (position == 0) {
return getNothingSelectedView(parent);
}
return adapter.getView(position - EXTRA, null, parent);
}
protected View getNothingSelectedView(ViewGroup parent) {
return layoutInflater.inflate(nothingSelectedLayout, parent, false);
}
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
// BUG! Vote to fix!!
// http://code.google.com/p/android/issues/detail?id=17128 - Spinner
// does not support multiple view types
if (position == 0) {
return nothingSelectedDropdownLayout == -1 ? new View(context)
: getNothingSelectedDropdownView(parent);
}
return adapter.getDropDownView(position - EXTRA, null, parent); // could
}
protected View getNothingSelectedDropdownView(ViewGroup parent) {
return layoutInflater.inflate(nothingSelectedDropdownLayout, parent,
false);
}
#Override
public int getCount() {
int count = adapter.getCount();
return count == 0 ? 0 : count + EXTRA;
}
#Override
public Object getItem(int position) {
return position == 0 ? null : adapter.getItem(position - EXTRA);
}
#Override
public int getItemViewType(int position) {
return position == 0 ? getViewTypeCount() - EXTRA : adapter
.getItemViewType(position - EXTRA);
}
#Override
public int getViewTypeCount() {
return adapter.getViewTypeCount() + EXTRA;
}
#Override
public long getItemId(int position) {
return adapter.getItemId(position - EXTRA);
}
#Override
public boolean hasStableIds() {
return adapter.hasStableIds();
}
#Override
public boolean isEmpty() {
return adapter.isEmpty();
}
#Override
public void registerDataSetObserver(DataSetObserver observer) {
adapter.registerDataSetObserver(observer);
}
#Override
public void unregisterDataSetObserver(DataSetObserver observer) {
adapter.unregisterDataSetObserver(observer);
}
#Override
public boolean areAllItemsEnabled() {
return false;
}
#Override
public boolean isEnabled(int position) {
return position == 0 ? false : true; // don't allow the 'nothing
}
}
It looks like you are getting null here
String gender = GenderSpinner.getSelectedItem().toString();
because nothing has been selected so GenderSpinner.geSelecetedItem() is null when you try to call toString() on it. You could set a selected item as the default item or if you want to force the user to choose an item then you can just check for null here when running this code and if it is then display a message to the user to choose a gender.
If you go with the second option then you may consider using RadioButtons as it will be more natural for the user or use a text hint as the default value of the Spinner with a message of something like "Please choose a gender"
I'm trying to implement a simple android REST Client and i having some problems understanding how to pass data between my activities.
I have this ListActivity (I'm using the Spring REST Template) :
public class MainActivity extends ListActivity
{
protected static final String TAG = MainActivity.class.getSimpleName();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Toast.makeText(this, "You have selected" + position + id ,
Toast.LENGTH_SHORT).show();
}
#Override
protected void onStart() {
super.onStart();
new DownloadClientesTask().execute();
}
private void refreshClientes(List<Cliente> clientes) {
if (clientes == null) {
return;
}
ClientesListAdapter adapter = new ClientesListAdapter(this, clientes);
setListAdapter(adapter);
}
private class DownloadClientesTask extends AsyncTask<Void, Void, List<Cliente>> {
#Override
protected List<Cliente> doInBackground(Void... params) {
final String url = "http://192.168.1.119/~henry/api_slim/index.php/customers";
try {
// Set the Accept header for "application/json"
HttpHeaders requestHeaders = new HttpHeaders();
List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>();
acceptableMediaTypes.add(MediaType.APPLICATION_JSON);
requestHeaders.setAccept(acceptableMediaTypes);
// Populate the headers in an HttpEntity object to use for the request
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);
// Create a new RestTemplate instance
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJacksonHttpMessageConverter());
// Perform the HTTP GET request
ResponseEntity<Cliente[]> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity,
Cliente[].class);
// convert the array to a list and return it
return Arrays.asList(responseEntity.getBody());
} catch (Exception e) {
// TODO Auto-generated catch block
Log.e(TAG, e.getMessage(), e);
}
return null;
}
#Override
protected void onPostExecute(List<Cliente> result) {
refreshClientes(result);
}
}
}
And this is My listAdapter :
public class ClientesListAdapter extends BaseAdapter{
private List<Cliente> clientes;
private final LayoutInflater layoutInflater;
public ClientesListAdapter(Context context, List<Cliente> clientes) {
this.clientes = clientes;
this.layoutInflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return this.clientes != null ? clientes.size() : 0;
}
#Override
public Cliente getItem(int position) {
return this.clientes.get(position);
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = this.layoutInflater.inflate(R.layout.cliente_list_item, parent, false);
}
Cliente cliente = getItem(position);
if (cliente != null) {
TextView t = (TextView) convertView.findViewById(R.id.name);
t.setText(cliente.getFirstname());
}
return convertView;
}
}
This the POJO class of the data iḿ getting :
public class Cliente {
private Integer id_customer;
private String firstname;
public Integer getId_customer() {
return id_customer;
}
public void setId_customer(Integer id_customer) {
this.id_customer = id_customer;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
}
When i select an element from the listView i would like show details specific about this element on another activity or fragment, but i don't know how to obtain the customer_id of this element from the list, do i have to save it when i procesing the response? do I need to use content provider or database provide this behavior? i'm really confused, thanks in advance for any help!
There are good examples on how to pass data from one activity to another here, pass objects between activities. You may want to take a look first to the solutions on those links.
Please see below an example that can put you on the right track.
List adapter class:
public class ClientesListAdapter extends BaseAdapter{
//private members
private List<Cliente> clientes;
//adapter position - not used for this example
public int adapterPosition;
//context of app
private Context mContext;
//default constructor
public ClientesListAdapter(Context context, List<Cliente> clientes) {
//context pointer
this.mContext = context;
//alloc
this.clientes = new ArrayList<Cliente>(clientes.size());
this.clientes.addAll(clients);
}
//Holder for events and dates (memory management)
public static class ViewHolder{
TextView myTextView;//this is actually findViewById(R.id.name) #see getView() method
}
//generated method
#Override
public int getCount() {
// TODO Auto-generated method stub
return this.clientes != null ? clientes.size() : 0;
}
//generated method
#Override
public Cliente getItem(int position) {
return this.clientes.get(position);
}
//generated method
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
//get client's id
public int getClienteId(int position){
return this.clientes.get(position).getClienteId();
}
//get client's id without passing the position
public int getClienteId(){
return this.clientes.get(adapterPosition).getClienteId();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//row is actually convertView (the current view)
View row = convertView;
//holds our view elements
ViewHolder holder;
//if row is null
if(row == null){
//inflate layout to get our view elements
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(com.yourapp.R.layout.my_layout, parent, false);//your layout here, modify code
//set up the holder
holder = new ViewHolder();
holder.myTextView = (TextView) row.findViewById(com.yourapp.R.id.name);
//give the row a tag (holder)
row.setTag(holder);
}else{
//row is not null we can see it (no need to allocate memory)
holder = (ViewHolder) row.getTag();
}
//get your cliente object
Cliente cliente = this.clientes.get(position);
if (cliente != null) {
holder.myTextView.setText(cliente.getFirstname());
}
//copy position
adapterPostion = position;
return convertView;
}
}
You see that we used a ViewHolder class for memory management. This is a good practice for holding view elements inside your list adapter. You can find more info about list views, explained by Romain Guy - The World of ListViews.
From your MainActivity allocate the adapter and get your item on click:
//---- code --- //
ListView myListView = (ListView)findViewById(R.id.mylistview);//or you may use ListActivity
ClientesListAdapter adapter = new ClientesListAdapter(this, clientes);//"this" or "getApplicationContext()"
myListView.setAdapter(adapter);
adapter.notifyDataSetChanged();//notify
// ---- code --- //
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Toast.makeText(this, "You have selected" + position + id ,
Toast.LENGTH_SHORT).show();
Intent intent = new Intent(MyActivity.this, ActivityB.class);
intent.putInt("cliente_id",adapter.getClienteId());
startActivity(intent);
}
Another example is with implementing an interface in the adapter like this:
//--code//
//Interface method
private OnSaveEditsListener saveEditsListener = null;
public void setOnSaveEditsListener(OnSaveEditsListener l) {
saveEditsListener = l;
}
//--code//
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
//--code--//
//get clicked position of calendar (get clicked day)
convertView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
v.requestFocusFromTouch();
currentAgendaPosition = position;
try{
saveEditsListener.onSaveEdits();
}catch(Exception ex){
ex.printStackTrace();
}
}
});
//returns current row
return row;
}
//--code--//
And from your MainActivity start the second activity like this:
adapter.setOnSaveEditsListener(new OnSaveEditsListener() {
#Override
public void onSaveEdits() {
//Start activity from here
//--code--//
startActivity(intent);
}
});
get the position of the item clicked and get the object present at that position from the arraylist and use it to get the required details.
use
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Toast.makeText(this, "You have selected" + position + id ,
Toast.LENGTH_SHORT).show();
// use this.clientes.get(position) and pass it to the next activity or fragment using putextras to where you need to pass and display this in the destination end using the same object by getting it using getExtra()
}
Your list is in the adapter:
private List<Cliente> clientes;
In onListItemClick, you can get the Cliente from this list using the position parameter.
You pass information to another activity when you call startActivity, passing it an Intent. The Intent may have additional information, in your case you could set the customer_id as an int extra, something like:
intent.putExtra(EXTRA_CUSTOMER_ID, customer_id);
I have a very strange problem while using my ListView.
Only a part of my adapter items are renderd in the listview on screen but when I interact with the listview (ie tries to scroll it) all items are renderd properly.
This fenonemon only occurs if i have less items than the screen can show. Take a look at these screenshots below.
Before interaction:
After interaction:
Source code of activity where adding items:
String[] jRests = getResources().getStringArray(R.array.j_restaurants);
String[] lRests = getResources().getStringArray(R.array.l_restaurants);
items = new ArrayList<Object>();
items.add(getString(R.string.campus_j));
for(String item : jRests){
String[] val = item.split(",,,");
items.add(new FoodSectionListItem(new Restaurant(val[0], val[1], val[2], "")));
}
items.add(getString(R.string.campus_l));
for(String item : lRests){
String[] val = item.split(",,,");
items.add(new FoodSectionListItem(new Restaurant(val[0], val[1], val[2], "")));
}
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
adapter = new BaseSectionAdapter(this, R.layout.list_item_fragment_header);
if(!isTabletView()){
adapter.setSelectedItem(-1);
}
adapter.setItems(items);
Code of adapter:
public class BaseSectionAdapter extends AmazingAdapter {
private LayoutInflater inflater;
private int selectedItem = 0;
private List<Object> items;
private List<SectionItem> sections = new ArrayList<SectionItem>(10);
private List<Class> itemTypes = new ArrayList<Class>();
private List<Integer> sectionPositions = new ArrayList<Integer>();
private int listHeaderLayoutId;
private View headerView;
public static interface ISectionListItem {
public void setProps(View convertView, int position, int selectedItem);
public View getLayout(LayoutInflater inflater);
}
private class SectionItem implements Serializable {
private static final long serialVersionUID = -8930010937740160935L;
String text;
int position;
public SectionItem(String text, int position) {
this.text = text;
this.position = position;
}
}
public BaseSectionAdapter(Context context, int listHeaderLayoutId) {
this.listHeaderLayoutId = listHeaderLayoutId;
init(context);
}
public BaseSectionAdapter(Context context, int listHeaderLayoutId, List<Object> listItems) {
this.listHeaderLayoutId = listHeaderLayoutId;
init(context);
initListItems(listItems);
}
private void init(Context context) {
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void setSelectedItem(int position) {
selectedItem = position;
}
// public List<ListItem> getItems() {
// return items;
// }
private void initListItems(List<Object> itemList) {
int curSection = -1;
//int curPosition = 0;
//curSection = 0;
this.items = itemList;
itemTypes.clear();
sections.clear();
sectionPositions.clear();
int listSize = itemList.size();
for(int i = 0; i < listSize; i++){
Object currentItem = items.get(i);
if(currentItem instanceof String){
sections.add(new SectionItem((String) currentItem,i));
curSection++;
}
if(!itemTypes.contains(currentItem.getClass())){
itemTypes.add(currentItem.getClass());
}
sectionPositions.add(curSection);
}
Log.d("test", "No of items = "+items.size());
Log.d("test", "No of itemtypes = "+itemTypes.size());
Log.d("test", "View type count = "+getViewTypeCount());
}
public void setItems(List<Object> itemList) {
initListItems(itemList);
}
public int getCount() {
return items==null?0:items.size();
}
#Override
public int getViewTypeCount(){
return (itemTypes.size() == 0)?1:itemTypes.size();
}
#Override
public int getItemViewType(int position){
return itemTypes.indexOf(items.get(position).getClass());
}
#Override
public boolean isEnabled(int position){
return !(items.get(position) instanceof String || items.get(position) instanceof EmptySectionListItem);
}
#Override
public Object getItem(int position) {
return items.get(position);
}
public long getItemId(int position) {
return position;
}
#Override
protected void onNextPageRequested(int page) {
// TODO Auto-generated method stub
}
#Override
protected void bindSectionHeader(View view, int position,
boolean displaySectionHeader) {
// TextView lSectionTitle = (TextView) view
// .findViewById(R.id.txt_list_header);
// if (displaySectionHeader) {
// lSectionTitle.setVisibility(View.VISIBLE);
// lSectionTitle
// .setText(getSections()[getSectionForPosition(position)]);
// } else {
// lSectionTitle.setVisibility(View.GONE);
// }
}
#Override
public View getAmazingView(int position, View convertView, ViewGroup parent) {
Object curItemObject = items.get(position);
boolean isHeader = (curItemObject instanceof String);
if(convertView == null){
if(isHeader && headerView != null){
convertView = headerView;
}else if(isHeader){
convertView = inflater.inflate(listHeaderLayoutId, null);
headerView = convertView;
}else{
convertView = ((ISectionListItem) curItemObject).getLayout(inflater);
}
}
if(isHeader){
TextView header = ((TextView)convertView.findViewById(R.id.txt_list_header));
header.setText((String)curItemObject);
}else{
((ISectionListItem)curItemObject).setProps(convertView, position, selectedItem);
}
return convertView;
}
#Override
public void configurePinnedHeader(View header, int position, int alpha) {
TextView textView = ((TextView)header.findViewById(R.id.txt_list_header));
textView.setText(getSections()[getSectionForPosition(position)]);
}
#Override
public int getPositionForSection(int section) {
if(section >= sections.size()){
return 0;
}
return sections.get(section).position;
}
#Override
public int getSectionForPosition(int position) {
return sectionPositions.get(position);
}
#Override
public String[] getSections() {
String[] res = new String[sections.size()];
for (int i = 0; i < res.length; i++) {
res[i] = sections.get(i).text;
}
return res;
}
}
Code of layout:
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.HORIZONTAL);
FrameLayout listLayout = new FrameLayout(this);
LinearLayout.LayoutParams listParams = new LinearLayout.LayoutParams(0, FrameLayout.LayoutParams.MATCH_PARENT);
listParams.weight = 1;
listLayout.setId(LIST_FRAGMENT_VIEW_ID);
FrameLayout detailLayout = new FrameLayout(this);
LinearLayout.LayoutParams detailParams = new LinearLayout.LayoutParams(0, FrameLayout.LayoutParams.MATCH_PARENT);
detailParams.weight = 2;
detailLayout.setId(DETAIL_FRAGMENT_VIEW_ID);
layout.addView(listLayout, listParams);
layout.addView(detailLayout, detailParams);
if(savedInstanceState == null){
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(listLayout.getId(), (Fragment) listFragment, TWO_PANEL_LIST_FRAGMENT_TAG);
ft.add(detailLayout.getId(), detailFragment);
ft.commit();
}
setContentView(layout);
try calling notifyDataSetChanged() in runOnUIThread() method like I have shown below and it will work like a charm. :)
runOnUiThread(new Runnable() {
#Override
public void run() {
messageAdapter.notifyDataSetChanged();
}
});
i dont know what causes the problem, but if you don't find a logical solution to it you could try something like this:
trigger an onTouchEvent() programmatically whenever you launch the ListView.
scroll down and back up programmatically as soon as the ListView is launched.
etc..
Add ListView widget to layout.xml and add content of list to that. Do not use FrameLayout as it probably is the cause of the problem. It is updating content after touch so the Layout it is on is no implementing the correct onCreate() setup as the ListView widget has.
Are you calling the method notifyDataSetChanged() on your adapter after adding new items? This causes the listview to refresh its view when the underlying dataset is changed.
If it still doesn't work, try notifyDataSetInvalidated() that causes the listview to redraw completely.
Solved it!!!
Problem was with the adapter trying to reuse the same section item. Not good!!!
Changed it to inflate the section item each time we hit a section!