Skip to content

Commit f413ef0

Browse files
committed
Add sample for RecyclerView
1 parent cc599f0 commit f413ef0

File tree

7 files changed

+281
-0
lines changed

7 files changed

+281
-0
lines changed

ParseUI-Widget-Sample/build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ android {
2121

2222
dependencies {
2323
compile 'com.android.support:appcompat-v7:23.1.1'
24+
compile 'com.android.support:recyclerview-v7:23.1.0'
2425
compile project(':ParseUI-Widget')
2526

2627
testCompile 'junit:junit:4.12'

ParseUI-Widget-Sample/src/main/AndroidManifest.xml

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
</intent-filter>
2929
</activity>
3030

31+
<activity
32+
android:name=".RecyclerActivity"
33+
android:label="@string/recycler_name"/>
34+
3135
<activity
3236
android:name=".ListActivity"
3337
android:label="@string/list_name"/>

ParseUI-Widget-Sample/src/main/java/com/parse/ui/widget/sample/MainActivity.java

+6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ protected void onCreate(Bundle savedInstanceState) {
1212
super.onCreate(savedInstanceState);
1313
setContentView(R.layout.activity_main);
1414

15+
findViewById(R.id.sample_recycler).setOnClickListener(this);
1516
findViewById(R.id.sample_list).setOnClickListener(this);
1617
}
1718

@@ -21,6 +22,11 @@ protected void onCreate(Bundle savedInstanceState) {
2122
public void onClick(View v) {
2223
int id = v.getId();
2324
switch (id) {
25+
case R.id.sample_recycler: {
26+
Intent intent = new Intent(this, RecyclerActivity.class);
27+
startActivity(intent);
28+
break;
29+
}
2430
case R.id.sample_list: {
2531
Intent intent = new Intent(this, ListActivity.class);
2632
startActivity(intent);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
package com.parse.ui.widget.sample;
2+
3+
import android.os.Bundle;
4+
import android.support.v4.widget.SwipeRefreshLayout;
5+
import android.support.v7.app.AppCompatActivity;
6+
import android.support.v7.widget.LinearLayoutManager;
7+
import android.support.v7.widget.RecyclerView;
8+
import android.view.LayoutInflater;
9+
import android.view.View;
10+
import android.view.ViewGroup;
11+
import android.widget.ProgressBar;
12+
import android.widget.TextView;
13+
14+
import com.parse.ParseObject;
15+
import com.parse.ParseQuery;
16+
import com.parse.widget.util.ParseQueryPager;
17+
18+
import java.util.List;
19+
20+
import bolts.CancellationTokenSource;
21+
import bolts.Continuation;
22+
import bolts.Task;
23+
24+
public class RecyclerActivity extends AppCompatActivity {
25+
26+
private SwipeRefreshLayout refreshLayout;
27+
28+
private MyAdapter<ParseObject> adapter;
29+
30+
@Override
31+
protected void onCreate(Bundle savedInstanceState) {
32+
super.onCreate(savedInstanceState);
33+
setContentView(R.layout.activity_recycler);
34+
35+
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler);
36+
37+
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
38+
recyclerView.setLayoutManager(layoutManager);
39+
40+
adapter = new MyAdapter<>(createPager());
41+
recyclerView.setAdapter(adapter);
42+
43+
refreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresh);
44+
refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
45+
@Override
46+
public void onRefresh() {
47+
final ParseQueryPager<ParseObject> pager = createPager();
48+
pager.loadNextPage().continueWith(new Continuation<List<ParseObject>, Void>() {
49+
@Override
50+
public Void then(Task<List<ParseObject>> task) throws Exception {
51+
refreshLayout.setRefreshing(false);
52+
53+
if (task.isCancelled()) {
54+
return null;
55+
}
56+
57+
if (task.isFaulted()) {
58+
return null;
59+
}
60+
61+
adapter.swap(pager);
62+
adapter.notifyDataSetChanged();
63+
return null;
64+
}
65+
}, Task.UI_THREAD_EXECUTOR);
66+
}
67+
});
68+
}
69+
70+
private ParseQueryPager<ParseObject> createPager() {
71+
ParseQuery<ParseObject> query = ParseQuery.getQuery("TestObject");
72+
query.orderByAscending("name");
73+
return new ParseQueryPager<>(query, 25);
74+
}
75+
76+
public static class MyAdapter<T extends ParseObject> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
77+
78+
private static final int TYPE_ITEM = 0;
79+
private static final int TYPE_NEXT = 1;
80+
81+
private static class ItemViewHolder extends RecyclerView.ViewHolder {
82+
TextView textView;
83+
84+
public ItemViewHolder(View itemView) {
85+
super(itemView);
86+
textView = (TextView) itemView;
87+
}
88+
}
89+
90+
private static class NextViewHolder extends RecyclerView.ViewHolder {
91+
TextView textView;
92+
ProgressBar progressBar;
93+
94+
public NextViewHolder(View itemView) {
95+
super(itemView);
96+
textView = (TextView) itemView.findViewById(android.R.id.text1);
97+
progressBar = (ProgressBar) itemView.findViewById(android.R.id.progress);
98+
}
99+
100+
public void setLoading(boolean loading) {
101+
if (loading) {
102+
textView.setVisibility(View.INVISIBLE);
103+
progressBar.setVisibility(View.VISIBLE);
104+
progressBar.setIndeterminate(true);
105+
} else {
106+
textView.setVisibility(View.VISIBLE);
107+
progressBar.setVisibility(View.INVISIBLE);
108+
progressBar.setIndeterminate(false);
109+
}
110+
}
111+
}
112+
113+
private final Object lock = new Object();
114+
private ParseQueryPager<T> pager;
115+
private CancellationTokenSource cts;
116+
117+
public MyAdapter(ParseQueryPager<T> pager) {
118+
swap(pager);
119+
}
120+
121+
public ParseQueryPager<T> getPager() {
122+
synchronized (lock) {
123+
return pager;
124+
}
125+
}
126+
127+
public void swap(ParseQueryPager<T> pager) {
128+
synchronized (lock) {
129+
if (cts != null) {
130+
cts.cancel();
131+
}
132+
this.pager = pager;
133+
this.cts = new CancellationTokenSource();
134+
}
135+
}
136+
137+
private void loadNextPage() {
138+
final ParseQueryPager<T> pager;
139+
final CancellationTokenSource cts;
140+
141+
synchronized (lock) {
142+
pager = this.pager;
143+
cts = this.cts;
144+
}
145+
146+
final int oldSize = pager.getObjects().size();
147+
148+
// Uses Tasks, so it does not support CACHE_THEN_NETWORK. See ListActivity for a sample
149+
// with callbacks.
150+
pager.loadNextPage(cts.getToken()).continueWith(new Continuation<List<T>, Task<Void>>() {
151+
@Override
152+
public Task<Void> then(Task<List<T>> task) throws Exception {
153+
if (task.isCancelled()) {
154+
return null;
155+
}
156+
157+
if (task.isFaulted()) {
158+
notifyDataSetChanged();
159+
return null;
160+
}
161+
162+
// Remove "Load more..."
163+
notifyItemRemoved(oldSize);
164+
165+
// Insert results
166+
List<T> results = task.getResult();
167+
if (results.size() > 0) {
168+
notifyItemRangeInserted(oldSize, results.size());
169+
}
170+
171+
if (pager.hasNextPage()) {
172+
// Add "Load more..."
173+
notifyItemInserted(pager.getObjects().size());
174+
}
175+
return null;
176+
}
177+
});
178+
notifyItemChanged(oldSize);
179+
}
180+
181+
@Override
182+
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
183+
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
184+
switch (viewType) {
185+
case TYPE_ITEM: {
186+
View v = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);
187+
return new ItemViewHolder(v);
188+
}
189+
case TYPE_NEXT: {
190+
View v = inflater.inflate(R.layout.load_more_list_item, parent, false);
191+
v.setOnClickListener(new View.OnClickListener() {
192+
@Override
193+
public void onClick(View v) {
194+
if (!getPager().isLoadingNextPage()) {
195+
loadNextPage();
196+
}
197+
}
198+
});
199+
NextViewHolder vh = new NextViewHolder(v);
200+
vh.textView.setText(R.string.load_more);
201+
return vh;
202+
}
203+
default:
204+
throw new IllegalStateException("Invalid view type: " + viewType);
205+
}
206+
}
207+
208+
@Override
209+
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
210+
switch (getItemViewType(position)) {
211+
case TYPE_ITEM: {
212+
ParseObject item = getPager().getObjects().get(position);
213+
214+
ItemViewHolder vh = (ItemViewHolder) holder;
215+
vh.textView.setText(item.getString("name"));
216+
}
217+
break;
218+
case TYPE_NEXT: {
219+
NextViewHolder vh = (NextViewHolder) holder;
220+
vh.setLoading(getPager().isLoadingNextPage());
221+
}
222+
break;
223+
}
224+
}
225+
226+
@Override
227+
public int getItemCount() {
228+
ParseQueryPager<T> pager = getPager();
229+
return pager.getObjects().size() + (pager.hasNextPage() ? 1 : 0);
230+
}
231+
232+
@Override
233+
public int getItemViewType(int position) {
234+
return position < getPager().getObjects().size() ? TYPE_ITEM : TYPE_NEXT;
235+
}
236+
237+
@Override
238+
public void registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer) {
239+
super.registerAdapterDataObserver(observer);
240+
// We use this method as a notification that the RecyclerView is bound to the adapter.
241+
loadNextPage();
242+
}
243+
}
244+
}

