I am trying to make a LoaderManager list backwards compatible to Android 2.1. The list is loading fine but the @id/android:empty message shows even when there are items clearly visible in the list.
I have looked at a number of solutions on StackOverflow that use setEmptyView() and setEmptyText() but couldn't get them to work.
Here is the code for the ListFragment. I have been combining code from various http://www.vogella.com/ tutorials.
package com.example.contentprov;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SimpleCursorAdapter;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import com.example.contentprov.data.MyTodoContentProvider;
import com.example.contentprov.data.TodoTable;
/*
* TodosOverviewActivity displays the existing todo items
* in a list
*
* You can create new ones via the ActionBar entry "Insert"
* You can delete existing ones via a long press on the item
*/
public class TodoOverviewFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener {
private SimpleCursorAdapter adapter;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivity().setContentView(R.layout.todo_list);
fillData();
}
// Opens the second activity if an entry is clicked
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Intent i = new Intent(getActivity(), TodoDetailActivity.class);
Uri todoUri = Uri.parse(MyTodoContentProvider.CONTENT_URI + "/" + id);
i.putExtra(MyTodoContentProvider.CONTENT_ITEM_TYPE, todoUri);
startActivity(i);
}
private void fillData() {
// Fields from the database (projection)
// Must include the _id column for the adapter to work
String[] from = new String[] { TodoTable.COLUMN_SUMMARY };
// Fields on the UI to which we map
int[] to = new int[] { R.id.label };
getActivity().getSupportLoaderManager().initLoader(0, null, this);
adapter = new SimpleCursorAdapter(getActivity(), R.layout.todo_row, null, from,
to, 0);
setListAdapter(adapter);
}
// Creates a new loader after the initLoader () call
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = { TodoTable.COLUMN_ID, TodoTable.COLUMN_SUMMARY };
CursorLoader cursorLoader = new CursorLoader(getActivity(),
MyTodoContentProvider.CONTENT_URI, projection, null, null, null);
return cursorLoader;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
adapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
// data is not available anymore, delete reference
adapter.swapCursor(null);
}
@Override
public void onItemClick(AdapterView<?> l, View v, int position, long id) {
Intent i = new Intent(getActivity(), TodoDetailActivity.class);
Uri todoUri = Uri.parse(MyTodoContentProvider.CONTENT_URI + "/" + id);
i.putExtra(MyTodoContentProvider.CONTENT_ITEM_TYPE, todoUri);
startActivity(i);
}
}
Here is the XML file for the list:
<?xml version="1.0" encoding="utf-8"?>
<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/android:list"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
<TextView
android:id="@id/android:empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/no_todos" />
</LinearLayout>
EDIT: The solution was to combine Eluvatar and dymmeh's answers. Here is the new version of the ListFragment.
package com.example.contentprov;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SimpleCursorAdapter;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import com.example.contentprov.data.MyTodoContentProvider;
import com.example.contentprov.data.TodoTable;
/*
* TodosOverviewActivity displays the existing todo items
* in a list
*
* You can create new ones via the ActionBar entry "Insert"
* You can delete existing ones via a long press on the item
*/
public class TodoOverviewFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener {
private SimpleCursorAdapter adapter;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fillData();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.todo_list,
container, false);
return view;
}
// Opens the second activity if an entry is clicked
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Intent i = new Intent(getActivity(), TodoDetailActivity.class);
Uri todoUri = Uri.parse(MyTodoContentProvider.CONTENT_URI + "/" + id);
i.putExtra(MyTodoContentProvider.CONTENT_ITEM_TYPE, todoUri);
startActivity(i);
}
private void fillData() {
// Fields from the database (projection)
// Must include the _id column for the adapter to work
String[] from = new String[] { TodoTable.COLUMN_SUMMARY };
// Fields on the UI to which we map
int[] to = new int[] { R.id.label };
getActivity().getSupportLoaderManager().initLoader(0, null, this);
adapter = new SimpleCursorAdapter(getActivity(), R.layout.todo_row, null, from,
to, 0);
setListAdapter(adapter);
}
// Creates a new loader after the initLoader () call
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = { TodoTable.COLUMN_ID, TodoTable.COLUMN_SUMMARY };
CursorLoader cursorLoader = new CursorLoader(getActivity(),
MyTodoContentProvider.CONTENT_URI, projection, null, null, null);
return cursorLoader;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
adapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
// data is not available anymore, delete reference
adapter.swapCursor(null);
}
@Override
public void onItemClick(AdapterView<?> l, View v, int position, long id) {
Intent i = new Intent(getActivity(), TodoDetailActivity.class);
Uri todoUri = Uri.parse(MyTodoContentProvider.CONTENT_URI + "/" + id);
i.putExtra(MyTodoContentProvider.CONTENT_ITEM_TYPE, todoUri);
startActivity(i);
}
}
By calling getActivity().setContentView(R.layout.todo_list);
you're telling your activity to display a ListView
and an empty TextView
. Your ListFragment
already contains a ListView
and empty TextView
that is managed automatically for you. So what you are doing is displaying a separate ListView
from your todo_list
layout and then modifying the ListView
contained within your ListFragment
(which is why it appears that nothing is being loaded into your ListView
). If you simply remove the call to getActivity().setContentView(R.layout.todo_list);
it should work as long as you are adding the ListFragment
properly.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.