Dianne Hackborn | 9fd3b6e | 2011-02-01 10:38:02 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2010 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Dianne Hackborn | 10c3352 | 2011-05-27 18:29:00 -0700 | [diff] [blame] | 17 | package com.example.android.supportv4.app; |
Dianne Hackborn | 9fd3b6e | 2011-02-01 10:38:02 -0800 | [diff] [blame] | 18 | |
| 19 | import android.support.v4.app.FragmentActivity; |
| 20 | import android.support.v4.app.FragmentManager; |
| 21 | import android.support.v4.app.ListFragment; |
| 22 | import android.support.v4.app.LoaderManager; |
| 23 | import android.support.v4.content.CursorLoader; |
| 24 | import android.support.v4.content.Loader; |
Svetoslav Ganov | a09e21a | 2011-11-14 16:37:43 -0800 | [diff] [blame] | 25 | import android.support.v4.view.MenuItemCompat; |
| 26 | import android.support.v4.widget.SearchViewCompat; |
| 27 | import android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat; |
Dianne Hackborn | 9fd3b6e | 2011-02-01 10:38:02 -0800 | [diff] [blame] | 28 | import android.support.v4.widget.SimpleCursorAdapter; |
| 29 | |
| 30 | import android.database.Cursor; |
| 31 | import android.net.Uri; |
| 32 | import android.os.Bundle; |
Svetoslav Ganov | a09e21a | 2011-11-14 16:37:43 -0800 | [diff] [blame] | 33 | import android.provider.BaseColumns; |
| 34 | import android.provider.Contacts.People; |
Dianne Hackborn | 9fd3b6e | 2011-02-01 10:38:02 -0800 | [diff] [blame] | 35 | import android.text.TextUtils; |
| 36 | import android.util.Log; |
| 37 | import android.view.Menu; |
| 38 | import android.view.MenuInflater; |
Svetoslav Ganov | a09e21a | 2011-11-14 16:37:43 -0800 | [diff] [blame] | 39 | import android.view.MenuItem; |
Dianne Hackborn | 9fd3b6e | 2011-02-01 10:38:02 -0800 | [diff] [blame] | 40 | import android.view.View; |
| 41 | import android.widget.ListView; |
| 42 | |
| 43 | /** |
Dianne Hackborn | d9012d1 | 2011-04-04 18:52:04 -0700 | [diff] [blame] | 44 | * Demonstration of the use of a CursorLoader to load and display contacts |
| 45 | * data in a fragment. |
Dianne Hackborn | 9fd3b6e | 2011-02-01 10:38:02 -0800 | [diff] [blame] | 46 | */ |
Svetoslav Ganov | a09e21a | 2011-11-14 16:37:43 -0800 | [diff] [blame] | 47 | @SuppressWarnings("all") |
Dianne Hackborn | d9012d1 | 2011-04-04 18:52:04 -0700 | [diff] [blame] | 48 | public class LoaderCursorSupport extends FragmentActivity { |
Dianne Hackborn | 9fd3b6e | 2011-02-01 10:38:02 -0800 | [diff] [blame] | 49 | |
| 50 | @Override |
| 51 | protected void onCreate(Bundle savedInstanceState) { |
| 52 | super.onCreate(savedInstanceState); |
| 53 | |
| 54 | FragmentManager fm = getSupportFragmentManager(); |
| 55 | |
| 56 | // Create the list fragment and add it as our sole content. |
| 57 | if (fm.findFragmentById(android.R.id.content) == null) { |
| 58 | CursorLoaderListFragment list = new CursorLoaderListFragment(); |
| 59 | fm.beginTransaction().add(android.R.id.content, list).commit(); |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | //BEGIN_INCLUDE(fragment_cursor) |
| 64 | public static class CursorLoaderListFragment extends ListFragment |
| 65 | implements LoaderManager.LoaderCallbacks<Cursor> { |
| 66 | |
| 67 | // This is the Adapter being used to display the list's data. |
| 68 | SimpleCursorAdapter mAdapter; |
| 69 | |
| 70 | // If non-null, this is the current filter the user has provided. |
| 71 | String mCurFilter; |
| 72 | |
| 73 | @Override public void onActivityCreated(Bundle savedInstanceState) { |
| 74 | super.onActivityCreated(savedInstanceState); |
| 75 | |
| 76 | // Give some text to display if there is no data. In a real |
| 77 | // application this would come from a resource. |
| 78 | setEmptyText("No phone numbers"); |
| 79 | |
| 80 | // We have a menu item to show in action bar. |
| 81 | setHasOptionsMenu(true); |
| 82 | |
| 83 | // Create an empty adapter we will use to display the loaded data. |
| 84 | mAdapter = new SimpleCursorAdapter(getActivity(), |
Svetoslav Ganov | a09e21a | 2011-11-14 16:37:43 -0800 | [diff] [blame] | 85 | android.R.layout.simple_list_item_1, null, |
| 86 | new String[] { People.DISPLAY_NAME }, |
| 87 | new int[] { android.R.id.text1}, 0); |
Dianne Hackborn | 9fd3b6e | 2011-02-01 10:38:02 -0800 | [diff] [blame] | 88 | setListAdapter(mAdapter); |
| 89 | |
Dianne Hackborn | be6b6b4 | 2011-06-13 13:48:13 -0700 | [diff] [blame] | 90 | // Start out with a progress indicator. |
| 91 | setListShown(false); |
| 92 | |
Dianne Hackborn | 9fd3b6e | 2011-02-01 10:38:02 -0800 | [diff] [blame] | 93 | // Prepare the loader. Either re-connect with an existing one, |
| 94 | // or start a new one. |
| 95 | getLoaderManager().initLoader(0, null, this); |
| 96 | } |
| 97 | |
| 98 | @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { |
| 99 | // Place an action bar item for searching. |
Svetoslav Ganov | a09e21a | 2011-11-14 16:37:43 -0800 | [diff] [blame] | 100 | MenuItem item = menu.add("Search"); |
| 101 | item.setIcon(android.R.drawable.ic_menu_search); |
Dianne Hackborn | 80df91c | 2012-05-29 13:58:13 -0700 | [diff] [blame] | 102 | MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS |
| 103 | | MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW); |
Svetoslav Ganov | a09e21a | 2011-11-14 16:37:43 -0800 | [diff] [blame] | 104 | View searchView = SearchViewCompat.newSearchView(getActivity()); |
| 105 | if (searchView != null) { |
| 106 | SearchViewCompat.setOnQueryTextListener(searchView, |
| 107 | new OnQueryTextListenerCompat() { |
| 108 | @Override |
| 109 | public boolean onQueryTextChange(String newText) { |
| 110 | // Called when the action bar search text has changed. Update |
| 111 | // the search filter, and restart the loader to do a new query |
| 112 | // with this filter. |
Dianne Hackborn | 80df91c | 2012-05-29 13:58:13 -0700 | [diff] [blame] | 113 | String newFilter = !TextUtils.isEmpty(newText) ? newText : null; |
| 114 | // Don't do anything if the filter hasn't actually changed. |
| 115 | // Prevents restarting the loader when restoring state. |
| 116 | if (mCurFilter == null && newFilter == null) { |
| 117 | return true; |
| 118 | } |
| 119 | if (mCurFilter != null && mCurFilter.equals(newFilter)) { |
| 120 | return true; |
| 121 | } |
| 122 | mCurFilter = newFilter; |
Svetoslav Ganov | a09e21a | 2011-11-14 16:37:43 -0800 | [diff] [blame] | 123 | getLoaderManager().restartLoader(0, null, CursorLoaderListFragment.this); |
| 124 | return true; |
| 125 | } |
| 126 | }); |
| 127 | MenuItemCompat.setActionView(item, searchView); |
| 128 | } |
Dianne Hackborn | 9fd3b6e | 2011-02-01 10:38:02 -0800 | [diff] [blame] | 129 | } |
| 130 | |
| 131 | @Override public void onListItemClick(ListView l, View v, int position, long id) { |
| 132 | // Insert desired behavior here. |
| 133 | Log.i("FragmentComplexList", "Item clicked: " + id); |
| 134 | } |
| 135 | |
| 136 | // These are the Contacts rows that we will retrieve. |
| 137 | static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { |
Svetoslav Ganov | a09e21a | 2011-11-14 16:37:43 -0800 | [diff] [blame] | 138 | People._ID, |
| 139 | People.DISPLAY_NAME, |
Dianne Hackborn | 9fd3b6e | 2011-02-01 10:38:02 -0800 | [diff] [blame] | 140 | }; |
| 141 | |
| 142 | public Loader<Cursor> onCreateLoader(int id, Bundle args) { |
| 143 | // This is called when a new Loader needs to be created. This |
| 144 | // sample only has one Loader, so we don't care about the ID. |
| 145 | // First, pick the base URI to use depending on whether we are |
| 146 | // currently filtering. |
| 147 | Uri baseUri; |
| 148 | if (mCurFilter != null) { |
Svetoslav Ganov | a09e21a | 2011-11-14 16:37:43 -0800 | [diff] [blame] | 149 | baseUri = Uri.withAppendedPath(People.CONTENT_FILTER_URI, Uri.encode(mCurFilter)); |
Dianne Hackborn | 9fd3b6e | 2011-02-01 10:38:02 -0800 | [diff] [blame] | 150 | } else { |
Svetoslav Ganov | a09e21a | 2011-11-14 16:37:43 -0800 | [diff] [blame] | 151 | baseUri = People.CONTENT_URI; |
Dianne Hackborn | 9fd3b6e | 2011-02-01 10:38:02 -0800 | [diff] [blame] | 152 | } |
| 153 | |
| 154 | // Now create and return a CursorLoader that will take care of |
| 155 | // creating a Cursor for the data being displayed. |
Svetoslav Ganov | a09e21a | 2011-11-14 16:37:43 -0800 | [diff] [blame] | 156 | String select = "((" + People.DISPLAY_NAME + " NOTNULL) AND (" |
| 157 | + People.DISPLAY_NAME + " != '' ))"; |
Dianne Hackborn | 9fd3b6e | 2011-02-01 10:38:02 -0800 | [diff] [blame] | 158 | return new CursorLoader(getActivity(), baseUri, |
| 159 | CONTACTS_SUMMARY_PROJECTION, select, null, |
Svetoslav Ganov | a09e21a | 2011-11-14 16:37:43 -0800 | [diff] [blame] | 160 | People.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); |
Dianne Hackborn | 9fd3b6e | 2011-02-01 10:38:02 -0800 | [diff] [blame] | 161 | } |
| 162 | |
| 163 | public void onLoadFinished(Loader<Cursor> loader, Cursor data) { |
| 164 | // Swap the new cursor in. (The framework will take care of closing the |
| 165 | // old cursor once we return.) |
| 166 | mAdapter.swapCursor(data); |
Dianne Hackborn | be6b6b4 | 2011-06-13 13:48:13 -0700 | [diff] [blame] | 167 | |
| 168 | // The list should now be shown. |
| 169 | if (isResumed()) { |
| 170 | setListShown(true); |
| 171 | } else { |
| 172 | setListShownNoAnimation(true); |
| 173 | } |
Dianne Hackborn | 9fd3b6e | 2011-02-01 10:38:02 -0800 | [diff] [blame] | 174 | } |
| 175 | |
| 176 | public void onLoaderReset(Loader<Cursor> loader) { |
| 177 | // This is called when the last Cursor provided to onLoadFinished() |
| 178 | // above is about to be closed. We need to make sure we are no |
| 179 | // longer using it. |
| 180 | mAdapter.swapCursor(null); |
| 181 | } |
| 182 | } |
| 183 | //END_INCLUDE(fragment_cursor) |
| 184 | } |