45

I have a problem with the setEmptyView method from a ListView.

Here is my Java code:

ListView view = (ListView)findViewById(R.id.listView1);
view.setEmptyView(findViewById(R.layout.empty_list_item));

ArrayAdapter<Session> adapter1 = new ArrayAdapter<Session>(this, android.R.layout.simple_list_item_1, 
        android.R.id.text1, MainController.getInstanz().getItems());
view.setAdapter(adapter1);

empty_list_item:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:text="@string/emptyList" >

</TextView>

listview:

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

What is wrong with my code? When I have items I see them in the list. But when the list is empty I don't see the TextView.

Amr
  • 1,068
  • 12
  • 21
gurehbgui
  • 14,236
  • 32
  • 106
  • 178

12 Answers12

100

Your TextView should be placed right under the ListView item with its visibility set to gone (android:visibility="gone"), do not place it in another layout. This is how your main layout would look like

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/listViewFangbuch"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    </ListView>
    <TextView
        android:id="@+id/empty_list_item"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone"
        android:text="@string/emptyList" >
    </TextView>

</LinearLayout>

And this is how your code might look like

ListView view = (ListView)findViewById(R.id.listViewFangbuch);
view.setEmptyView(findViewById(R.id.empty_list_item));

ArrayAdapter<Session> adapter1 = new ArrayAdapter<Session>(this, android.R.layout.simple_list_item_1, 
        android.R.id.text1, MainController.getInstanz().getItems());
view.setAdapter(adapter1);
bryant1410
  • 5,540
  • 4
  • 39
  • 40
mmbrian
  • 1,672
  • 2
  • 14
  • 26
  • 2
    Would you care to explain why? – aij Mar 23 '14 at 20:27
  • 22
    ListView simply runs setVisible(VISIBLE) or setVisible(GONE) on the setEmptyView(emptyView) when the adapter becomes empty or non-empty: emptyView must be present in the view tree (setContentView()/addContentView()) and all its parents must be VISIBLE for ListView's setVisible(VISIBLE) to make it appear - just as if you were to call setVisible() yourself. ListView needs setEmptyView(). ListActivity ONLY needs it if you don't set android:id="@android:id/empty" – android.weasel Jul 09 '14 at 10:54
  • 2
    If under a ListView on the same screen is placed another information, don't forget to cover the ListView and TextView with (as shown by @mmbrian). If you forget to separate the ListView and TextView from other controls, the TextView won't be shown. – CoolMind Jul 03 '15 at 15:52
  • Just great! The documentation is short and memtions nothing about this. But, thanks, It works. –  Oct 18 '19 at 03:47
32

the problem is, i have to do a addContentView:

