0

I'm new to android programming and having trouble with adding items to listview with custom adapter. My program consist of list, textfield, spinner and button. The goal is to add new item to the list (with textfield's content as a name and spinner selection as a type), when the button is pressed. The problem is that items won't show up in the list. I have tried following several tutorials (lastly this one) but nothing seems to help. Here are my sources:

activity_list_view_demo.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<TextView
    android:id="@+id/textViewNum"
    android:text="0"
    android:layout_height="wrap_content"
    android:layout_width="fill_parent">
</TextView>
<Spinner
        android:id="@+id/shop"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:entries="@array/shop_name"
/>

 <ListView
    android:id="@+id/lista"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
/>

 <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <EditText
        android:id="@+id/txtItem"
        android:layout_gravity="bottom"
        android:layout_weight="4"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:inputType="text"
        android:hint="Esine"
    />

    <Spinner
        android:id="@+id/type"
        android:layout_gravity="bottom"
        android:layout_weight="2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:entries="@array/type_name"
    />

    <Button
        android:id="@+id/btnAdd"
        android:layout_gravity="bottom"
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Lisää"
    />

</LinearLayout>

</LinearLayout>

listitem_row.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
    android:id="@+id/textViewName"
    android:text="TextView"
    android:layout_height="fill_parent"
    android:layout_width="fill_parent">
</TextView>

<TextView
    android:text="TextView"
    android:id="@+id/textViewType"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
</TextView>

</LinearLayout>

ListViewAdapter.java

package com.example.testi2;

import java.util.ArrayList;

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.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class ListViewAdapter extends ArrayAdapter<ShoppingList>
{
Context context;
ArrayList<ShopItem> items;
int layoutResourceId = 0;

public ListViewAdapter(Context context, ShoppingList list, int resourceId) {
    super(context, R.layout.listitem_row);
    this.context = context;
    this.layoutResourceId = resourceId;

    for (int i = 0; i < list.getLength() - 1; i++) {
        items.add(list.getItem(i));
    }
}

@Override
public View getView(int position, View convertView, ViewGroup parent)
{
    View rowView = convertView;

    if (rowView == null) {
        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        rowView = inflater.inflate(R.layout.listitem_row, null);
    }

    ShopItem i = items.get(position);

    if (i != null) {
        TextView nameView = (TextView) rowView.findViewById(R.id.textViewName);
        TextView typeView = (TextView) rowView.findViewById(R.id.textViewType);
        nameView.setText(i.getName());
        typeView.setText(i.getType());
    }

    return rowView;
}

}

ListViewDemo.java

package com.example.testi2;

import java.util.ArrayList;
import java.util.List;

import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.app.Activity;
import android.app.ListActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import android.os.Build;

public class ListViewDemo extends Activity {

private Spinner typeSpinner;    
private ListViewAdapter adapter;
private ListView lview;
private ShoppingList shoppinglist;

@Override
public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.activity_list_view_demo);

    shoppinglist = new ShoppingList();
    shoppinglist.addItem("Banaani", "Hedelmä");
    createAddBtn();
    createList();
    typeSpinner = (Spinner) findViewById(R.id.type);     
}

public void createList() {
    lview = (ListView) findViewById(R.id.lista);
    adapter=new ListViewAdapter(this, shoppinglist, R.layout.listitem_row);
    lview.setAdapter(adapter);
}

public void createAddBtn() {
    Button btn = (Button) findViewById(R.id.btnAdd);

    OnClickListener listener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            EditText edit = (EditText) findViewById(R.id.txtItem);
            String editStr = edit.getText().toString();
            String spinnerStr = typeSpinner.getSelectedItem().toString();
            TextView numView = (TextView) findViewById(R.id.textViewNum);
            if (editStr.length()>0) {
                shoppinglist.addItem(editStr, spinnerStr);
                edit.setText("");
                adapter.notifyDataSetChanged();
                numView.setText(String.valueOf(shoppinglist.getItems().length));
            }
        }
    };       
    btn.setOnClickListener(listener);   
   }

   }

Any ideas what I'm doing wrong?

1 Answer 1

1

To start off, I would recommend you implement the ViewHolder pattern for any Adapter (http://developer.android.com/training/improving-layouts/smooth-scrolling.html#ViewHolder), but that is beyond the scope of this question.

To answer your question: you should look at where the Array adapter is getting its items. In your implementation's constructor, you are breaking any dependencies between the shopping list and the item array by simply copying over all the items. This results in any addition to the shopping list not transferring over to the adapters item list. Therefore, notifyDatasetChanged will have no effect.

To fix this problem, try using ArrayAdapters three parameter constructor that also takes an ArrayList so that you can keep a hard dependency between the adapter's dataset and the shopping list in the Activity.

Assuming ShoppingList simply extends ArrayList<ShopItem>, this would work like

public ListViewAdapter(Context context, ShoppingList list, int resourceId) {
    super(context, 0, list);
    this.context = context;
    this.layoutResourceId = resourceId;
}

Also, your ArrayAdapter should extend ArrayAdapter<ShopItem>, not ArrayAdapter<ShoppingList>. The generic should be the type of item to display, not the list.

Sign up to request clarification or add additional context in comments.

3 Comments

If I change ListViewAdapter's constructor to your example, what object am I supposed to use in getView method? I mean, at the moment I'm trying to get data ("name" and "type") from local variable "items" that should contain the shoppinglist's items (which it in fact doesn't contain?), but if the list isn't stored anywhere in the constructor how can I use it?
You can use ArrayAdapter's getItem(position) method to access the data needed bind in the getView method. If you look into ArrayAdapter's source code, it is simply holding it's own reference to a List of objects, which it why you holding your own list is unnecessary.
Still not working. I now understand that the actual problem seems to be that getView() isn't even called and that is because getCount() always returns 0. That seems to be usually caused by not sending the list items to the superclass constructor. But since I'm calling correct superclass constructor (the one from your example), I don't understand what's the problem in this case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.