19fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn/* 29fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * Copyright (C) 2010 The Android Open Source Project 39fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * 49fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License"); 59fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * you may not use this file except in compliance with the License. 69fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * You may obtain a copy of the License at 79fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * 89fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * http://www.apache.org/licenses/LICENSE-2.0 99fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * 109fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * Unless required by applicable law or agreed to in writing, software 119fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS, 129fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * See the License for the specific language governing permissions and 149fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * limitations under the License. 159fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn */ 169fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 1710c33528e033643099783a5bc4eedb4b8a1e9a0eDianne Hackbornpackage com.example.android.supportv4.app; 189fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 199fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.support.v4.app.FragmentActivity; 209fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.support.v4.app.FragmentManager; 219fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.support.v4.app.ListFragment; 229fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.support.v4.app.LoaderManager; 239fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.support.v4.content.CursorLoader; 249fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.support.v4.content.Loader; 25a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganovimport android.support.v4.view.MenuItemCompat; 26a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganovimport android.support.v4.widget.SearchViewCompat; 27a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganovimport android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat; 289fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.support.v4.widget.SimpleCursorAdapter; 299fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 309fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.database.Cursor; 319fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.net.Uri; 329fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.os.Bundle; 33a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganovimport android.provider.BaseColumns; 34a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganovimport android.provider.Contacts.People; 359fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.text.TextUtils; 369fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.util.Log; 379fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.view.Menu; 389fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.view.MenuInflater; 39a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganovimport android.view.MenuItem; 409fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.view.View; 419fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.widget.ListView; 429fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 439fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn/** 44d9012d1bfa132969fb8fed737e2f9f19eefbc0b5Dianne Hackborn * Demonstration of the use of a CursorLoader to load and display contacts 45d9012d1bfa132969fb8fed737e2f9f19eefbc0b5Dianne Hackborn * data in a fragment. 469fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn */ 47a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov@SuppressWarnings("all") 48d9012d1bfa132969fb8fed737e2f9f19eefbc0b5Dianne Hackbornpublic class LoaderCursorSupport extends FragmentActivity { 499fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 509fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn @Override 519fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn protected void onCreate(Bundle savedInstanceState) { 529fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn super.onCreate(savedInstanceState); 539fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 549fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn FragmentManager fm = getSupportFragmentManager(); 559fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 569fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // Create the list fragment and add it as our sole content. 579fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn if (fm.findFragmentById(android.R.id.content) == null) { 589fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn CursorLoaderListFragment list = new CursorLoaderListFragment(); 599fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn fm.beginTransaction().add(android.R.id.content, list).commit(); 609fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn } 619fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn } 629fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 639fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn//BEGIN_INCLUDE(fragment_cursor) 649fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn public static class CursorLoaderListFragment extends ListFragment 659fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn implements LoaderManager.LoaderCallbacks<Cursor> { 669fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 679fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // This is the Adapter being used to display the list's data. 689fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn SimpleCursorAdapter mAdapter; 699fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 709fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // If non-null, this is the current filter the user has provided. 719fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn String mCurFilter; 729fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 739fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn @Override public void onActivityCreated(Bundle savedInstanceState) { 749fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn super.onActivityCreated(savedInstanceState); 759fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 769fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // Give some text to display if there is no data. In a real 779fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // application this would come from a resource. 789fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn setEmptyText("No phone numbers"); 799fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 809fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // We have a menu item to show in action bar. 819fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn setHasOptionsMenu(true); 829fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 839fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // Create an empty adapter we will use to display the loaded data. 849fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn mAdapter = new SimpleCursorAdapter(getActivity(), 85a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov android.R.layout.simple_list_item_1, null, 86a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov new String[] { People.DISPLAY_NAME }, 87a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov new int[] { android.R.id.text1}, 0); 889fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn setListAdapter(mAdapter); 899fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 90be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn // Start out with a progress indicator. 91be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn setListShown(false); 92be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn 939fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // Prepare the loader. Either re-connect with an existing one, 949fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // or start a new one. 959fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn getLoaderManager().initLoader(0, null, this); 969fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn } 979fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 989fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 999fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // Place an action bar item for searching. 100a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov MenuItem item = menu.add("Search"); 101a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov item.setIcon(android.R.drawable.ic_menu_search); 10280df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS 10380df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn | MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW); 104a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov View searchView = SearchViewCompat.newSearchView(getActivity()); 105a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov if (searchView != null) { 106a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov SearchViewCompat.setOnQueryTextListener(searchView, 107a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov new OnQueryTextListenerCompat() { 108a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov @Override 109a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov public boolean onQueryTextChange(String newText) { 110a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov // Called when the action bar search text has changed. Update 111a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov // the search filter, and restart the loader to do a new query 112a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov // with this filter. 11380df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn String newFilter = !TextUtils.isEmpty(newText) ? newText : null; 11480df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn // Don't do anything if the filter hasn't actually changed. 11580df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn // Prevents restarting the loader when restoring state. 11680df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn if (mCurFilter == null && newFilter == null) { 11780df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn return true; 11880df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn } 11980df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn if (mCurFilter != null && mCurFilter.equals(newFilter)) { 12080df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn return true; 12180df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn } 12280df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn mCurFilter = newFilter; 123a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov getLoaderManager().restartLoader(0, null, CursorLoaderListFragment.this); 124a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov return true; 125a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov } 126a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov }); 127a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov MenuItemCompat.setActionView(item, searchView); 128a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov } 1299fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn } 1309fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 1319fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn @Override public void onListItemClick(ListView l, View v, int position, long id) { 1329fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // Insert desired behavior here. 1339fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn Log.i("FragmentComplexList", "Item clicked: " + id); 1349fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn } 1359fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 1369fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // These are the Contacts rows that we will retrieve. 1379fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { 138a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov People._ID, 139a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov People.DISPLAY_NAME, 1409fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn }; 1419fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 1429fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn public Loader<Cursor> onCreateLoader(int id, Bundle args) { 1439fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // This is called when a new Loader needs to be created. This 1449fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // sample only has one Loader, so we don't care about the ID. 1459fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // First, pick the base URI to use depending on whether we are 1469fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // currently filtering. 1479fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn Uri baseUri; 1489fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn if (mCurFilter != null) { 149a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov baseUri = Uri.withAppendedPath(People.CONTENT_FILTER_URI, Uri.encode(mCurFilter)); 1509fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn } else { 151a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov baseUri = People.CONTENT_URI; 1529fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn } 1539fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 1549fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // Now create and return a CursorLoader that will take care of 1559fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // creating a Cursor for the data being displayed. 156a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov String select = "((" + People.DISPLAY_NAME + " NOTNULL) AND (" 157a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov + People.DISPLAY_NAME + " != '' ))"; 1589fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn return new CursorLoader(getActivity(), baseUri, 1599fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn CONTACTS_SUMMARY_PROJECTION, select, null, 160a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov People.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); 1619fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn } 1629fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 1639fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 1649fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // Swap the new cursor in. (The framework will take care of closing the 1659fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // old cursor once we return.) 1669fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn mAdapter.swapCursor(data); 167be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn 168be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn // The list should now be shown. 169be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn if (isResumed()) { 170be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn setListShown(true); 171be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn } else { 172be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn setListShownNoAnimation(true); 173be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn } 1749fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn } 1759fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn 1769fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn public void onLoaderReset(Loader<Cursor> loader) { 1779fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // This is called when the last Cursor provided to onLoadFinished() 1789fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // above is about to be closed. We need to make sure we are no 1799fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn // longer using it. 1809fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn mAdapter.swapCursor(null); 1819fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn } 1829fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn } 1839fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn//END_INCLUDE(fragment_cursor) 1849fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn} 185