listview with arraylist,simple adapter in android - android

I try to show something into listview using arraylist and simple adapter.
I tried something like below but in my result shows the last names of the arraylist.
What is my wrong i cant understand.
final ListView listView = (ListView) findViewById(R.id.mylist);
ArrayList<HashMap<String, String>> list_of_bookmarks = new ArrayList<HashMap<String, String>>();
HashMap<String, String> b = new HashMap<String, String>();
String[] from = { "php_key","c_key","android_key","hacking_key" };
String[] name_of_bookmarks = { "php","c","android","hacking" };
for(int i=0;i<4;i++)
{
b.put(from[i],name_of_bookmarks[i]);
list_of_bookmarks.add(b);
}
};
int[] to = { R.id.txt1,R.id.txt1,R.id.txt1,R.id.txt1};
SimpleAdapter adapter = new SimpleAdapter(getBaseContext(), list_of_bookmarks, R.layout.list_layout, from, to);
listView.setAdapter(adapter);
I just want to show "php","c","android","hacking" in a listview.
And what should be more efficient way to do that.I am a beginner so you may suggest a better way which should i follow

My advice to you would be to create a separate class that extends the Adapter(or some subclass of it)
Here is a simple example of a String array adapter.
package ro.gebs.captoom.adapters;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import antistatic.spinnerwheel.adapters.AbstractWheelTextAdapter;
import com.example.captoom.R;
public class LanguagesAdapter extends AbstractWheelTextAdapter {
// Countries names
private String languages[];
public LanguagesAdapter(Context context) {
super(context, R.layout.lang_item, NO_RESOURCE);
languages = context.getResources().getStringArray(R.array.lang_array);
setItemTextResource(R.id.language_txt);
}
#Override
public View getItem(int index, View cachedView, ViewGroup parent) {
View view = super.getItem(index, cachedView, parent);
return view;
}
#Override
public int getItemsCount() {
return languages.length;
}
#Override
protected CharSequence getItemText(int index) {
return languages[index];
}
}
and the usage is simple just use the method .setAdapter();
Or another example which uses an arrayAdapter:
package apc.example;
import java.util.ArrayList;
import utils.BitmapManager;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class PersonAdapter extends ArrayAdapter<Person> {
Context context;
int layoutResourceId;
ArrayList<Person> data = null;
public PersonAdapter(Context context, int layoutResourceId,
ArrayList<Person> data) {
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = data;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
ItemHolder holder = null;
if (row == null) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new ItemHolder();
holder.imgIcon = (ImageView) row.findViewById(R.id.icon);
holder.txtName = (TextView) row.findViewById(R.id.title);
holder.txtDescription = (TextView) row.findViewById(R.id.desc);
row.setTag(holder);
} else {
holder = (ItemHolder) row.getTag();
}
Person bean = data.get(position);
holder.txtName.setText(bean.getName());
holder.txtDescription.setText(bean.getDescription());
Bitmap b = BitmapFactory.decodeResource(context.getResources(), R.drawable.user);
BitmapManager.INSTANCE.setPlaceholder(b);
BitmapManager.INSTANCE.loadBitmap(bean.getUrl(), holder.imgIcon, 80, 80);
return row;
}
public static class ItemHolder {
public ImageView imgIcon;
TextView txtName;
TextView txtDescription;
}
public void updateAdapter(ArrayList<Person> pers){
this.data = pers;
}
}
This is an example of an adapter for a more complex class that has more fields rather than a simple string. But that can easily be modified to ArrayAdapter<String> and then go from there.
Anyways i think it's always a best practice to write your custom adapters for listviews.
Hope this helps!

Main.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="60dp" >
<ListView
android:id="#+id/zone_list"
android:layout_marginBottom="70dp"
android:background="#drawable/batteryborder"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
setlanguage.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="60dp">
<TextView
android:id="#+id/tvName"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:textSize="18dp"
android:gravity="center_vertical" />
</LinearLayout>
add in onCreate() of your activity file
ListView listView;
String[] from = { "php_key","c_key","android_key","hacking_key" };
ArrayAdapter arrayAdapter;
listView = (ListView) findViewById(R.id.zone_list);
arrayAdapter = new ArrayAdapter<>(this,R.layout.setlanguage, R.id.tvName, from);
listView.setAdapter(arrayAdapter);

