1

I'm pulling my hair out trying to figure this out. From all the tutorials I've read, the way I have this setup should work. I have a ListActivity that is using a custom adapter to display some data. I'd like to display a "no items found" message if the adapter is empty.

This is my layout:

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 style="@style/BaseStyle"
 android:orientation="vertical"
 android:padding="5dip"
 >
      <ListView android:id="@android:id/list"
      style="@style/BaseStyle"
      />

      <TextView xmlns:android="http://schemas.android.com/apk/res/android" 
      android:id="@android:id/empty"
      style="@style/BaseStyle.Title"
      android:text="No Items Found"
      />

      <TextView xmlns:android="http://schemas.android.com/apk/res/android" 
      android:id="@+id/text"
      style="@style/BaseStyle.Title"
      android:layout_alignParentTop="true"
      />
 </RelativeLayout>

This is my code:

 public class Main extends ListActivity {
 private CustomAdapter adapter;
 private String[] items = {};

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

      adapter = new CustomAdapter();

      PopulateItems();

      for (String item : items)
           adapter.addItem(item);

      this.setListAdapter(adapter);
      adapter.notifyDataSetChanged();
 }

 private class CustomAdapter extends BaseAdapter {
 private String[] mData;
 private LayoutInflater mInflater;

 public CustomAdapter() {
      mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 }

 public void addItem(String item) {
      mData.add(item);
 }

 @Override
 public int getCount() {
      return mData.size();
 }

 @Override
 public Object getItem(int position) {
      return mData.get(position);
 }

 @Override
 public long getItemId(int position) {
      return position;
 }

 @Override
 public View getView(int position, View convertView, ViewGroup parent)
 {
      ViewHolder holder;
      String item = (String)this.getItem(position);

      if (convertView == null)
      {         
           holder = new ViewHolder();

           convertView = mInflater.inflate(R.layout.main, parent, false);
           holder.text = (TextView)convertView.findViewById(R.id.text);
           convertView.setTag(holder);
      } else {
           holder = (ViewHolder)convertView.getTag();
      }
      TextView tvText = holder.text;
      tvText.setText(item);
 }

 static class ViewHolder {
      TextView text;
 }

What happens is the "No Items Found" text displays fine, when the "items" string array has no data. There is a process in the PopulateItem() method that will populate the array with data, and if there is data, the "No Items Found" text can still be seen on each row of the listing, "underneath" the data. So the empty text is basically being overlaid by the data.

Kris B
  • 3,436
  • 9
  • 64
  • 106

2 Answers2

1

Because your text view with id "empty" is still visible, set the visibility of that view as invisible initially and if the list is empty then only make it visible,
look at android:visibility="invisible" parameter.
and in the code if list is empty yourtextview.setVisibility(View.VISIBILE)

sat
  • 40,138
  • 28
  • 93
  • 102
  • There's no need for such complexity. ListView should automatically set the empty view to be invisible when it detects that the list is not empty – yjw Sep 06 '11 at 05:28
  • That was my impression, that if you have a View with an id of android:id="@android:id/empty", then it will display that View if the list is empty. That is what is confusing me. I will try to set the visibility. – Kris B Sep 06 '11 at 13:21
0

I'm not sure if you made any typos in your question for your code. It looks like you strip out parts of your code before posting it here.

getView() is meant for you to craft a View for a particular row in your ListView. I'm guessing you actually inflated your main.xml, which is your RelativeLayout containing the ListView, EmptyView and another TextView.

If your ListView is only dislaying strings, just instantiate a TextView and return it in getView

@Override
public View getView(int position, View convertView, ViewGroup parent)
{
  String item = (String)this.getItem(position);

  if (convertView == null)
  {         
       convertView = new TextView(context);
  } 
  convertView.setText(item);
  return convertView
}

Pass in the Context through the constructor of your custom adapter

Edit: Showing multiple textviews in a single row

If I'm going to be strict about it, the problem is not in the line convertView = mInflater.inflate(). The error is in the file inflated. It is usually easier to inflate another xml file if you have a more complex view for each row in your listview. The earlier mistake is somehwhat seemingly recursive inflating of main.xml

To handle multiple textview, do sth like this:

Create another xml file to represent each row in your listview, list_item.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  .....
 >
  <TextView android:id="@+id/list_text_1"
    ....
  />

  <TextView android:id="@+id/list_text_2"
    ....
  />

  <TextView android:id="@+id/list_text_3"
    ....
  />
 </LinearLayout>

In your getView implementation in your adapter,

@Override
public View getView(int position, View convertView, ViewGroup parent)
{
  String item = (String)this.getItem(position);

  if (convertView == null)
  {         
     convertView = mInflater.inflate(R.layout.list_item.xml, parent, false);
     //link list_text_1, list_text_2, list_text_3 as you need to the individual   
     // textviews
  } 
  else {
    // TODO linking up the textviews when convertView is not null
  }
  return convertView
}

This is probably a good time to bring in the viewholder pattern considering you need to inflate a xml file. Page 11/19 of the pdf file linked in this answer gives a pretty good explanation about the ViewHolder pattern.

Lastly, do read through more examples of ListView, and observe when do they use the inflater in getView and what they actually inflate.

Community
  • 1
  • 1
yjw
  • 3,394
  • 4
  • 20
  • 20
  • I'm relatively new to Android development, but, from what I was reading as long as you have a View with an id of @android:id/empty, that view will be displayed if there is no data. I didn't include all of my code, but this is the parts of the code dealing with the layout. The only places where I call main.xml are when I use setContentView, under onCreate, and in the getView method. Edit: I wrote this late at night, so I did have a typo. In getView I think I'mmissing where I instantiate the tvText variable. – Kris B Sep 06 '11 at 13:47
  • your understanding of @android:id/empty is not wrong. It will be displayed as long as the contents are empty, and Android will hide this view as long as you have no content. From your description it looks like you have a hierarchy of where you have listviews inside your listview. This means any row that is not populated with data will be considered empty and show the empty view...hence "No Items Found" on each row – yjw Sep 06 '11 at 13:58
  • So, I'm confused and maybe I'm missing something obvious, but I'm seeing "No Items Found" once if the adapter is empty, like I would expect. The issue is that when there is data, I'm seeing the "No Items Found" message AND the data together, on each row. It looks like the data is being overlayed, on top of, the "No Items Found" message on each row. – Kris B Sep 06 '11 at 23:12
  • Ok, I think I know where my issue is. It's on this line of code: convertView = mInflater.inflate(R.layout.main, parent, false); I probably shouldn't be using that and just need to use yjw's code. yjw, how would you change your code to target multiple TextView's? – Kris B Sep 06 '11 at 23:26
  • I updated my answer. Hopefully it's clear enough. Do ping me if you have any queries! – yjw Sep 07 '11 at 02:33
  • Thanks for the update. In my original post, I am using the ViewHolder pattern and I'm inflating the main.xml layout. Maybe you have to scroll down in my code to see all of it? So, my original issue still remains, is that I see the "No Items Found" message when there is no data (as expected), but when there is data I see BOTH the "No Items Found" AND the data on top of each other. I was thinking that inflating the main.xml was causing all of the TextView to be shown, even the empty TextView, which is where my confusion lies. – Kris B Sep 07 '11 at 13:49
  • Hi, I'm confused. Are you still facing this problem after trying out my solution for multiple textview? Do note that the key is not create another .xml layout, and to avoid inflating a .xml file containing a ListView inside your getView() implementation – yjw Sep 07 '11 at 15:26