11package com .parse .ui .widget .sample ;
22
3+ import android .database .DataSetObserver ;
34import android .os .Bundle ;
45import android .support .annotation .Nullable ;
56import android .support .v7 .app .AppCompatActivity ;
6- import android .util .Log ;
7+ import android .view .LayoutInflater ;
8+ import android .view .View ;
9+ import android .view .ViewGroup ;
10+ import android .widget .BaseAdapter ;
711import android .widget .ListView ;
8- import android .widget .Toast ;
12+ import android .widget .ProgressBar ;
13+ import android .widget .TextView ;
914
15+ import com .parse .FindCallback ;
1016import com .parse .ParseException ;
1117import com .parse .ParseObject ;
1218import com .parse .ParseQuery ;
13- import com .parse .ParseQueryAdapter ;
19+ import com .parse .widget . util . ParseQueryPager ;
1420
1521import java .util .List ;
1622
23+ import bolts .CancellationTokenSource ;
1724
18- public class ListActivity extends AppCompatActivity {
1925
20- private static final String TAG = "ListActivity" ;
26+ public class ListActivity extends AppCompatActivity {
2127
2228 @ Override
2329 protected void onCreate (@ Nullable Bundle savedInstanceState ) {
@@ -26,32 +32,205 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
2632
2733 ListView listView = (ListView ) findViewById (R .id .list );
2834
29- ParseQueryAdapter <ParseObject > adapter = new ParseQueryAdapter <>(this ,
30- new ParseQueryAdapter .QueryFactory <ParseObject >() {
31- @ Override
32- public ParseQuery <ParseObject > create () {
33- return ParseQuery .getQuery ("Contact" )
34- .orderByAscending ("name" )
35- .setCachePolicy (ParseQuery .CachePolicy .CACHE_THEN_NETWORK );
35+ MyAdapter <ParseObject > adapter = new MyAdapter <>(createPager ());
36+ listView .setAdapter (adapter );
37+ }
38+
39+ private ParseQueryPager <ParseObject > createPager () {
40+ ParseQuery <ParseObject > query = ParseQuery .getQuery ("TestObject" );
41+ query .orderByAscending ("name" );
42+ query .setCachePolicy (ParseQuery .CachePolicy .CACHE_THEN_NETWORK );
43+ return new ParseQueryPager <>(query , 25 );
44+ }
45+
46+ public static class MyAdapter <T extends ParseObject > extends BaseAdapter {
47+
48+ public static final int TYPE_ITEM = 0 ;
49+ public static final int TYPE_NEXT = 1 ;
50+
51+ private static class ItemViewHolder extends ViewHolder {
52+ TextView textView ;
53+
54+ public ItemViewHolder (View itemView ) {
55+ super (itemView );
56+ textView = (TextView ) itemView ;
57+ }
58+ }
59+
60+ private static class NextViewHolder extends ViewHolder {
61+ TextView textView ;
62+ ProgressBar progressBar ;
63+
64+ public NextViewHolder (View itemView ) {
65+ super (itemView );
66+ textView = (TextView ) itemView .findViewById (android .R .id .text1 );
67+ progressBar = (ProgressBar ) itemView .findViewById (android .R .id .progress );
68+ }
69+
70+ public void setLoading (boolean loading ) {
71+ if (loading ) {
72+ textView .setVisibility (View .INVISIBLE );
73+ progressBar .setVisibility (View .VISIBLE );
74+ progressBar .setIndeterminate (true );
75+ } else {
76+ textView .setVisibility (View .VISIBLE );
77+ progressBar .setVisibility (View .INVISIBLE );
78+ progressBar .setIndeterminate (false );
79+ }
80+ }
81+ }
82+
83+ private final Object lock = new Object ();
84+ private ParseQueryPager <T > pager ;
85+ private CancellationTokenSource cts ;
86+
87+ public MyAdapter (ParseQueryPager <T > pager ) {
88+ swap (pager );
89+ }
90+
91+ public ParseQueryPager <T > getPager () {
92+ synchronized (lock ) {
93+ return pager ;
94+ }
95+ }
96+
97+ public void swap (ParseQueryPager <T > pager ) {
98+ synchronized (lock ) {
99+ if (cts != null ) {
100+ cts .cancel ();
101+ }
102+ this .pager = pager ;
103+ this .cts = new CancellationTokenSource ();
104+ }
105+ }
106+
107+ private void loadNextPage () {
108+ final ParseQueryPager <T > pager ;
109+ final CancellationTokenSource cts ;
110+
111+ synchronized (lock ) {
112+ pager = this .pager ;
113+ cts = this .cts ;
114+ }
115+
116+ // Utilizing callbacks to support CACHE_THEN_NETWORK
117+ pager .loadNextPage (new FindCallback <T >() {
118+ @ Override
119+ public void done (List <T > results , ParseException e ) {
120+ if (results == null && e == null ) { // cancelled
121+ return ;
122+ }
123+
124+ if (e != null ) {
125+ notifyDataSetChanged ();
126+ return ;
36127 }
37- }, android .R .layout .simple_list_item_1 );
38- adapter .setTextKey ("name" );
39- adapter .addOnQueryLoadListener (new ParseQueryAdapter .OnQueryLoadListener <ParseObject >() {
40- @ Override
41- public void onLoading () {
42- Log .d (TAG , "loading" );
43- }
44-
45- @ Override
46- public void onLoaded (List <ParseObject > objects , Exception e ) {
47- Log .d (TAG , "loaded" );
48- if (e != null
49- && e instanceof ParseException
50- && ((ParseException ) e ).getCode () != ParseException .CACHE_MISS ) {
51- Toast .makeText (ListActivity .this , "Error: " + e .getMessage (), Toast .LENGTH_LONG ).show ();
128+
129+ notifyDataSetChanged ();
52130 }
131+ }, cts .getToken ());
132+ notifyDataSetChanged ();
133+ }
134+
135+ @ Override
136+ public int getCount () {
137+ ParseQueryPager <T > pager = getPager ();
138+ return pager .getObjects ().size () + (pager .hasNextPage () ? 1 : 0 );
139+ }
140+
141+ @ Override
142+ public T getItem (int position ) {
143+ List <T > objects = getPager ().getObjects ();
144+ return position < objects .size () ? objects .get (position ) : null ;
145+ }
146+
147+ @ Override
148+ public long getItemId (int position ) {
149+ return position ;
150+ }
151+
152+ @ Override
153+ public final View getView (int position , View convertView , ViewGroup parent ) {
154+ ViewHolder holder ;
155+ View view ;
156+ if (convertView == null ) {
157+ holder = onCreateViewHolder (parent , getItemViewType (position ));
158+ view = holder .itemView ;
159+ view .setTag (holder );
160+ } else {
161+ view = convertView ;
162+ holder = (ViewHolder ) view .getTag ();
53163 }
54- });
55- listView .setAdapter (adapter );
164+ onBindViewHolder (holder , position );
165+ return view ;
166+ }
167+
168+ public ViewHolder onCreateViewHolder (ViewGroup parent , int viewType ) {
169+ LayoutInflater inflater = LayoutInflater .from (parent .getContext ());
170+ switch (viewType ) {
171+ case TYPE_ITEM : {
172+ View v = inflater .inflate (android .R .layout .simple_list_item_1 , parent , false );
173+ return new ItemViewHolder (v );
174+ }
175+ case TYPE_NEXT : {
176+ View v = inflater .inflate (R .layout .load_more_list_item , parent , false );
177+ v .setOnClickListener (new View .OnClickListener () {
178+ @ Override
179+ public void onClick (View v ) {
180+ if (!getPager ().isLoadingNextPage ()) {
181+ loadNextPage ();
182+ }
183+ }
184+ });
185+ NextViewHolder vh = new NextViewHolder (v );
186+ vh .textView .setText (R .string .load_more );
187+ return vh ;
188+ }
189+ default :
190+ throw new IllegalStateException ("Invalid view type: " + viewType );
191+ }
192+ }
193+
194+ public void onBindViewHolder (ViewHolder holder , int position ) {
195+ switch (getItemViewType (position )) {
196+ case TYPE_ITEM : {
197+ ParseObject item = getItem (position );
198+
199+ ItemViewHolder vh = (ItemViewHolder ) holder ;
200+ vh .textView .setText (item .getString ("name" ));
201+ }
202+ break ;
203+ case TYPE_NEXT : {
204+ NextViewHolder vh = (NextViewHolder ) holder ;
205+ vh .setLoading (getPager ().isLoadingNextPage ());
206+ }
207+ break ;
208+ }
209+ }
210+
211+ @ Override
212+ public int getViewTypeCount () {
213+ return 2 ;
214+ }
215+
216+ @ Override
217+ public int getItemViewType (int position ) {
218+ return position < getPager ().getObjects ().size () ? TYPE_ITEM : TYPE_NEXT ;
219+ }
220+
221+ @ Override
222+ public void registerDataSetObserver (DataSetObserver observer ) {
223+ super .registerDataSetObserver (observer );
224+ // We use this method as a notification that the ListView is bound to the adapter.
225+ loadNextPage ();
226+ }
227+
228+ public static class ViewHolder {
229+ private View itemView ;
230+
231+ public ViewHolder (View itemView ) {
232+ this .itemView = itemView ;
233+ }
234+ }
56235 }
57236}
0 commit comments