You're reusing the same view in your int[] object.
int[] to = { R.id.txt1,R.id.txt1,R.id.txt1,R.id.txt1};
It looks like it's treating them all as the same object, so each time it adds a new item it changes the previous ones.
In order to use the SimpleAdapter you will need to define each view in the XML with different IDs.
int[] to = { R.id.txt1,R.id.txt2,R.id.txt3,R.id.txt4};
The SimpleAdapter may be simpler in regard to it's internal complexity, but it's definitely not simpler to actually use. With an ArrayAdapter you can just pass it the list of items and let it generate views automatically. It can be any size you need it to be so long as you don't run out of memory. (See below for example)
Once you start working with custom adapters I highly recommend you watch Romain Guy & Adam Powell's I/O talk. It's all a lot to take in when learning, but they do a great job of explaining how ListViews work.
//List of Items
String[] name_of_bookmarks = { "php","c","android","hacking" };
//Create your List object for the ArrayAdapter
//and make it the same size as name_of_books
List<String> listBookmarks = new ArrayList<String>(Array.getLength(name_of_bookmarks));
//Add name_of_bookmarks contents to listBookmarks
Collections.addAll(listBookmarks, name_of_books);
//Create an ArrayAdapter passing it the Context, a generic list item and your list
//An alternative to "this" would be "getApplicationContext()" from your main activity
//or "getActivity()" from a fragment. "getBaseContext()" is not recommended.
ArrayAdapter arrayAdapter = new ArrayAdapter(this, R.layout.list_item_text, listBookmarks);
//Set the adapter to your ListView
final ListView listView = (ListView) findViewById(R.id.mylist);
listView.setAdapter(arrayAdapter);

Try this one
public class MyFragment extends ListFragment{
String[] from = { "php_key","c_key","android_key","hacking_key" };
String[] name_of_bookmarks = { "php","c","android","hacking" };
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
List<HashMap<String, String>> list= new ArrayList<HashMap<String,String>>();
for (int i = 0; i < name_of_bookmarks.length; i++) {
HashMap<String, String> map= new HashMap<String, String>();
map.put("key", name_of_bookmarks[i]);
list.add(map);
}
String[] from = { "key" };
int[] to = { R.id.txt};
SimpleAdapter adapter = new SimpleAdapter(getActivity().getBaseContext(), list, R.layout.list_layout, from, to);
setListAdapter(adapter);
return super.onCreateView(inflater, container, savedInstanceState);
}
}

Whatever You Are Face Problem Exactly I Am Face Of The Problem Called "List
View Display Last Position Of Data Of An Array..."
The Problem Is Generated With Hash Map
final ListView listView = (ListView) findViewById(R.id.mylist);
ArrayList<HashMap<String, String>> list_of_bookmarks = new ArrayList<HashMap<String, String>>();
String[] from = { "php_key","c_key","android_key","hacking_key" };
String[] name_of_bookmarks = { "php","c","android","hacking" };
for(int i=0;i<4;i++)
{
HashMap<String, String> b = new HashMap<String, String>();
b.put(from[i],name_of_bookmarks[i]);
list_of_bookmarks.add(b);
}
};
int[] to = { R.id.txt1,R.id.txt1,R.id.txt1,R.id.txt1};
SimpleAdapter adapter = new SimpleAdapter(getBaseContext(), list_of_bookmarks, R.layout.list_layout, from, to);
listView.setAdapter(adapter);
Try Out This One If Any Doubt Created In Your Mind Then Ask Me Whatever Question Again
Simply You Have To Declared Your Hash Map Inside Your For Loop ...
Using Hash Map Inside Your For Loop Variable 'b' Created Each & Every Time With Considered As An Different Object. And Then Simply Array List Display Different Object Of Hash Map.
You Are Using Same Object To Store Value Of Hash Map And That Variable Was Override With Same Name That's Why you Are Faced The Problem
Thank You...

Related

Show only single column name from SQLite db in listview - Android