ParseUI-Widget-Sample/src/main/res/layout/activity_main.xml

+6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@
1111
android:orientation="vertical"
1212
tools:context="com.parse.ui.widget.sample.MainActivity">
1313

14+
<Button
15+
android:id="@+id/sample_recycler"
16+
android:layout_width="match_parent"
17+
android:layout_height="wrap_content"
18+
android:text="@string/recycler_name"/>
19+
1420
<Button
1521
android:id="@+id/sample_list"
1622
android:layout_width="match_parent"
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:orientation="vertical"
4+
android:layout_width="match_parent"
5+
android:layout_height="match_parent">
6+
7+
<android.support.v4.widget.SwipeRefreshLayout
8+
android:id="@+id/refresh"
9+
android:layout_width="match_parent"
10+
android:layout_height="match_parent">
11+
12+
<android.support.v7.widget.RecyclerView
13+
android:id="@+id/recycler"
14+
android:layout_width="match_parent"
15+
android:layout_height="match_parent"/>
16+
17+
</android.support.v4.widget.SwipeRefreshLayout>
18+
19+
</FrameLayout>

ParseUI-Widget-Sample/src/main/res/values/strings.xml

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<resources>
22
<string name="app_name">ParseUI-Widget Sample</string>
3+
<string name="recycler_name">RecyclerView Sample</string>
34
<string name="list_name">ListView Sample</string>
45

56
<string name="load_more">Load more…</string>

0 commit comments

Comments
 (0)