Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top