I need to set only first name field value in the listview.
Am querying data and getting all values and showing them in the listview. need to show only first name
The code,
import c...l.Database.ItemCRUDOperations;
import c...l.Model.Item;
List<Item> items;
ListView listView = (ListView) findViewById(R.id.listView);
itemCrud = new ItemCRUDOperations(this);
itemCrud.open();
items = itemCrud.getAllItems(); // returns id, first name, last name ...
// i need to only show first name in list view, currently it is showing all fields in listview
//I tried items.getFirstName() as I have getters and setters to it but not getting the value.
itemCrud.close();
ArrayAdapter<Item> adapter = new ArrayAdapter<>(this,
android.R.layout.simple_list_item_1, items);
listView.setAdapter(adapter);
Try this code:
...
List<String> firstNames = new ArrayList<>();
for (Item item : items) {
firstNames.add(item.getFirstName);
}
ArrayAdapter<Item> adapter = new ArrayAdapter<>(this,
android.R.layout.simple_list_item_1, firstNames);
listView.setAdapter(adapter);
Or you can simple override toString() method in your Item class:
#Override
public String toString() {
return getFirstName();
}
Use this to get a list with only firstName:
List<String> firstNamelist = new ArrayList<>();
for(Item item : items){
firstnameList.add(item.getFirstName());
}
then pass firstNameList to adapter:
ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
android.R.layout.simple_list_item_1, firstNameList);
Hope it helps.
The easiest option already suggested in another answer is to create list of Strings and pass it to the adapter instead of list of Items.
Another, more general, way is to implement own list adapter, overriding method getView in it, like this:
class ItemListAdapter extends ArrayAdapter<Item> {
private static class ViewHolder {
TextView firstName;
TextView lastName;
// More fields ...
}
ItemListAdapter(Context context, List<Item> items) {
super(context, 0, items);
}
#Override
#NonNull
public View getView(final int position, View view, #NonNull ViewGroup parent) {
final Item item = getItem(position);
final ViewHolder viewHolder;
if (view == null) {
viewHolder = new ViewHolder();
LayoutInflater inflater = LayoutInflater.from(getContext());
view = inflater.inflate(R.layout.item_layout, parent, false);
viewHolder.firstName = (TextView) view.findViewById(R.id.first_name_text_view);
view.setTag(viewHolder);
} else {
viewHolder = (ItemListAdapter.ViewHolder) view.getTag();
}
viewHolder.firstName.setText(item.getFirstName());
return view;
}
}
With this approach you will be able to add more information to the list item in future if you need.

NullPointer Exception on notifyDatasetChanged with custom Adapter

