I am new to Android development. I am trying to populate a spinner by using the SimpleAdapter. But spinner's list is showing blank element. When I click any element, its text is shown properly in Toast. Please tell me what is the problem in my code below.
public void onCreate(Bundle savedInstanceState) {
private List<Map<String, String>> data = new ArrayList<Map<String, String>>();
String[] from = new String[] { "colorsData" };
int[] to = new int[] { R.id.spinner };
String[] colors = getResources().getStringArray(R.array.colorsData);
for (int i = 0; i < colors.length; i++) {
data.add(addData(colors[i]));
}
Spinner spinner = (Spinner) findViewById(R.id.spinner);
SimpleAdapter simpleAdapter = new SimpleAdapter(this, data, android.R.layout.simple_spinner_item, from, to);
simpleAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(simpleAdapter);
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(
parent.getContext(),
"Selected Color:- "
+ parent.getItemAtPosition(position),
Toast.LENGTH_LONG).show();
}
});
}
private Map<String, String> addData(String colorName) {
Map<String, String> mapList = new HashMap<String, String>();
mapList.put("colorsData", colorName);
return mapList;
}
I'm about 95% sure that your to array should be declared as:
int[] to = new int[] { android.R.id.text1 };
Give that a try.
EDIT (based on comments below):
It seems there was a bug in older versions of AndroidOS which caused that IllegalStateException. (I didn't see the exception in 2.2, but I did see it in 1.5 in the emulator.) The bug can be worked around by adding a ViewBinder to the SimpleAdapter. ViewBinder isn't hard to implement; here's an example:
SimpleAdapter.ViewBinder viewBinder = new SimpleAdapter.ViewBinder() {
public boolean setViewValue(View view, Object data,
String textRepresentation) {
// We configured the SimpleAdapter to create TextViews (see
// the 'to' array), so this cast should be safe:
TextView textView = (TextView) view;
textView.setText(textRepresentation);
return true;
}
};
simpleAdapter.setViewBinder(viewBinder);
I blogged about this here.
Related
I am new to Android. I am Using "com.devsmart.android.ui.HorizontalListView" to show my items(playing cards). In the List I am getting 8 cards in the first attempt. What I want if I again call the method the there must be 7 cards so on means 1 cards must be remove from the list at each time till the list gets empty. But I am not able not do this removing of item from the list. I am posting my code here. Help will be appreciated.
MainActivity.java
ArrayList<HashMap<String, String>> aList9;
Button btn_aditional_card;
HorizontalListView list1;
int[] cards3 = new int[]{
R.drawable.card1,
R.drawable.card1,
R.drawable.card1,
R.drawable.card1,
R.drawable.card1,
R.drawable.card1,
R.drawable.card1,
R.drawable.card1,
R.drawable.card1,
R.drawable.card1,
R.drawable.card1,
R.drawable.card1,
R.drawable.card1,
R.drawable.card1
};
public class MainActivity extends AppCompatActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_aditional_card = (Button) findViewById(R.id.btn_aditional_card);
list1 = (HorizontalListView) findViewById(R.id.listview1);
btn_aditional_card.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
add8();
}
});
}
public void add8() {
final android.view.animation.Animation animScale = AnimationUtils.loadAnimation(this, R.anim.slide_right_in);
list1.startAnimation(animScale);
aList9 = new ArrayList<HashMap<String, String>>();
for (int i = 0; i < 8; i++) {
HashMap<String, String> hm = new HashMap<String, String>();
hm.put("card", Integer.toString(cards3[i]));
aList9.add(hm);
}
String[] from = {"card"};
int[] to = {R.id.ImageView};
final SimpleAdapter adapter = new SimpleAdapter(getBaseContext(), aList9, R.layout.activity_animation__adapter, from, to);
list1.setAdapter(adapter);
adapter.notifyDataSetChanged();
list1.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
aList9.remove(aList9.size() - 1);
adapter.notifyDataSetChanged();
}
});
}
Here removing of item from the list must be done on list1.setOnItemClickListener but I don't have any idea how.
In your list1.setOnItemClickListener, do this:
if (aList9.size() > 0) {
aList9.remove(aList9.size() - 1);
adapter.notifyDataSetChanged();
}
When removing item from data list, you have to notify your adapter to update view.
You can remove the last item from the list like;
if (aList9.size() > 0) {
aList9.remove(aList9.size() - 1);
}
Another solution,
Take Length of your integer array and traverse the loop inside your add8 method according to this length and at the end of the method decrement the length by one, like;
int length = cards3.length;
Inside your add8 method;
for (int i = 0; i < length; i++) {
HashMap<String, String> hm = new HashMap<String, String>();
hm.put("card", Integer.toString(cards3[i]));
aList9.add(hm);
}
After for loop decrement the length like;
length--;
Hope you'll get the solution.
In your main activity the code should look like.I am using arraylist instead you can use hashmap.This code is only to show you way what you need to do. follow this code in your project you will get solution this is tested in my site and working fine you need to change somewhere according to your code.In button click i am only removing last item from arraylist and notifying that dataset changed.hope it will help you.
ArrayList<String> arrlist = new ArrayList<String>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
arrlist.add("B");
arrlist.add("C");
arrlist.add("D");
arrlist.add("E");
arrlist.add("F");
arrlist.add("G");
ListView lv = (ListView) findViewById(R.id.listview);
Button btnShowList = (Button) findViewById(R.id.btnShowList);
final ArrayAdapter adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, arrlist);
//Listview adapter
lv.setAdapter(adapter);
btnShowList.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (arrlist.size() > 0) {
arrlist.remove(arrlist.size() - 1);
adapter.notifyDataSetChanged();
}
}
});
}
Read the comments
class MainActivity extends AppCompatActivity {
//make your Adapter global
private SimpleAdapter adapter;
ArrayList<HashMap<String, String>> aList9;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
add8();
btn_aditional_card.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// on button click you can add a view to the listview if you want
// if you don't want this just comment out the following line
// i still don't understand what you want to do with this button
alist9.add(...);
// if you add stuff in the array list then notify the adapter
// it will update the view
adapter.notifyDataSetChanged();
}
});
}
public void add8() {
// initialize your ArrayList and listview
//populate them
for(int i = 0; i < 8; i++) {
// do your stuff.
// populate the list
}
// initialize your adapter as before
adapter = new SimpleAdapter(....);
listview.setadapter(adapter);
adapter.notifyDataSetChanged();
list1.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// delete the items like this
// check if size is greater than 0 and then remove
aList9.remove(aList9.size() - 1);
adapter.notifyDataSetChanged();
}
});
}
}
ListViews have always been my weak point and right now I am practicing putting a Listview, within a Listview. Anyway, I first call my ListView at the start of my program and it loads it with an array saved in my strings.xml:
String[] departments = getResources().getStringArray(
R.array.departments_array);
setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item,
departments));
setContentView(R.layout.main);
ListView lv = getListView();
lv.setTextFilterEnabled(true);
What I want to do is update this ListView with a new array of values each time a list item is clicked. The reason why I am trying to do it this way is because I plan on having 27 different arrays with different values for each position, and I feel it would be lighter on my resources if instead of making a ListView for each array of items, I would update this one ListView. I know I am probably not doing this the most efficient way, but if there is another way of implementing my idea please tell me.
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// When clicked, show a toast with the TextView text
switch (position) {
case 0:
try {
//It is here that i dont know what to do, I was going to call
//the Listview the same way i did previously using my setlistadapter,
//but i kept getting errors about the code being undefined
String[] listitems1 = getResources().getStringArray(
R.array.items_array);
} catch (ClassCastException e) {
Toast.makeText(getApplicationContext(), "Error",
Toast.LENGTH_SHORT).show();
}
break;
case 1:
try {
//The listview will be changed again here
} catch (ClassCastException e) {
Toast.makeText(getApplicationContext(), "Error",
Toast.LENGTH_SHORT).show();
}
break;
}
};
});
Have you thought of using a BaseAdapter and setting it as the list adapter
http://developer.android.com/reference/android/widget/BaseAdapter.html
Your approach is wrong( if I understand what are you doing). Instead of replacing the adapter of the ListView every time the user clicks(and simply setting a new adapter should work) a element in the initial list you should start a new activity passing the clicked position and in your new activity set the adapter on a ListView with the correct array based on that position.
A small example:
Main class:
/**
* The main class with the initial 27 items array.
*/
public class Class1 extends ListActivity {
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// start the second activity that will show our array depending on the
// position clicked
Intent i = new Intent(this, Class2.class);
// put the position in the Intent so we can know in the other activity
// what array to load.
i.putExtra("pos", position);
startActivity(i);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// I just used a simple array of 2 items, you'll load your 27 items
// array
String[] items = { "1", "2" };
setListAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, items));
}
}
Secondary activity that will show the array based on the previously selected position:
public class Class2 extends ListActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// get the Intent that started the activity
Intent i = getIntent();
// find out what position did that other activity send to us.
int position = i.getIntExtra("pos", -1);
// load the ListView with an adapter based on the array that you
// want(according to that position)
if (position == 0) {
// the first element in the main list
String[] items = getResources().getStringArray(R.array.a1);
setListAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, items));
} else if (position == 1) {
// the second element in the main list
String[] items = getResources().getStringArray(R.array.a2);
setListAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, items));
} else {
// etc
}
}
}
Luksprog's answer is indeed correct, and it is very useful for lists many levels deep (you do not put limits, just keep spawning new activity instances with the proper list loaded)
BUT
If your list isn't more than 2 levels deep you can use ExpandableListActivity instead of ListActivity which is basically an enhanced version of the single-level list you're using which natively handle group collapsing/expanding and therefore you do not need the spawn of a new activity for each sublevel.
again note that this approach works only for lists which do not go deeper than 2 levels
ExpandableListActivity documentation
ExpandableListView documentation
ExpandableListAdapter documentation - you should be fine with the BaseExpandableListAdapter implementation
And here you have some nice example from Google itself:
public class ExpandableList3 extends ExpandableListActivity {
private static final String NAME = "NAME";
private static final String IS_EVEN = "IS_EVEN";
private ExpandableListAdapter mAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
List<Map<String, String>> groupData = new ArrayList<Map<String, String>>();
List<List<Map<String, String>>> childData = new ArrayList<List<Map<String, String>>>();
for (int i = 0; i < 20; i++) {
Map<String, String> curGroupMap = new HashMap<String, String>();
groupData.add(curGroupMap);
curGroupMap.put(NAME, "Group " + i);
curGroupMap.put(IS_EVEN, (i % 2 == 0) ? "This group is even" : "This group is odd");
//filling with dummy data...
List<Map<String, String>> children = new ArrayList<Map<String, String>>();
for (int j = 0; j < 15; j++) {
Map<String, String> curChildMap = new HashMap<String, String>();
children.add(curChildMap);
curChildMap.put(NAME, "Child " + j);
curChildMap.put(IS_EVEN, (j % 2 == 0) ? "This child is even" : "This child is odd");
}
childData.add(children);
}
// Set up our adapter
mAdapter = new SimpleExpandableListAdapter(
this,
groupData,
android.R.layout.simple_expandable_list_item_1,
new String[] { NAME, IS_EVEN },
new int[] { android.R.id.text1, android.R.id.text2 },
childData,
android.R.layout.simple_expandable_list_item_2,
new String[] { NAME, IS_EVEN },
new int[] { android.R.id.text1, android.R.id.text2 }
);
setListAdapter(mAdapter);
}
}
Ok, so this has been somewhat addressed alot on this site, however I do not believe the exact problem with what my code uses. I am filling a listView with CheckedTextViews which works completely. However when I click on an item it gets checked but when I scroll up and down random rows are also checked. I realize it must have something to do with how the ListView keeps track of the items. I am running into some errors at the moment. I attempted to fill a hashmap with the list of the rows so I can keep track which one is set to true and which are false. However I am not positive where to implement the map and try to fill it.
Here is my OnCreate
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.viewmenu);
//Get table name of menu clicked.
Bundle extras = getIntent().getExtras();
tableName = extras.getString("table");
// map each contact's name to a TextView in the ListView layout
String[] from = new String[] { "name" };
int[] to = new int[] { R.id.toppingCheckedTextView };
for(int i=0; i< from.length; i++){
map.put(i, false);
}
contactAdapter = new SimpleCursorAdapter(
ViewToppingListing.this, R.layout.toppings_list_item, null, from, to);
setListAdapter(contactAdapter); // set contactView's adapter
}
I attempt to place the map in the onCreate to fill it however it complains about a nullpointer.
Here is where I tried using the OnListItemClick method
#Override
protected void onListItemClick(ListView arg0, View arg1, int arg2, long arg3){
final int index = arg2 - arg0.getFirstVisiblePosition();
View v = arg0.getChildAt(index);
CheckedTextView ctv = (CheckedTextView) v.findViewById(R.id.toppingCheckedTextView);
if((Boolean)map.get(index) == true){
ctv.setChecked(true);
ctv.setVisibility(View.VISIBLE);
} else{
ctv.setVisibility(View.GONE);
}
}
I have read alot on this, and it seems that alot of solutions involves using getView(), however I don't know if that applies to my situation. Any help would be greatly appreciated!
First of all do you need a SimpleCursorAdapter? You set the adapter with a null cursor:
contactAdapter = new SimpleCursorAdapter(
ViewToppingListing.this, R.layout.toppings_list_item, null, from, to); // the third parameter is the cursor and you set it to null!
The behavior you see it's because of the ListView is recycling views and yes you'll have to implement your own adapter and override bindView(). The code bellow is based on another answer to a similar question maybe you'll want to look at it( Getting the selected View from ListView ). Here is an example:
public class TestCursorAdapter extends ListActivity {
MySimpleAdapter adapter;
private HashMap<Long, Boolean> positionHide = new HashMap<Long, Boolean>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] columns = new String[] { "_id", "name" };
MatrixCursor mc = new MatrixCursor(columns); // cursor for testing
for (int i = 1; i < 35; i++) {
long id = i;
mc.addRow(new Object[] { id, "Name" + i });
}
String[] from = new String[] { "name" };
int[] to = new int[] { R.id.checked_text };
adapter = new MySimpleAdapter(this,
R.layout.adapter_mysimpleadapter_row, mc, from, to);
setListAdapter(adapter);
}
private class MySimpleAdapter extends SimpleCursorAdapter {
public MySimpleAdapter(Context context, int layout, Cursor c,
String[] from, int[] to) {
super(context, layout, c, from, to);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
super.bindView(view, context, cursor);
CheckedTextView ctv = (CheckedTextView) view
.findViewById(R.id.checked_text);
long pos = cursor.getLong(0); // the id from the cursor
if (positionHide.get(pos) == null) {
ctv.setChecked(false);
// we don't have this id in the hashmap so the value is by
// default false, the TextView is GONE
} else {
// we have the value in the Hashmap so see what it is and set
// the textview visibility from this value
Boolean tmp = positionHide.get(pos);
if (tmp.booleanValue()) {
ctv.setChecked(true);
} else {
ctv.setChecked(false);
}
}
}
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Boolean tmp = positionHide.get(id);
if (tmp == null) {
// if null we don't have this key in the hashmap so
// we add it with the value true
positionHide.put(id, true);
} else {
positionHide.put(id, !tmp.booleanValue());
// if the value exists in the map then inverse it's value
}
adapter.notifyDataSetChanged(); // notify the adapter that something has
// changed
}
}
Please excuse me, I'm new:new at this. I use a simple_list_item_2 to display 11 items. These 11 items have been loaded by using HashMap and then SimpleAdapter. This works fine in displaying everything. The problem is that I cannot get setOnItemClickListener going. The code:
public class TwoLineActivity extends ListActivity
{
ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>(2);
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.scrolllist);
// enter valid data, these 2 are the same as the remaining 9
HashMap<String, String> maplist;
maplist = new HashMap<String, String>();
maplist.put("line1", "a11 data");
maplist.put("line2", "asd asd ad 1234569780");
list.add(maplist);
maplist = new HashMap<String, String>();
maplist.put("line1", "a12 data");
maplist.put("line2", "asd asd ad 1234569781");
list.add(maplist);
String[] from = { "line1", "line2" };
int[] to = { android.R.id.text1, android.R.id.text2 };
SimpleAdapter adapter = new SimpleAdapter(this, list, android.R.layout.simple_list_item_2, from, to);
setListAdapter(adapter);`
So up to here things are great, I get my list. Now I want to be able to select an item from the list, so I coded the next 2 lines
list.setAdapter(adapter);
list.setOnItemClickListener(new OnItemClickListener()
{ .....
I get the following errors
The method setAdapter(SimpleAdapter) is undefined for the type ArrayList<HashMap<String,String>>
and
The method setOnItemClickListener(new AdapterView.OnItemClickListener(){}) is undefined for the type ArrayList<HashMap<String,String>>
If your activity extends ListActivity, you should override
protected void onListItemClick(ListView l, View v, int position, long id) {
}
I'm writing a news-app and I'm having some trouble with displaying a custom list. All I want is that list items have 2 TextViews in them:
News-Title and
News-Description
These are contained in 2 static arrays: homeScreen.title[] and homeScreen.descriptionLong[].
Lower you have my code for the HashMap and the Adapter:
final static ArrayList> data = new ArrayList>();
static{
HashMap<String, String> row = new HashMap<String, String>();
for (int i = 0; i<HomeScreen.arrayLength; i++){
row.put("Title", HomeScreen.title[i]);
row.put("Description", HomeScreen.descriptionLong[i]);
data.add(row);
}
}
SimpleAdapter adapter = new SimpleAdapter(this,
data,
R.layout.mainmenu,
new String[] {"Title", "Description"},
new int[] { R.id.textView1, R.id.textView2});
setListAdapter(adapter);
}
public void onItemClick(SimpleAdapter arg0, View arg1, int position,
long id) {
selectedNews = position;
Toast.makeText(getApplicationContext(), "This is: " + selectedNews, Toast.LENGTH_LONG).show();
Intent intent = new Intent(MainMenu.this, ReadNews.class);
startActivity(intent);
}
The problem I'm having is that it only displays my 20'th (last) news information and also the default OnItemClick isn't working anymore. I'd appreciate your help...
You should put the row instantiation inside the for loop:
for (int i = 0; i<HomeScreen.arrayLength; i++){
HashMap<String, String> row = new HashMap<String, String>();
row.put("Title", HomeScreen.title[i]);
row.put("Description", HomeScreen.descriptionLong[i]);
data.add(row);
}
Update:
Your OnItemClickListener registration should look something like this:
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// your code here
}
});