Empty view does not show


#1

the empty view does not show up. the xml seems to render fine in the editor. any hints?

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onViewCreated(view, savedInstanceState);

	ListView l = this.getListView();
	View empty = getLayoutInflater(savedInstanceState).inflate(R.layout.empty_view, null, false);
	l.setEmptyView(empty);		
}

an xml file named empty_view

<?xml version="1.0" encoding="utf-8"?>

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

#2

All your ListView does is show and hide your empty view. It does not take care of adding it to the view hierarchy for you. Since your empty view isn’t in the view hierarchy, it never shows up.


#3

I was having trouble with this too process too. With Phillip’s suggestion, I began looking for a way to add the view to the View Hierarchy. It is actually very easy, it just took about 20 minutes of googling and experimenting before I found a reasonable solution.

[code] @Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);

	// Setup Empty View
	View emptyView = getLayoutInflater(savedInstanceState).inflate(R.layout.fragment_empty_list, null, false);

	// Setup the View's onClickListeners
	setupEmptyButton(emptyView);

	// ******** YOU MUST ADD THE VIEW TO THE VIEW HIERARCHY ******** \\
	getActivity().addContentView(emptyView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

	// Set the emptyView as the list's EmptyView
	getListView().setEmptyView(emptyView);
	
}[/code]

This is a 5 step process:
1. Create a Layout with the desired UI elements ( I used a TextView to display a message and a Button to add a new crime )
2. Inflate the layout into a View object
3. Setup any of the Layouts views in a Convenience Method ( This is where I setup the onClickListener() to handle the action of creating a new Crime)
4. Add the View to the View Hierarchy
5. Set the View as the EmptyView for the ListFragment

Step 1
Create a layout that you would like to use as the empty view.

Example Layout:
empty_list_layout.xml

[code]<?xml version="1.0" encoding="utf-8"?>

<TextView
    android:id="@+id/empty_text_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:layout_margin="16dp"
    android:textSize="26sp"
    android:text="@string/list_empty_crime"
    />

<Button 
    android:id="@+id/button_new_crime"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:text="@string/new_crime" />

[/code]

Step 2
Inflate the layout into a View object

Assuming you followed the tutorial from Chapter 16, we should be within the CrimeListFragment class.

The code should be placed within the onViewCreated(View view, Bundle savedInstanceState) method. I’m not totally positive, but I believe this is because the ContentView has not been created until after the onCreateView() method has executed. We can inflate a view within a fragment using the Activity’s LayoutInflater. The Activity class provides a convenience method for retrieving the LayoutInflator - getLayoutInflator() ( http://developer.android.com/reference/android/app/Activity.html ):

With the Activity’s LayoutInflater we can inflate our layout into a View object:
View emptyView = getLayoutInflater().inflate(R.layout.empty_list_layout, null, false);

Step 3
Since we have a button in our view, we would most likely want the button to do something. We have to setup the button’s onClickListener.

In the case of this project, we want the button to add a new Crime to the list (ArrayList mCrimes within CrimeLab). Fortunately, we have already written the code to do this. All we have to do is abstract it out of the onOptionsItemSelected(MenuItem item) method and put it into a Convenience method within the our CrimeListFragment class to prevent repeating code and improving code reusability.

Moving code from onOptionItemSelected(MenuItem item) method --> private void addNewCrime();

[code] @Override
public boolean onOptionsItemSelected(MenuItem item) {

	switch (item.getItemId()) {
	case R.id.menu_item_new_crime:

// Add New Crime and Prompt with CrimeFragment
addNewCrime();
return true;

}
}

// Convenience Methods
private void addNewCrime() {
// Create a new Crime object
Crime c = new Crime();

	// Get the array of crimes from CrimeLab and add the new crime
	CrimeLab.get(getActivity()).addCrime(c);
	
	// Create an Intent for CrimePagerActivity
	Intent i = new Intent(getActivity(), CrimePagerActivity.class);
	i.putExtra(CrimeFragment.EXTRA_CRIME_ID, c.getId());
	startActivityForResult(i,0);
}[/code]

Since we have moved the code to create a new crime, added to the mCrimes ArrayList, and prompt the user with the CrimePagerView’s CrimeFragment view in a single method we can call it in both the onOptionsItemSelected() and setupEmptyButton() methods. They now both allow the user the ability to add new crimes, but make it more obvious when no crimes exist and a user must create on to make the CrimeListFragment useful.

Simple enough we just need to setup our Layout, more specifically the ‘New Crime’ button
private void setupEmptyButton(View v) - we must pass the a reference to to view to call .findViewById() method

[code]private void setupEmptyButton(View emptyView) {
// We must have a Class Button Property/Member defined at the top of the CrimeListFragment Class
// Get a reference to the View
mEmptyButton = (Button) emptyView.findViewById(R.id.button_new_crime);

	// Set its onClickListener
	mEmptyButton.setOnClickListener(new OnClickListener() {
		
		@Override
		public void onClick(View v) {
			addNewCrime();
		}
	});
}[/code]

Step 4
Add the View to the View Hierarchy

Since ContentView has been created prior to onViewCreated() method, we can reference the ContentView object through the Activity, calling:

This simply say, “I want to add View v to the View Hierarchy.”

Now that the View has been add to the ContentView View Hierarchy, the Android OS knows about the view and can bring it up when the system desires (i.e. our Crime list is empty).

Step 5
All that is left is to tell the Activity that when the list is empty we want to call upon one of the Views sitting in the view hierarchy that we have already named. Call:

This essentially just passes a reference to the view in the method we created it in ( onViewCreated() ) , a reference that is stashed in the View Hierarchy which I am guessing is essentially just an array/data structure of view references.

That’s it, the Android OS does most of the heavy lifting.

Hopefully I saved someone some time and frustration.