ArrayAdapter unable to update contents - android

I am trying to update the contents of my ArrayAdapter. I have tried calling the method notifyDataSetChanged() on the adapter and invalidate() on the ListView but I do not see the data within the adapter being changed. I spent two hours searching through every StackOverflow post about this topic, but none of the answers worked.
Here is the ArrayAdapter class which I extended
public class ChannelAdapter extends ArrayAdapter<ChannelRow> {
Context context;
int layoutResourceId;
ChannelRow[] data;
public ChannelAdapter(Context context, int layoutResourceId, ChannelRow[] 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;
ChannelRowHolder holder = null;
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new ChannelRowHolder();
holder.userName = (TextView)row.findViewById(R.id.userNameTextView);
holder.channelName = (TextView)row.findViewById(R.id.channelNameTextView);
row.setTag(holder);
}
else
{
holder = (ChannelRowHolder)row.getTag();
}
ChannelRow channelRow = data[position];
holder.userName.setText(channelRow.getUserName());
holder.channelName.setText(channelRow.getChannelName());
return row;
}
static class ChannelRowHolder
{
TextView userName;
TextView channelName;
}
}
Below is my Activity which I deal with the adapter.
public class ChannelNameActivity extends Activity {
private ListView channelListView ;
private ChannelRow[] channelData;
private ChannelAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
this.setContentView(R.layout.activity_channelname);
// create ListView of channels
grabSessions();
channelData = new ChannelRow[]{ // default data
new ChannelRow("user1", "channel1"),
new ChannelRow("user2", "channel2")
};
// attach ListView adapters/views
adapter = new ChannelAdapter(this, R.layout.channel_row, channelData);
channelListView = (ListView) findViewById(R.id.channelListView);
final View contentView = (View)getLayoutInflater().inflate(R.layout.activity_channelname, null);
channelListView.addHeaderView(contentView);
channelListView.setAdapter(adapter);
....
}
private void grabSessions() {
ParseQuery<ParseObject> query = ParseQuery.getQuery("Session");
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> objects, ParseException e) {
if (e == null) {
createSessionsList((ArrayList<ParseObject>) objects);
} else {
// error with query
}
}
});
}
/**
* Called from grabSessions()
* Initializes channelData with the queried ParseObject Sessions
* #param objects the queried Sessions
*/
private void createSessionsList(ArrayList<ParseObject> objects){
ArrayList<ChannelRow> channels = new ArrayList<>();
ChannelRow newRow = null;
for (ParseObject o : objects){
newRow = new ChannelRow((String)o.get("hostName"), (String)o.get("chatTitle"));
channels.add(newRow);
}
channelData = channels.toArray(new ChannelRow[channels.size()]);
adapter.notifyDataSetChanged();
channelListView.invalidate();
}
}

Sir;
check this out private ChannelRow[] channelData; that's your instance variable, you instantiate it in your onCreate() this way
channelData = new ChannelRow[]{ // default data
new ChannelRow("user1", "channel1"),
new ChannelRow("user2", "channel2")
}; // channelData is holding is reference to the object being created with the `new` keyword
so for example if you add one more object to channelData and call your notifyDataSetChanged() it will refresh but in your createSessionsList(ArrayList<ParseObject> objects) method you assign your channelData to a new object like this channelData = channels.toArray(new ChannelRow[channels.size()]); and this reference is not what the ListView's Adapter data is pointing to, so your notifyDataSetChanged() does not work because it has not changed. what you have to do is recall the instantiation line, this is the complete code
private void createSessionsList(ArrayList<ParseObject> objects){
ArrayList<ChannelRow> channels = new ArrayList<>();
ChannelRow newRow = null;
for (ParseObject o : objects){
newRow = new ChannelRow((String)o.get("hostName"), (String)o.get("chatTitle"));
channels.add(newRow);
}
channelData = channels.toArray(new ChannelRow[channels.size()]);
adapter = new ChannelAdapter(this, R.layout.channel_row, channelData);
//edit started here
// set your Listview to the adapter
channelListView.setAdapter(adapter); // you set your list to the new adapter
adapter.notifyDataSetChanged();// you can remove it if you like
}
EDIT 1
if you hate the idea of calling this line adapter = new ChannelAdapter(this, R.layout.channel_row, channelData); all the time i'd suggest you use ArrayList and use the ArrayList.add(Object o) function to update your item then you can all notifyDataSetChanged() ..
Hope it helps..

