Skip to content

Commit 01cfc30

Browse files
committed
Update ListView sample to utilize ParseQueryPager
1 parent 57f43eb commit 01cfc30

File tree

3 files changed

+229
-29
lines changed

3 files changed

+229
-29
lines changed
Lines changed: 208 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,29 @@
11
package com.parse.ui.widget.sample;
22

3+
import android.database.DataSetObserver;
34
import android.os.Bundle;
45
import android.support.annotation.Nullable;
56
import 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;
711
import android.widget.ListView;
8-
import android.widget.Toast;
12+
import android.widget.ProgressBar;
13+
import android.widget.TextView;
914

15+
import com.parse.FindCallback;
1016
import com.parse.ParseException;
1117
import com.parse.ParseObject;
1218
import com.parse.ParseQuery;
13-
import com.parse.ParseQueryAdapter;
19+
import com.parse.widget.util.ParseQueryPager;
1420

1521
import 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
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:layout_width="match_parent"
4+
android:layout_height="wrap_content"
5+
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
6+
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
7+
android:minHeight="?android:attr/listPreferredItemHeightSmall" >
8+
<TextView
9+
android:id="@android:id/text1"
10+
android:layout_width="match_parent"
11+
android:layout_height="wrap_content"
12+
android:textAppearance="?android:attr/textAppearanceListItemSmall"
13+
android:layout_gravity="center_vertical" />
14+
<ProgressBar
15+
android:id="@android:id/progress"
16+
android:layout_width="wrap_content"
17+
android:layout_height="wrap_content"
18+
android:layout_gravity="center"/>
19+
</FrameLayout>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
<resources>
22
<string name="app_name">ParseUI-Widget Sample</string>
33
<string name="list_name">ListView Sample</string>
4+
5+
<string name="load_more">Load more…</string>
46
</resources>

0 commit comments

Comments
 (0)