This is my first post on stack overflow so apologies if confusing.
I am getting nullpointer on foodListAdapter.notifyDatasetChanged() in my onClick method.
I am using a custom adapter. My onClick method is in my MainActivity class below. Also, please note that if I comment out the foodListAdapter.notifyDataSetChanged in my onClick method and uncomment out the other 3 lines, my code works fine. But I think this is not the cleanest way.
public class MainActivity extends Activity implements View.OnClickListener
{
Button mainButton;
ListView mainListView;
ArrayAdapter spinnerDataAdapter;
FoodListAdapter foodListAdapter;
ArrayList newFoodList = new ArrayList();
ShareActionProvider mShareActionProvider;
private static final String PREFS = "prefs";
private static final String PREF_NAME = "name";
SharedPreferences mSharedPreferences;
Spinner mainSpinner;
TextView foodTextView;
CharSequence currentDate;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Access button in activity_main and set onClickListener
mainButton = (Button) findViewById(R.id.main_button);
mainButton.setOnClickListener(this);
//Access edit text in activity_main
foodTextView = (TextView) findViewById(R.id.food_textview);
//Access list view in activity_main
mainListView = (ListView) findViewById(R.id.main_listview);
mainSpinner = (Spinner) findViewById(R.id.main_spinner);
View header = (View)getLayoutInflater().inflate(R.layout.listview_header_row, null);
//Create an array foodListAdapter for the spinner
spinnerDataAdapter = ArrayAdapter.createFromResource(this, R.array.food_types, android.R.layout.simple_spinner_item);
mainSpinner.setAdapter(spinnerDataAdapter);
//Set this listview to react to items being pressed
// mainListView.setOnItemClickListener(this);
//Greet the user or ask for their name if they are new
displayWelcome();
//create food list and create foodListAdapter then set the foodListAdapter
newFoodList.add(new FoodItem(R.drawable.ic_chicken, "Chicken"));
FoodListAdapter adapter = new FoodListAdapter(this,
R.layout.listview_item_row, newFoodList);
mainListView.addHeaderView(header);
mainListView.setAdapter(adapter);
}
#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);
//Access the Share Item defined in the menu XML
MenuItem shareItem = menu.findItem(R.id.menu_item_share);
//Access the object responsible for
//putting together the sharing submenu
if(shareItem !=null) {
mShareActionProvider = (ShareActionProvider)shareItem.getActionProvider();
}
return true;
}
public CharSequence getFormattedDate(){
Date d = new Date();
CharSequence s = DateFormat.format("MMMM d, yyyy ", d.getTime());
return s;
}
#Override
public void onClick(View v) {
currentDate = getFormattedDate();
foodTextView.setText(mainSpinner.getSelectedItem().toString());
newFoodList.add(new FoodItem(R.drawable.ic_chicken, mainSpinner.getSelectedItem().toString() + " was stored on: " + currentDate ));
foodListAdapter.notifyDataSetChanged();
// FoodListAdapter foodListAdapter = new FoodListAdapter(this,
// R.layout.listview_item_row, newFoodList);
// mainListView.setAdapter(foodListAdapter);
}
And here is my full custom adapter code:
package com.vintage.freshulator;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
public class FoodListAdapter extends ArrayAdapter<FoodItem> {
Context context;
int layoutResourceId;
ArrayList<FoodItem> data;
public FoodListAdapter(Context context, int layoutResourceId, ArrayList data) {
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = data;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
FoodListHolder holder = null;
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new FoodListHolder();
holder.imgIcon = (ImageView)row.findViewById(R.id.imgIcon);
holder.txtTitle = (TextView)row.findViewById(R.id.txtTitle);
row.setTag(holder);
}
else
{
holder = (FoodListHolder)row.getTag();
}
FoodItem foodItem = data.get(position);
holder.txtTitle.setText(foodItem.title);
holder.imgIcon.setImageResource(foodItem.icon);
return row;
}
static class FoodListHolder
{
ImageView imgIcon;
TextView txtTitle;
}
}
First of all you are using a variable that will not be reachable later by other methods. Instead create your adapter in onCreate like this:
foodListAdapter = new FoodListAdapter(this, R.layout.listview_item_row,
newFoodList);
mainListView.setAdapter(foodListAdapter);
Second of all changing the array in your activity won't change it inside of the adapter. So make the data variable inside of the adapter public:
public ArrayList<FoodItem> data;
Then in your onClick method, you can manipulate the adapters data like this:
foodListAdapter.data.add(new FoodItem(R.drawable.ic_chicken,
mainSpinner.getSelectedItem().toString()+" was stored on: "+currentDate));
foodListAdapter.notifyDataSetChanged();
Use
foodListAdapter = new FoodListAdapter(this,
R.layout.listview_item_row, newFoodList);
for creating FoodListAdapter object. getting NullPointer Exception because foodListAdapter is null(creating new adapter object of FoodListAdapter ).
Your foodListAdapter is null, because you are initializing it with adapter and using notifyDatasetChanged with foodListAdapter,so
change
FoodLisAdapter adapter = new FoodListAdapter(this,
R.layout.listview_item_row, newFoodList);
mainListView.addHeaderView(header);
mainListView.setAdapter(adapter);
to
foodListAdapter = new FoodListAdapter(this,
R.layout.listview_item_row, newFoodList);
mainListView.addHeaderView(header);
mainListView.setAdapter(foodListAdapter);

Android AutoCompleteTextView with custom list item containing multiple views