Related

How to set onClick for custom array adapter with extra data

I have a custom array adapter for a ListView. The goal is to have each list item have an individual picture, and that when the user clicks on the item they are taken to a web page. I have the image part working, and there are some stackoverflow answers for where to put the onItemClickListener. It seems it would go in the custom array adapter class But I can't figure out how to access the url from the list item.
Here is the code:
public class Animal
{
int image_resource_id;
String animal_type;
String wikipedia_url;
Animal(int image_resource_id, String animal_type, String wikipedia_url)
{
this.image_resource_id = image_resource_id;
this.animal_type = animal_type;
this.wikipedia_url = wikipedia_url;
}
}
class AnimalViewHolder
{
ImageView animal_image = null;
TextView animal_name = null;
String animal_url = "";
}
class CustomAnimalAdapter extends ArrayAdapter<Animal>
{
Context context;
int layoutResourceId;
Animal data[] = null;
public CustomAnimalAdapter(Context context, int layoutResourceId, Animal[] 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;
AnimalViewHolder holder = null;
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new AnimalViewHolder();
holder.animal_image = (ImageView)row.findViewById(R.id.animal_image);
holder.animal_name = (TextView)row.findViewById(R.id.animal_name);
row.setTag(holder);
}
else
{
holder = (AnimalViewHolder)row.getTag();
}
Animal animal = data[position];
holder.animal_name.setText(animal.animal_type);
holder.animal_image.setImageResource(animal.image_resource_id);
return row;
}
}
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_main);
Animal[] animal_list = {
new Animal(R.drawable.lion, "Lion", "http://en.wikipedia.org/wiki/Lion"),
new Animal(R.drawable.tiger, "Tiger", "http://en.wikipedia.org/wiki/Tiger"),
new Animal(R.drawable.bear, "Bear", "http://en.wikipedia.org/wiki/Bear"),
new Animal(R.drawable.monkey, "Monkey", "http://en.wikipedia.org/wiki/Monkey"),
new Animal(R.drawable.moose, "Moose", "http://en.wikipedia.org/wiki/Moose"),
new Animal(R.drawable.shark, "Shark", "http://en.wikipedia.org/wiki/Shark")
};
CustomAnimalAdapter adapter = new CustomAnimalAdapter(this,
R.layout.row_item, animal_list);
list_view_1 = (ListView)findViewById(R.id.listView1);
list_view_1.setAdapter(adapter);
}
update your adapter getview with
row.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(animal.wikipedia_url));
context.startActivity(browserIntent);
}
});

custom adapter with ArrayList<HashMap<String, List<String>>>