View empty = getLayoutInflater().inflate(R.layout.empty_list_item, null, false);
addContentView(empty, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
view.setEmptyView(empty);

now its fine

gurehbgui
  • 14,236
  • 32
  • 106
  • 178
  • This works, I'm not sure why, I think setEmptyView does not work the way I would have expected, I believe you need to add the view to the contentview already. – sgarman Oct 22 '13 at 23:13
  • Wow, this works! addContentView(...) made all the difference. – satyadeepk Jan 19 '14 at 18:15
  • 2
    After playing with this, addContentView() is not the correct approach. It will appear equivalent as long as your ListView occupies all of your Activity's visible space. Instead of your empty view being a sibling to your ListView, it ends up being a sibling to your other root-level layouts in your Activity. It appears to work because it's floating (z-order) on top of all other Views in the activity. – Harvey Nov 09 '14 at 19:50
30

For me, none of this answers worked for me. What I had to do was add the empty view manually (inflated) to the "parent" view of the Listview:

ListView my_list = (ListView) findViewById(R.id.my_list);
View emptyView = getLayoutInflater().inflate(R.layout.empty_view,null);
((ViewGroup)my_list.getParent()).addView(emptyView); 
listView.setEmptyView(emptyView);
danigonlinea
  • 1,113
  • 1
  • 14
  • 20
  • 1
    After playing with this, I found that it was better to pass the parent to inflate() otherwise addView() doesn't respect the layout_* attributes of your empty_view layout. – Harvey Nov 09 '14 at 20:08
  • 1
    This one works if you're using a custom adapter for your Listview and a new layout for your Empty view. – Ian Mar 02 '15 at 03:44
  • This was the answer that did what I wanted, thanks a lot! – techfly Dec 10 '16 at 15:56
18

The simplest way to use setEmptyView() is with your "empty" TextView and ListView in the same layout like this:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

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

    <TextView
        android:id="@+id/empty_list_item"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/emptyList"
        android:visibility="gone" />

</LinearLayout>

Now you can use:

view.setEmptyView(findViewById(R.id.empty_list_item));
Sam
  • 86,580
  • 20
  • 181
  • 179
  • 1
    i did it like this now, still no textView – gurehbgui Sep 18 '12 at 19:29
  • that should be the correct answer. works for me in all listview related usecases. no matter if you use ListActivity or any other Activity. Even with Fragments (where you do not have the "addContentView" functionality) – dy_ Sep 22 '14 at 22:48
13

After trying all of the solutions presented here and experimenting, I believe the code below is the best method to use when your ListView and empty View are not side-by-side in a layout with the automatic ids set.

ViewGroup parentGroup = (ViewGroup)getListView().getParent();
View empty = getActivity().getLayoutInflater().inflate(R.layout.list_empty_view,
                                                       parentGroup,
                                                       false);
parentGroup.addView(empty);
getListView().setEmptyView(empty);

Reasoning:

  • By passing the parent group into inflate, the layout_* attributes of your empty view layout are respected
  • By not attaching the view in inflate (the false parameter), the empty view is returned. Otherwise, inflate would return the parent requiring us to use parentGroup.findViewById(empty_view_id) to get the empty view for use with setEmptyView(). Here we avoid the extra lookup, the need for another id, and the need to expose that id in our code. If we didn't need to preserve the reference to empty, telling inflate to attach would be the correct action removing the need for the addView call.
  • An anti-pattern, addContentView(), is not the correct approach. It will appear equivalent as long as your ListView occupies all of your Activity's visible space. Instead of your empty view being a sibling to your ListView, it ends up being a sibling to your other root-level layouts in your Activity. It appears to work because it's floating (z-order) on top of all other Views in the activity. See: Activity.addContentView(View) == ViewGroup.addContentView(View)?
Harvey
  • 5,703
  • 1
  • 32
  • 41
  • By default, addView() adds the view to the end of the group. This does not place the empty view in the correct location when your list view is followed by siblings. I addressed this by specifying the correct index: addView(empty, parentGroup.indexOfChild(getListView())) – Snooze Nov 03 '17 at 20:16
6

The core of the problem is that the AdapterView class does not actually add the view you pass to setEmptyView() to any container. It just changes the visibility. There are lots of ways to put your "empty view" object into a container, as the other answers describe.

The documentation for AdapterView should really be updated to reflect this, since it is not obvious.

Dave
  • 155
  • 1
  • 6
4

Create a layout in XML that specifies both the ListView and the empty view you want to use. If you give them IDs of @android:id/list and @android:id/empty, android will automatically use the view with id:empty when list is empty.

Nima
  • 6,383
  • 7
  • 46
  • 68
3

There are some correct solutions, but I think this is the best approach!

View emptyView = getLayoutInflater().inflate(R.layout.empty_list_cart, null);
addContentView(emptyView, listView.getLayoutParams()); // You're using the same params as listView
listView.setEmptyView(emptyView);
listView.setAdapter(adapter);
cesards
  • 15,882
  • 11
  • 70
  • 65
  • See my answer for why `((ViewGroup)listView.getParent()).addView()` should be used instead of `addContentView()` – Harvey Nov 09 '14 at 20:06
1

also these two methods helped me with displaying empty view:

    adapter.notifyDataSetChanged();
    list.invalidateViews();
1

Just use,

View emptyView = getLayoutInflater().inflate(R.layout.empty_view, null);
((ViewGroup)listView.getParent()).addView(emptyView);

Instead of listView.setEmptyView(emptyView);

Sazzad Hissain Khan
  • 37,929
  • 33
  • 189
  • 256
0

My problem was, that I added a footer view which seems not working with the empty view. After removing the footer view the empty view is displayed.

Stefan
  • 582
  • 1
  • 5
  • 17
0

I have just been learned android, but the snippet from https://developer.android.com/guide/topics/ui/layout/listview.html depicts some different approach:

// Create a progress bar to display while the list loads
ProgressBar progressBar = new ProgressBar(this);
progressBar.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
        LayoutParams.WRAP_CONTENT, Gravity.CENTER));
progressBar.setIndeterminate(true);
getListView().setEmptyView(progressBar);
// Must add the progress bar to the root of the layout
ViewGroup root = (ViewGroup) findViewById(android.R.id.content);
root.addView(progressBar); 

ViewGroup root = (ViewGroup) findViewById(android.R.id.content);

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62