I try to create a AutoCompleteTextView with custom list items, like showing a picture and a name in one list item. I know how to create it with 1 line of text in a list item but i'm a bit confused on who to do this with more views. I was thing about a ListAdapter and assigning the values to the right views. I'm pretty stuck here. I hope someone can give me a push in the right direction. Question is updated below.
Main activity:
public class AutocompleteCustomActivity extends Activity {
String[] firstView = {"Apple","Banana","Strawberry"};
String[] secondView = {"Green","Yellow","Red"};
AutoCompleteTextView autocomplete;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/*
// Simple 1 line list item
this.autocomplete = (AutoCompleteTextView) findViewById(R.id.autocomplete);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list_item, firstView);
autocomplete.setAdapter(adapter);
*/
// 2 Lines of text in list item
this.autocomplete = (AutoCompleteTextView) findViewById(R.id.autocomplete);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.two_list_items, firstView);
autocomplete.setAdapter(adapter);
}
}
XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
UPDATE:
After a lot of hardcore Googling and trial and erroring i came up with this code. I think it's pretty oké but the list items keep showing after selecting one. I know it's the settext that opens the new listitems.
I found this post: Disable Android AutoCompleteTextView after user selects item from drop down
But i don't know what he means :( Anyone knows how to fix this?
package com.sb.autocompletecustom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AutoCompleteTextView;
import android.widget.SimpleAdapter;
public class AutocompleteCustomActivity extends Activity {
AutoCompleteTextView autocomplete;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Data to fill autocomplete
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
Map<String, String> curGroupMap = new HashMap<String, String>();
list.add(curGroupMap);
curGroupMap.put("name", "Banana");
curGroupMap.put("color", "Yellow");
curGroupMap = new HashMap<String, String>();
list.add(curGroupMap);
curGroupMap.put("name", "Strawberry");
curGroupMap.put("color", "Red");
curGroupMap = new HashMap<String, String>();
list.add(curGroupMap);
curGroupMap.put("name", "Strawberry");
curGroupMap.put("color", "Black");
// 2 Lines of text in list item
this.autocomplete = (AutoCompleteTextView) findViewById(R.id.autocomplete);
SimpleAdapter adapter = new SimpleAdapter(this, list, R.layout.two_list_items, new String[] { "name", "color" }, new int[] { R.id.textView1, R.id.textView2 });
autocomplete.setAdapter(adapter);
autocomplete.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> p, View v, int pos, long id) {
Map<String, String> map = (Map<String, String>) p.getItemAtPosition(pos);
String itemName = map.get("name");
autocomplete.setText(itemName);
}
});
}
}
use a custom list adapter. you can inflate the layout and assign the values
public class AutoCompleteCursorAdapter extends CursorAdapter implements Filterable{
private TextView txtDrName, txtDrugName, txtDrugManufacturer;
private int rowResID;
private static Cursor c;
private String autoCompleteTextName;
Context context;
int layout;
public AutoCompleteCursorAdapter(Context context, int layout ) {
super(context, c);
// this.c = c;
this.context = context;
this.autoCompleteTextName = autoCompleteTextName;
this.layout = layout;
}
public long getItemId(int position) {
return position;
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
final LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(layout, parent, false);
txtDrName = (TextView)v.findViewById(R.id.txtAutoName) ;
....
}
return v;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
txtDrName = (TextView) view.findViewById(R.id.txtAutoName) ;
}
#Override
public String convertToString(Cursor cursor) {
// this method dictates what is shown when the user clicks each entry in your autocomplete list
String name="";
name = cursor.getString(cursor.getColumnIndex("prefix"))+" "+cursor.getString(cursor.getColumnIndex("firstName"));
}
return name;
}
#Override
public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
// this is how you query for suggestions
if (getFilterQueryProvider() != null)
{ return getFilterQueryProvider().runQuery(constraint); }
if(constraint!=null){
DataBaseHelper db = new DataBaseHelper(context);
db.openDataBase();
if(autoCompleteTextName.equals(AppConstants.AUTOCOMPLETEDOCTORNAME)){
c = db.getStaffStartingWith((String) constraint);
}
else if (autoCompleteTextName.equals(AppConstants.AUTOCOMPLETEDRUGNAME)){
c = db.getDrugsForStartingWith((String) constraint);
}
c.moveToFirst();
db.close();
}
return c;
}
`

Android - ListView dynamic Buttons for each row calling dynamic listeners

I'm new to android, i've spent the last 2 days trying previous examples and online solutions but I just can't seem to get my head around it :(
I'm able to display a list view, parse some json from online and store a book title, book description and book ID and display this data in the listview. I want to be able to put a 'download' button in each row for the ListView, each button will correspond to its book ID on Click() and the action listener will download the book by appending that ID to a url.
e.g www.books.com/download_book1 or /download_book2....
Here is my code. Catalogue.java class
public class Catalogue extends ListActivity {
private JSONObject json;
private ListView lv;
private ArrayList<Integer> alKey = new ArrayList<Integer>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); //icicle
setContentView(R.layout.shelflist);
ArrayList<HashMap<String, String>> mylist = new ArrayList<HashMap<String, String>>();
....
try{
JSONArray entries = json.getJSONArray("entries");
for(int i=0;i<entries.length();i++){
HashMap<String, String> map = new HashMap<String, String>();
JSONObject e = entries.getJSONObject(i);
alKey.add(e.getInt("key"));
map.put("id", String.valueOf(i));
map.put("title", "Title:" + e.getString("title"));
map.put("description", "Description: " + e.getString("description"));
mylist.add(map);
}
}catch(JSONException e) {
Log.e("log_tag", "Error parsing data "+e.toString());
}
ListAdapter adapter = new SimpleAdapter(this, mylist , R.layout.shelfrow,
new String[] { "title", "description" },
new int[] { R.id.item_title, R.id.item_subtitle });
setListAdapter(adapter);
lv = getListView();
lv.setTextFilterEnabled(true);
.....
This is as far as I get. I don't know how to add 1 button per row in the List and assign an action listener to each button.
I also have a shelfrow.xml file (textView, textView for item_title and item_subtitle) and a shelflist.xml file (ListView).
I have a shelf.xml file with
Basically you need to learn the concept of ListAdapter.
Here's the short story: picture an object that holds the data to be displayed inside a list, along with the way to display each line individually. That's your ListAdapter. Now take each individual line: it's a book with a title and an OnClickListener. It's rendered inside a View with a TextView (for the title) and a Button (for the OnClickListener). All you need to do is give one View to the adapter that will be used for each line, and a List of the books you want to be inside the list.
Here's some sample code. I hope it clears things up a bit
private class MyItemModel{ //that's our book
String title; // the book's title
String description;
long id;
OnClickListener listener = new OnClickListener(){ // the book's action
#Override
public void onClick(View v) {
// the default action for all lines
doSomethingWithTheBookTitleOrUniqueId(this);
}
};
}
private class MyListAdapter extends BaseAdapter{
View renderer;
List<MyItemModel> items;
// call this one and pass it layoutInflater.inflate(R.layout.my_list_item)
public MyListAdapter(View renderer) {
this.renderer = renderer;
}
// whenever you need to set the list of items just use this method.
// call it when you have the data ready and want to display it
public void setModel(List<MyItemModel> items){
this.items = items;
notifyDataSetChanged();
}
#Override
public int getCount() {
return items!=null?items.size():0;
}
#Override
public Object getItem(int position) {
return items!=null?items.get(position):null;
}
#Override
public long getItemId(int position) {
return items!=null?items.get(position).id:-1;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null){
convertView = renderer;
}
MyItemModel item = items.get(position);
// replace those R.ids by the ones inside your custom list_item layout.
TextView label = (TextView)convertView.findViewById(R.id.item_title);
label.setText(item.label);
Button button = (Button)convertView.findViewById(R.id.item_button);
button.setOnClickListener(item.listener);
return convertView;
}
}
In order to pass the List, instead of putting the data inside your list of hashmaps you can do this for instance (be careful, I also updated the MyItemModel and MyListAdapter to your need, added the id and description properties):
List<MyItemModel> myListModel = new ArrayList<MyItemModel>();
try{
JSONArray entries = json.getJSONArray("entries");
for(int i=0;i<entries.length();i++){
MyItemModel item = new MyItemModel();
JSONObject e = entries.getJSONObject(i);
alKey.add(e.getInt("key"));
item.id = i;
item.title = e.getString("title");
item.description = e.getString("description");
// you can change the button action at this point:
// item.onClickListener = new OnClickListener(){...};
myListModel.add(item);
}
}catch(JSONException e) {
Log.e("log_tag", "Error parsing data "+e.toString());
}
ListAdapter adapter = new MyListAdapter(getLayoutInflater().inflate(R.layout.shelfrow, this));
adapter.setModel(myListModel);
setListAdapter(adapter);
lv = getListView();
lv.setTextFilterEnabled(true);
You can create your own class extending ArrayAdapter that will hold your list and set onClickListener to the Button in each row.
But in getView method of your ArrayAdapter you have to create a new view every time.
for example - row layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="110dp"
android:background="#FFF"
android:layout_width="fill_parent">
<LinearLayout
android:layout_width="fill_parent"
android:background="#FFF"
android:orientation="vertical"
android:padding="2dp"
android:layout_height="110dp">
<TextView android:id="#+id/list_item_title"
android:background="#FFF"
android:layout_width="fill_parent"
android:layout_height="40dp"/>
<Button android:id="#+id/download_button"
android:gravity="center"
android:text="Download"
android:layout_height="35dp"/>
</LinearLayout>
</RelativeLayout>
and getView method in ArrayAdapter
private List<Map<String, String>> jsonMapList;
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.list_item, null);
// here you set textview values (title and description)
// TextView title = (TextView) v.findViewById(R.id.list_item_title);
// title.setText('bla');
// and set OnClickListener
Button button = (Button) v.findViewById(R.id.download_button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
downloadFile(getUrl(position));
}
});
return v;
}
// method that downloads file
private void downloadFile(String url) {}
// get url from your list by index
private String getUrl(int index) {
return jsonMapList.get(index).get("url");
}
Usage of Map is unnecessary, you could use any object you prefer.
In activity class
CustomAdapter listAdapter = new CustomAdapter(this, android.R.layout.simple_list_item_single_choice, jsonMapList);
setListAdapter(listAdapter);

Android: ListView with complex data model

I'd like to map an Array of "complex" data to a ListView. In a very simplified form my data model would look like something like this:
class ListPlacesValues {
String idObject;
String name;
String city;
String country;
ArrayList<String> classification;
double distance_quantity;
DistanceUnit distance_unit;
[...more stuff ...]
}
I know that I can convert my complex data into a HashList and then just use a SimpleAdapter:
SimpleAdapter mAdapter = new SimpleAdapter(
this,
hashList,
R.layout.places_listitem,
new String[] { "name", "city", "country"},
new int[] { R.id.name, R.id.city, R.id.country}
);
However, I would rather use my data model directly, but I've no idea where and how to start, so that in the end I can do something like this:
ArrayList<ListPlacesValues> values = getData();
MyAdapter mAdapter = new MyAdapter(
this,
values,
R.layout.places_listitem,
ListPlacesValues { values.name, values.city, values.country},
new int[] { R.id.name, R.id.city, R.id.country}
);
Solution: I found this Android API sample (List14), which was really helpful.
You can extend ArrayAdapter. Here's code example for you. In this example - SearchItem is some custom POJO. Basically you need to override getView() method to build your row by inflating row layout and then populating values based on List of items and current position
class SearchItemsAdapter extends ArrayAdapter<SearchItem> {
Activity context;
List<SearchItem> items;
SearchHeader header;
#SuppressWarnings("unchecked")
public SearchItemsAdapter(final Activity context,
final Map<SearchHeader, List<SearchItem>> result) {
super(context, R.layout.item, (List) ((Object[]) result.values()
.toArray())[0]);
this.context = context;
this.header = result.keySet().iterator().next();
this.items = result.get(this.header);
}
#Override
public View getView(final int position, final View convertView,
final ViewGroup parent) {
final View view = this.context.getLayoutInflater().inflate(
R.layout.item, null);
final SearchItem item = this.items.get(position);
((TextView) view.findViewById(R.id.jt)).setText(item.jt);
((TextView) view.findViewById(R.id.dp)).setText(item.dp);
((TextView) view.findViewById(R.id.cn)).setText(item.cn);
((TextView) view.findViewById(R.id.loc)).setText(item.loc.name);
final TextView body = ((TextView) view.findViewById(R.id.e));
body.setText(item.e);
body.setTag(item.src[0]);
((TextView) view.findViewById(R.id.src)).setText(item.src[1]);
return view;
}
}
There is one pitfall with the convertView in the sample you linked
if(convertView != null){ //reuse
convertView.setAnimation(null);
convertView.setAnyCustomFieldsIdontWantFilledWithData(null);
}
you want to set all animations or unused fields to null otherwise your items might have data in them or animations pending you dont want.

Categories

Resources