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)?