1 /* 2 * Copyright 2016 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 17 package com.example.android.swiperefreshmultipleviews; 18 19 import com.example.android.common.dummydata.Cheeses; 20 import com.example.android.common.logger.Log; 21 22 import android.os.AsyncTask; 23 import android.os.Bundle; 24 import android.support.v4.app.Fragment; 25 import android.support.v4.widget.SwipeRefreshLayout; 26 import android.view.LayoutInflater; 27 import android.view.Menu; 28 import android.view.MenuInflater; 29 import android.view.MenuItem; 30 import android.view.View; 31 import android.view.ViewGroup; 32 import android.widget.ArrayAdapter; 33 import android.widget.GridView; 34 35 import java.util.List; 36 37 /** 38 * A sample which shows how to use {@link android.support.v4.widget.SwipeRefreshLayout} to add 39 * the 'swipe-to-refresh' gesture to a layout with multiple children. In this sample, 40 * SwipeRefreshLayout contains a scrollable {@link android.widget.GridView}, along with a 41 * {@link android.widget.TextView} empty view. 42 * 43 * <p>To provide an accessible way to trigger the refresh, this app also provides a refresh 44 * action item. 45 * 46 * <p>In this sample app, the refresh updates the GridView with a random set of new items. 47 */ 48 public class SwipeRefreshMultipleViewsFragment extends Fragment { 49 50 private static final String LOG_TAG = SwipeRefreshMultipleViewsFragment.class.getSimpleName(); 51 52 private static final int LIST_ITEM_COUNT = 40; 53 54 /** 55 * The {@link MultiSwipeRefreshLayout} that detects swipe gestures and triggers callbacks in 56 * the app. 57 */ 58 private MultiSwipeRefreshLayout mSwipeRefreshLayout; 59 60 /** 61 * The {@link android.widget.GridView} that displays the content that should be refreshed. 62 */ 63 private GridView mGridView; 64 65 /** 66 * The {@link android.widget.ListAdapter} used to populate the {@link android.widget.GridView} 67 * defined in the previous statement. 68 */ 69 private ArrayAdapter<String> mListAdapter; 70 71 /** 72 * The {@link View} which is displayed when the GridView is empty. 73 */ 74 private View mEmptyView; 75 76 @Override onCreate(Bundle savedInstanceState)77 public void onCreate(Bundle savedInstanceState) { 78 super.onCreate(savedInstanceState); 79 80 // Notify the system to allow an options menu for this fragment. 81 setHasOptionsMenu(true); 82 } 83 84 // BEGIN_INCLUDE (inflate_view) 85 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)86 public View onCreateView(LayoutInflater inflater, ViewGroup container, 87 Bundle savedInstanceState) { 88 View view = inflater.inflate(R.layout.fragment_sample, container, false); 89 90 mSwipeRefreshLayout = (MultiSwipeRefreshLayout) view.findViewById(R.id.swiperefresh); 91 92 // BEGIN_INCLUDE (change_colors) 93 // Set the color scheme of the SwipeRefreshLayout by providing 4 color resource ids 94 mSwipeRefreshLayout.setColorSchemeResources( 95 R.color.swipe_color_1, R.color.swipe_color_2, 96 R.color.swipe_color_3, R.color.swipe_color_4); 97 // END_INCLUDE (change_colors) 98 99 mGridView = (GridView) view.findViewById(android.R.id.list); 100 mEmptyView = view.findViewById(android.R.id.empty); 101 return view; 102 } 103 // END_INCLUDE (inflate_view) 104 105 // BEGIN_INCLUDE (setup_views) 106 @Override onViewCreated(View view, Bundle savedInstanceState)107 public void onViewCreated(View view, Bundle savedInstanceState) { 108 super.onViewCreated(view, savedInstanceState); 109 110 /** 111 * Create an ArrayAdapter to contain the data for the GridView. Each item in the GridView 112 * uses the system-defined simple_list_item_1 layout that contains one TextView. Initially 113 */ 114 mListAdapter = new ArrayAdapter<>( 115 getActivity(), 116 android.R.layout.simple_list_item_1, 117 android.R.id.text1); 118 119 // Set the adapter between the GridView and its backing data. 120 mGridView.setAdapter(mListAdapter); 121 122 // Set the empty view so that it is displayed as needed 123 mGridView.setEmptyView(mEmptyView); 124 125 // BEGIN_INCLUDE (setup_swipeable_children) 126 // Tell the MultiSwipeRefreshLayout which views are swipeable. In this case, the GridView 127 // and empty view. 128 mSwipeRefreshLayout.setSwipeableChildren(android.R.id.list, android.R.id.empty); 129 // END_INCLUDE (setup_swipeable_children) 130 131 // BEGIN_INCLUDE (setup_refreshlistener) 132 /** 133 * Implement {@link SwipeRefreshLayout.OnRefreshListener}. When users do the "swipe to 134 * refresh" gesture, SwipeRefreshLayout invokes 135 * {@link SwipeRefreshLayout.OnRefreshListener#onRefresh onRefresh()}. In 136 * {@link SwipeRefreshLayout.OnRefreshListener#onRefresh onRefresh()}, call a method that 137 * refreshes the content. Call the same method in response to the Refresh action from the 138 * action bar. 139 */ 140 mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { 141 @Override 142 public void onRefresh() { 143 Log.i(LOG_TAG, "onRefresh called from SwipeRefreshLayout"); 144 145 initiateRefresh(); 146 } 147 }); 148 // END_INCLUDE (setup_refreshlistener) 149 } 150 // END_INCLUDE (setup_views) 151 152 @Override onCreateOptionsMenu(Menu menu, MenuInflater inflater)153 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 154 inflater.inflate(R.menu.main_menu, menu); 155 } 156 157 // BEGIN_INCLUDE (setup_refresh_menu_listener) 158 /** 159 * Respond to the user's selection of the Refresh action item. Start the SwipeRefreshLayout 160 * progress bar, then initiate the background task that refreshes the content. 161 */ 162 @Override onOptionsItemSelected(MenuItem item)163 public boolean onOptionsItemSelected(MenuItem item) { 164 switch (item.getItemId()) { 165 case R.id.menu_clear: 166 Log.i(LOG_TAG, "Clear menu item selected"); 167 mListAdapter.clear(); 168 return true; 169 170 case R.id.menu_refresh: 171 Log.i(LOG_TAG, "Refresh menu item selected"); 172 173 // We make sure that the SwipeRefreshLayout is displaying it's refreshing indicator 174 if (!mSwipeRefreshLayout.isRefreshing()) { 175 mSwipeRefreshLayout.setRefreshing(true); 176 } 177 178 // Start our refresh background task 179 initiateRefresh(); 180 181 return true; 182 } 183 184 return super.onOptionsItemSelected(item); 185 } 186 // END_INCLUDE (setup_refresh_menu_listener) 187 188 // BEGIN_INCLUDE (initiate_refresh) 189 /** 190 * By abstracting the refresh process to a single method, the app allows both the 191 * SwipeGestureLayout onRefresh() method and the Refresh action item to refresh the content. 192 */ initiateRefresh()193 private void initiateRefresh() { 194 Log.i(LOG_TAG, "initiateRefresh"); 195 196 /** 197 * Execute the background task, which uses {@link android.os.AsyncTask} to load the data. 198 */ 199 new DummyBackgroundTask().execute(); 200 } 201 // END_INCLUDE (initiate_refresh) 202 203 // BEGIN_INCLUDE (refresh_complete) 204 /** 205 * When the AsyncTask finishes, it calls onRefreshComplete(), which updates the data in the 206 * ListAdapter and turns off the progress bar. 207 */ onRefreshComplete(List<String> result)208 private void onRefreshComplete(List<String> result) { 209 Log.i(LOG_TAG, "onRefreshComplete"); 210 211 // Remove all items from the ListAdapter, and then replace them with the new items 212 mListAdapter.clear(); 213 for (String cheese : result) { 214 mListAdapter.add(cheese); 215 } 216 217 // Stop the refreshing indicator 218 mSwipeRefreshLayout.setRefreshing(false); 219 } 220 // END_INCLUDE (refresh_complete) 221 222 /** 223 * Dummy {@link AsyncTask} which simulates a long running task to fetch new cheeses. 224 */ 225 private class DummyBackgroundTask extends AsyncTask<Void, Void, List<String>> { 226 227 static final int TASK_DURATION = 3 * 1000; // 3 seconds 228 229 @Override doInBackground(Void... params)230 protected List<String> doInBackground(Void... params) { 231 // Sleep for a small amount of time to simulate a background-task 232 try { 233 Thread.sleep(TASK_DURATION); 234 } catch (InterruptedException e) { 235 e.printStackTrace(); 236 } 237 238 // Return a new random list of cheeses 239 return Cheeses.randomList(LIST_ITEM_COUNT); 240 } 241 242 @Override onPostExecute(List<String> result)243 protected void onPostExecute(List<String> result) { 244 super.onPostExecute(result); 245 246 // Tell the Fragment that the refresh has completed 247 onRefreshComplete(result); 248 } 249 250 } 251 }