Its a really complicated question, but I hope someone can help me.
I want to make a custom adapter that can handle
Array List mentioned in the title
Currently I am doing this, but its not even going into getView(...) method.
public class EventsAdapter extends BaseAdapter{
ArrayList<HashMap<String, List<String>>> eventList;
private Context context;
private int resource;
private static final String TAG_TITLE = "e_title";
public EventsAdapter(Context context, int resId,ArrayList<HashMap<String, List<String>>> eventList)
{
this.context = context;
this.resource = resId;
this.eventList = eventList;
Log.v("chk", "1");
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View event = convertView;
TextView title, desc, date, time, venue;
HashMap<String, List<String>> hm = eventList.get(position);
List<String> items = hm.get(TAG_TITLE);
Typeface font = Typeface.createFromAsset(context.getAssets(), "Ubahn.ttf");
if( event == null )
{
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
event = inflater.inflate( resource , parent, true );
event.setTag(items.get(position));
}
title = (TextView) event.findViewById( R.id.etitle);
desc = (TextView) event.findViewById( R.id.edesc );
date = (TextView)event.findViewById(R.id.edate);
time = (TextView)event.findViewById(R.id.etiming);
venue = (TextView)event.findViewById(R.id.elocation);
title.setTypeface(font);
System.out.print(items.get(0).toString());
title.setText(items.get(0).toString());
desc.setText(items.get(1).toString());
date.setText(items.get(2).toString());
time.setText(items.get(3).toString());
venue.setText(items.get(4).toString());
return event;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return 5;
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return eventList.get(position).get(position).get(position);
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
}
Any help would be greatly appreciated.
Here is how I am filling the data in the Array List
for (int i = 0; i < products.length(); i++) {
JSONObject c = products.getJSONObject(i);
// Storing each json item in variable
String title = c.getString(TAG_TITLE);
String description = c.getString(TAG_DESC);
String date = c.getString(TAG_DATE);
String time = c.getString(TAG_TIME);
String venue = c.getString(TAG_VENUE);
// creating new HashMap
HashMap<String, List<String>> map = new HashMap<String, List<String>>();
List<String> el = new ArrayList<String>();
el.add(title);
el.add(description);
el.add(date);
el.add(time);
el.add(venue);
// adding each child node to HashMap key => value
map.put(TAG_TITLE, el);
// map.put(TAG_DESC, description);
//muap.put(TAG_DATE, date);
// adding HashList to ArrayList
eventList.add(map);
}
and then here I am setting the adapter
EventsAdapter adapter = new EventsAdapter(getActivity(), R.layout.events_list_item, eventList);
lv.setAdapter( adapter);
I think it would be useful to consider when you are filling that list.
a good design pattern is to create the data as an empty hashmap, establish the adapter with that map, declare the listview( or whatever ) and then assign the adapter with the empty data set. later, fill the hashmap, and then adapter.notifydatasetchanged
I declare these feilds:
//array of places filtered by keyword
List<Place> places = new ArrayList<Place>( );
//spinner of places filtered by keyword
Spinner placesSpinner;
//adapter for spinner
private PlacesSpinnerAdapter placesSpinnerAdapter;
in onCreate:
//this is for a spinner, but same difference
placesSpinner = (Spinner)findViewById( R.id.placesSpinner );
placesSpinnerAdapter = new PlacesSpinnerAdapter( this,
android.R.layout.simple_spinner_dropdown_item, places );
placesSpinner.setAdapter( placesSpinnerAdapter );
and somewhere in the onPostExecute method of an AsyncTask you have no interest in
places.clear( );
places.addAll( result.results );
placesSpinnerAdapter.notifyDataSetChanged( );
placesSpinner.performClick( );
and lastly, here's a difference I see: adapters do Lists, I've never had a good time passing them hashmaps... do a map.keySet() or map.values(); as you hand the data over to the adapter; I know for certain the very standard pattern I just described does not work if the data set is hashmaps
gl hf
return list size from getCount method
#Override
public int getCount() {
return eventList.size();
}
As the array list inside the adapter does not have 5 items(it has only one item) so try return the size of the list
simply use this code for custom adapter java
public class CustomAdapter extends SimpleAdapter {
ArrayList<HashMap<String,String>> arrayList;
Context context;
public CustomAdapter(Context context,ArrayList<HashMap<String,String>> arrayList, int resource, String[] from ,int[] to) {
super(context, arrayList, resource, from, to);
this.context = context;
this.arrayList = arrayList;
}
#Override
public int getCount() {
return arrayList.size();
}
#Override
public Object getItem(int position) {
return arrayList.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//return super.getView(position, convertView, parent);
View view = super.getView(position,convertView,parent);
RelativeLayout container = (RelativeLayout)
view.findViewById(R.id.container);
return view;
}
}
and this is WelcomeActivity
ArrayList<HashMap<String, String>> userList = "Define your list here"
String[] from = new String[]{"name","phone"};
int[] to = new int[]{R.id.name,R.id.phone};
ListView lv = (ListView) findViewById(R.id.list);
CustomAdapter customAdapter = new CustomAdapter(this,userList,R.layout.user_list_f,from,to);
lv.setAdapter(customAdapter);
it has been working for me perfectly

ListView showing only one item or last item

The title of this question is same but technical issue are different.
Hi i am trying to get data from SQLite but i am able to show only last item in listview. I tried different- different solution but not getting success.
Problem is not getting item from SQLite(I am able to fetch all item) but showing item using adapter in listview.
Here is my code.
ListActivity.java
db=new DBHelper(getBaseContext());
db.getWritableDatabase();
try {
final DBHelper m = new DBHelper(getBaseContext());
final List<GetSet> NotesWiseProfile = m.getBabyDetails();
for (final GetSet cn : NotesWiseProfile) {
counter++;
String babyName = cn.getBabyName();
String babyImage = cn.getBabyImage();
int babyId = cn.getBabyId();
BabyData baby_data[] = new BabyData[]
{
new BabyData(R.drawable.ic_launcher, babyName,babyId),
};
adapter = new MobileArrayAdapter(this,
R.layout.list_row, baby_data);
listView1.invalidateViews();
listView1.setAdapter(adapter);
}
}
catch (Exception e) {
}
BabyData.java
public class BabyData {
public int icon;
public String title;
public int babyid;
public BabyData(){
super();
}
public BabyData(int icon, String title,int babyId) {
super();
this.icon = icon;
this.title = title;
babyid = babyId;
}
}
MobileArrayAdapter.java
public class MobileArrayAdapter extends ArrayAdapter<BabyData>{
Context context;
int layoutResourceId;
BabyData data[] = null;
public MobileArrayAdapter(Context context, int layoutResourceId, BabyData[] 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;
DataHolder holder = null;
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new DataHolder ();
holder.imgIcon = (ImageView)row.findViewById(R.id.imvBabyFace);
holder.txtTitle = (TextView)row.findViewById(R.id.tvbabyNameList);
holder.txtBabyId = (TextView)row.findViewById(R.id.tvBabyId);
row.setTag(holder);
}
else
{
holder = (DataHolder )row.getTag();
}
BabyData weather = data[position];
holder.txtTitle.setText(weather.title);
holder.txtBabyId.setText(String.valueOf(weather.babyid));
holder.imgIcon.setImageResource(weather.icon);
return row;
}
static class DataHolder
{
ImageView imgIcon;
TextView txtTitle;
TextView txtBabyId;
}
}
I don't understand what's wrong in my code. Please give me any hint or reference.
Thanks in Advance.
Put the listview declarations out of the for loop, something like:
BabyData baby_data[] = new BabyData[NotesWiseProfile.size()];
for (final GetSet cn : NotesWiseProfile) {
String babyName = cn.getBabyName();
String babyImage = cn.getBabyImage();
int babyId = cn.getBabyId();
baby_data[counter] = new BabyData(R.drawable.ic_launcher, babyName,babyId);
counter++;
}
adapter = new MobileArrayAdapter(this,
R.layout.list_row, baby_data);
listView1.invalidateViews();
listView1.setAdapter(adapter);
I think you should use a field for storing you babies. Currrently, you are using a local Baby array for that. As far as I know, the ListView always gets its data from the array you passed to it (invalidating it causes the ListView to look up that data again.
To recap: Store your array as a field - if data changes, update the array and call notifyDatasetChanged() on your adapter, which will cause your ListView to reload the data.

NullPointer Exception when setting the adapter for a ListView

I am trying to set the data to an adapter through an AsyncTask. This has caused alot of grief - Most recently when trying to set the Array Adapter.
The following method is called onPostExecute();
private void setQueues(final JSONObject[] qInfo)
{
queues = new QueueItem[qInfo.length];
for(int i = 0; i < qInfo.length; i++)
{
queues[i] = new QueueItem();
//final int ii = i;
// Formatting the queue title
String name = qInfo[i].optString("name").replace("-", " ");
queues[i].label = name;
try {
if(qInfo[i].getString("active").contains("1"))
{
queues[i].value = true;
}
else
{
queues[i].value = false;
}
}
catch (JSONException e)
{
e.printStackTrace();
}
}
lv.setAdapter(new QueueAdapter(getActivity(),
R.layout.queues_items, queues));
This causes the following exception runtime : link here
EDIT : As requested, here is QueueAdapter :
public class QueueAdapter extends ArrayAdapter<QueueItem>{
Context context;
int layoutResourceId;
QueueItem data[] = null;
public QueueAdapter(Context context, int layoutResourceId, QueueItem[] 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;
QueueHolder holder = null;
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new QueueHolder();
holder.queueswitch = (Switch)row.findViewById(R.id.queues_item_switch);
holder.txtLabel = (TextView)row.findViewById(R.id.queues_item_text);
row.setTag(holder);
}
else
{
holder = (QueueHolder)row.getTag();
}
QueueItem queue = data[position];
holder.txtLabel.setText(queue.label);
holder.queueswitch.setChecked(queue.value);
return row;
}
static class QueueHolder
{
Switch queueswitch;
TextView txtLabel;
}
}
lv.setAdapter(new QueueAdapter(getActivity(),
R.layout.queues_items, queues));
this snippet should be in try block.. Because If there is JSONException all elements in that array will be null...
I mean to say.. put for loop inside try block and not the oppt.. if you still want to loop when an Exception occurs.. Then Try using Collections instead of array..

How do i display my data when overriding getview

Ive been learning about the getview . But i cant get it to display the data in my listview. Can anyone help code is below
//public class OrderProductSearch extends Activity {
public class OrderProductSearch extends Activity {
ArrayList<HashMap<String,String>> list = new ArrayList<HashMap<String,String>>();
HashMap<String,String> item = new HashMap<String,String>();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try{
setContentView(R.layout.orderproducts);
}
catch (Exception e) {
//
String shaw="";
shaw = e.getMessage();
}
//Create view of the list where content will be stored
final ListView listContent = (ListView)findViewById(R.id.orderproductlistview);
//Set for fast scrolling
listContent.setFastScrollEnabled(true);
//Create instance of the database
final DbAdapter db = new DbAdapter(this);
//Open the Database and read from it
db.openToRead();
//Routine to call all product sub groups from the database
final Cursor cursor = db.getAllSubGroupProduct();
//Manages the cursor
startManagingCursor(cursor);
int i=0;
cursor.moveToFirst();
while (cursor.getPosition() < cursor.getCount()) {
item.put("ProdName",cursor.getString(2));
item.put("ProdSize", cursor.getString(3));
item.put("ProdPack",cursor.getString(4));
item.put("OrdQty","0");
//list.add(item);
list.add(i, item);
item = new HashMap<String,String>();
cursor.moveToNext();
i = i + 1;
}
String[] from = new String[] {"ProdName", "ProdSize", "ProdPack", "OrdQty"};
int[] to = new int[] { R.id.productlinerow, R.id.productlinerow2, R.id.productlinerow3, R.id.productlinerow4};
//SimpleAdapter notes = new SimpleAdapter(OrderProductSearch.this,list,R.layout.productlinerow,from,to);
NewAdapter notes = new NewAdapter(OrderProductSearch.this,list,R.layout.productlinerow,from,to);
listContent.setAdapter(notes);
//Close the database
db.close();
}
class NewAdapter extends SimpleAdapter{
int resource;
Context cxt;
private Context context;
List<? extends Map<String, ?>> DataList;
public NewAdapter(Context context, List<? extends Map<String, ?>> data,
int _resource, String[] from, int[] to) {
super(context, data, _resource, from, to);
resource = _resource;
this.context = context;
DataList = data;
// TODO Auto-generated constructor stub
}
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.productlinerow, null);
}
// TextView bTitle = (TextView) v.findViewById(R.id.productlinerow);
// bTitle.setText(DataList[position,1][1].toString());
return v;
}
}
}
If you're using a SimpleAdapter, you don't need to extend the class and customize the getView() as the SimpleAdapter handles the mapping of data to your layout via the resource, from and to parameters. Take a look at this tutorial for the idea:
http://vbsteven.com/archives/24
If you want to do more involved customization, use a BaseAdapter, which the SimpleAdapter actually extends. Here's a tutorial with examples of that:
http://android.amberfog.com/?p=296

Categories

Resources