EndlessListActivity.java (6808B)
1 /** 2 * 3 */ 4 package de.mtbnews.android; 5 6 import java.util.ArrayList; 7 import java.util.List; 8 9 import android.app.ListActivity; 10 import android.content.SharedPreferences; 11 import android.preference.PreferenceManager; 12 import android.widget.AbsListView; 13 import android.widget.BaseAdapter; 14 import android.widget.ListView; 15 import android.widget.AbsListView.OnScrollListener; 16 17 /** 18 * Erweitert die Oberklasse {@link ListActivity} für "endlose" Listen, die 19 * seitenweise vom Server geladen werden. Bei Erreichen des Endes wird 20 * automatisch der nächste Bereich nachgeladen. 21 * 22 * @author dankert 23 * 24 */ 25 public abstract class EndlessListActivity<T> extends ListActivity 26 { 27 /** 28 * boolean-Parameter der ansagt, dass die Anzeige mit dem letzten Element 29 * beginnen soll. 30 */ 31 public static final String LAST_POST = "last_post"; 32 33 /** 34 * boolean-Parameter der ansagt, dass die Anzeige mit dem ersten Element 35 * beginnen soll. 36 */ 37 public static final String FIRST_POST = "first_post"; 38 39 private boolean loadingInProgress = true; 40 41 protected int displayFrom; 42 protected int displayTo; 43 protected boolean autoScrollDown; 44 45 /** 46 * Die in dieser ListActivity enthaltene Liste.<br> 47 * Die Referenz auf diese Liste darf sich nicht ändern, da der ListAdapter 48 * mit dieser Instanz verbunden ist. Durch 'final' wird das sicher gestellt. 49 */ 50 final protected List<T> entries = new ArrayList<T>(); 51 52 private SharedPreferences prefs; 53 54 private boolean firstLoad; 55 56 /** 57 * Absolute Anzahl aller verfügbaren Elemente. 58 * 59 * @return Anzahl 60 */ 61 protected abstract int getTotalSize(); 62 63 protected boolean isAutoScrolldown() 64 { 65 return prefs.getBoolean("scroll_down", false); 66 } 67 68 /** 69 * Initiales Laden der ersten Listeneinträge. 70 */ 71 protected void initialLoad() 72 { 73 firstLoad = true; 74 prefs = PreferenceManager.getDefaultSharedPreferences(this); 75 final int numLoad = Integer.parseInt(prefs.getString("num_load", "10")); 76 77 if (getIntent().getBooleanExtra(FIRST_POST, false)) 78 autoScrollDown = false; 79 else if (getIntent().getBooleanExtra(LAST_POST, false)) 80 autoScrollDown = true; 81 else 82 autoScrollDown = isAutoScrolldown(); 83 84 if (autoScrollDown) 85 { 86 loadEntries(new OnListLoadedListener<T>() 87 { 88 89 @Override 90 public void listLoaded(List<T> list) 91 { 92 final int end = getTotalSize(); 93 final int start = Math.max(0, end - numLoad); 94 95 loadEntries(new OnListLoadedListener<T>() 96 { 97 98 @Override 99 public void listLoaded(List<T> list) 100 { 101 entries.clear(); 102 entries.addAll(list); 103 ((BaseAdapter) getListAdapter()).notifyDataSetChanged(); 104 105 displayFrom = start; 106 displayTo = end; 107 108 getListView().setSelection(entries.size() - 1); 109 110 setOnScrollListener(); 111 112 loadingInProgress = false; 113 } 114 }, start, end); 115 116 } 117 }, 0, 1); 118 119 } 120 else 121 { 122 final int start = 0; 123 final int end = numLoad - 1; 124 125 loadEntries(new OnListLoadedListener<T>() 126 { 127 128 @Override 129 public void listLoaded(List<T> list) 130 { 131 entries.clear(); 132 entries.addAll(list); 133 ((BaseAdapter) getListAdapter()).notifyDataSetChanged(); 134 135 displayFrom = start; 136 displayTo = start + entries.size() - 1; 137 138 setOnScrollListener(); 139 140 loadingInProgress = false; 141 } 142 }, start, end); 143 } 144 145 } 146 147 /** 148 * @param from 149 * @param to 150 * @param firstLoad 151 * @return gelandene Elemente 152 */ 153 abstract protected void loadEntries(OnListLoadedListener<T> onListLoaded, final int from, final int to, 154 boolean firstLoad); 155 156 /** 157 * @param onListLoaded 158 * @param from 159 * @param to 160 * @param firstLoad 161 * @return gelandene Elemente 162 */ 163 private void loadEntries(OnListLoadedListener<T> onListLoaded, int from, int to) 164 { 165 loadEntries(onListLoaded, from, to, firstLoad); 166 firstLoad = false; 167 } 168 169 private void setOnScrollListener() 170 { 171 final ListView list = getListView(); 172 173 /** 174 * Weitere List-Einträge automatisch nachladen. 175 */ 176 list.setOnScrollListener(new OnScrollListener() 177 { 178 @Override 179 public void onScrollStateChanged(AbsListView view, int scrollState) 180 { 181 } 182 183 /** 184 * Callback method to be invoked when the list or grid has been 185 * scrolled. This will be called after the scroll has completed 186 * Parameters 187 * 188 * @param view 189 * The view whose scroll state is being reported 190 * @param firstVisibleItem 191 * the index of the first visible cell (ignore if 192 * visibleItemCount == 0) 193 * @param visibleItemCount 194 * the number of visible cells 195 * @param totalItemCount 196 * the number of items in the list adaptor {@inheritDoc} 197 * 198 * @see android.widget.AbsListView.OnScrollListener#onScroll(android.widget.AbsListView, 199 * int, int, int) 200 */ 201 @Override 202 public void onScroll(AbsListView view, final int firstVisibleItem, final int visibleItemCount, 203 final int totalItemCount) 204 { 205 206 // Letztes Item, dass angezeigt wird. 207 int lastInScreen = firstVisibleItem + visibleItemCount; 208 209 if (autoScrollDown) 210 { 211 // Sind wir am oberen Rand der Liste und die Liste ist noch 212 // nicht vollständig geladen? 213 if (firstVisibleItem == 0 && displayFrom > 0 && !loadingInProgress) 214 { 215 loadingInProgress = true; 216 217 int start = Math.max(0, displayFrom - Integer.parseInt(prefs.getString("num_load", "10"))); 218 219 int end = displayFrom - 1; 220 221 loadEntries(new OnListLoadedListener<T>() 222 { 223 224 @Override 225 public void listLoaded(List<T> list) 226 { 227 int loadedSize = list.size(); 228 displayFrom -= loadedSize; 229 230 list.addAll(entries); 231 entries.clear(); 232 entries.addAll(list); 233 234 ((BaseAdapter) getListAdapter()).notifyDataSetChanged(); 235 236 // Zur gleichen Position springen (die jetzt 237 // aber etwas weiter nach hinten verschoben 238 // ist). 239 getListView().setSelection(firstVisibleItem + loadedSize); 240 241 loadingInProgress = false; 242 } 243 }, start, end); 244 245 } 246 } 247 else 248 { 249 // Sind wir am unterenRand der Liste? 250 if ((lastInScreen == totalItemCount) && (totalItemCount < getTotalSize()) && !(loadingInProgress)) 251 { 252 loadingInProgress = true; 253 254 int start = displayTo + 1; 255 int end = start + Integer.parseInt(prefs.getString("num_load", "10")) - 1; 256 257 loadEntries(new OnListLoadedListener<T>() 258 { 259 @Override 260 public void listLoaded(List<T> list) 261 { 262 int loadedSize = list.size(); 263 entries.addAll(list); 264 265 displayTo += loadedSize; 266 267 ((BaseAdapter) getListAdapter()).notifyDataSetChanged(); 268 269 loadingInProgress = false; 270 } 271 }, start, end); 272 273 } 274 } 275 } 276 }); 277 } 278 279 interface OnListLoadedListener<T> 280 { 281 abstract void listLoaded(List<T> list); 282 } 283 }