16a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn/* 26a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn * Copyright (C) 2012 The Android Open Source Project 36a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn * 46a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License"); 56a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn * you may not use this file except in compliance with the License. 66a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn * You may obtain a copy of the License at 76a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn * 86a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn * http://www.apache.org/licenses/LICENSE-2.0 96a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn * 106a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn * Unless required by applicable law or agreed to in writing, software 116a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS, 126a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn * See the License for the specific language governing permissions and 146a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn * limitations under the License. 156a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn */ 166a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 176a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornpackage com.example.android.supportv4.app; 186a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 196a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.support.v4.app.FragmentActivity; 206a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.support.v4.app.FragmentManager; 216a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.support.v4.app.ListFragment; 226a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.support.v4.app.LoaderManager; 236a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.support.v4.content.CursorLoader; 246a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.support.v4.content.Loader; 256a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.support.v4.view.MenuItemCompat; 266a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.support.v4.widget.SearchViewCompat; 276a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat; 286a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.support.v4.widget.SimpleCursorAdapter; 296a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 306a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.database.Cursor; 316a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.net.Uri; 326a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.os.Bundle; 336a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.provider.BaseColumns; 346a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.provider.Contacts.People; 356a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.text.TextUtils; 366a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.util.Log; 376a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.view.Menu; 386a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.view.MenuInflater; 396a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.view.MenuItem; 406a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.view.View; 416a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornimport android.widget.ListView; 426a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 436a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn/** 446a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn * Demonstration of the use of a CursorLoader to load and display contacts 456a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn * data in a fragment. 466a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn */ 476a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn@SuppressWarnings("all") 486a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackbornpublic class LoaderRetainedSupport extends FragmentActivity { 496a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 506a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn @Override 516a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn protected void onCreate(Bundle savedInstanceState) { 526a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn super.onCreate(savedInstanceState); 536a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 546a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn FragmentManager fm = getSupportFragmentManager(); 556a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 566a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // Create the list fragment and add it as our sole content. 576a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn if (fm.findFragmentById(android.R.id.content) == null) { 586a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn CursorLoaderListFragment list = new CursorLoaderListFragment(); 596a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn fm.beginTransaction().add(android.R.id.content, list).commit(); 606a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn } 616a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn } 626a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 636a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn//BEGIN_INCLUDE(fragment_cursor) 646a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn public static class CursorLoaderListFragment extends ListFragment 656a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn implements LoaderManager.LoaderCallbacks<Cursor> { 666a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 676a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // This is the Adapter being used to display the list's data. 686a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn SimpleCursorAdapter mAdapter; 696a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 706a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // If non-null, this is the current filter the user has provided. 716a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn String mCurFilter; 726a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 736a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn @Override public void onActivityCreated(Bundle savedInstanceState) { 746a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn super.onActivityCreated(savedInstanceState); 756a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 766a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // In this sample we are going to use a retained fragment. 776a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn setRetainInstance(true); 786a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 796a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // Give some text to display if there is no data. In a real 806a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // application this would come from a resource. 816a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn setEmptyText("No phone numbers"); 826a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 836a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // We have a menu item to show in action bar. 846a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn setHasOptionsMenu(true); 856a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 866a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // Create an empty adapter we will use to display the loaded data. 876a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn mAdapter = new SimpleCursorAdapter(getActivity(), 886a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn android.R.layout.simple_list_item_1, null, 896a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn new String[] { People.DISPLAY_NAME }, 906a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn new int[] { android.R.id.text1}, 0); 916a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn setListAdapter(mAdapter); 926a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 936a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // Start out with a progress indicator. 946a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn setListShown(false); 956a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 966a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // Prepare the loader. Either re-connect with an existing one, 976a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // or start a new one. 986a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn getLoaderManager().initLoader(0, null, this); 996a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn } 1006a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 1016a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 1026a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // Place an action bar item for searching. 1036a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn MenuItem item = menu.add("Search"); 1046a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn item.setIcon(android.R.drawable.ic_menu_search); 1056a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS 1066a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn | MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW); 1076a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn View searchView = SearchViewCompat.newSearchView(getActivity()); 1086a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn if (searchView != null) { 1096a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn SearchViewCompat.setOnQueryTextListener(searchView, 1106a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn new OnQueryTextListenerCompat() { 1116a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn @Override 1126a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn public boolean onQueryTextChange(String newText) { 1136a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // Called when the action bar search text has changed. Update 1146a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // the search filter, and restart the loader to do a new query 1156a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // with this filter. 1166a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn String newFilter = !TextUtils.isEmpty(newText) ? newText : null; 1176a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // Don't do anything if the filter hasn't actually changed. 1186a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // Prevents restarting the loader when restoring state. 1196a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn if (mCurFilter == null && newFilter == null) { 1206a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn return true; 1216a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn } 1226a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn if (mCurFilter != null && mCurFilter.equals(newFilter)) { 1236a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn return true; 1246a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn } 1256a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn mCurFilter = newFilter; 1266a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn getLoaderManager().restartLoader(0, null, CursorLoaderListFragment.this); 1276a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn return true; 1286a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn } 1296a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn }); 1306a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn MenuItemCompat.setActionView(item, searchView); 1316a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn } 1326a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn } 1336a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 1346a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn @Override public void onListItemClick(ListView l, View v, int position, long id) { 1356a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // Insert desired behavior here. 1366a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn Log.i("FragmentComplexList", "Item clicked: " + id); 1376a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn } 1386a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 1396a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // These are the Contacts rows that we will retrieve. 1406a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { 1416a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn People._ID, 1426a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn People.DISPLAY_NAME, 1436a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn }; 1446a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 1456a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn public Loader<Cursor> onCreateLoader(int id, Bundle args) { 1466a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // This is called when a new Loader needs to be created. This 1476a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // sample only has one Loader, so we don't care about the ID. 1486a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // First, pick the base URI to use depending on whether we are 1496a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // currently filtering. 1506a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn Uri baseUri; 1516a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn if (mCurFilter != null) { 1526a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn baseUri = Uri.withAppendedPath(People.CONTENT_FILTER_URI, Uri.encode(mCurFilter)); 1536a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn } else { 1546a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn baseUri = People.CONTENT_URI; 1556a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn } 1566a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 1576a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // Now create and return a CursorLoader that will take care of 1586a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // creating a Cursor for the data being displayed. 1596a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn String select = "((" + People.DISPLAY_NAME + " NOTNULL) AND (" 1606a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn + People.DISPLAY_NAME + " != '' ))"; 1616a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn return new CursorLoader(getActivity(), baseUri, 1626a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn CONTACTS_SUMMARY_PROJECTION, select, null, 1636a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn People.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); 1646a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn } 1656a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 1666a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 1676a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // Swap the new cursor in. (The framework will take care of closing the 1686a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // old cursor once we return.) 1696a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn mAdapter.swapCursor(data); 1706a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 1716a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // The list should now be shown. 1726a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn if (isResumed()) { 1736a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn setListShown(true); 1746a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn } else { 1756a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn setListShownNoAnimation(true); 1766a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn } 1776a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn } 1786a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn 1796a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn public void onLoaderReset(Loader<Cursor> loader) { 1806a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // This is called when the last Cursor provided to onLoadFinished() 1816a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // above is about to be closed. We need to make sure we are no 1826a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // longer using it. 1836a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn mAdapter.swapCursor(null); 1846a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn } 1856a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn } 1866a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn//END_INCLUDE(fragment_cursor) 1876a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn} 188