Skip to content

Add RecyclerView sample #130

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ParseUI-Widget-Sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ android {

dependencies {
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:recyclerview-v7:23.1.0'
compile project(':ParseUI-Widget')

testCompile 'junit:junit:4.12'
Expand Down
4 changes: 4 additions & 0 deletions ParseUI-Widget-Sample/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
</intent-filter>
</activity>

<activity
android:name=".RecyclerActivity"
android:label="@string/recycler_name"/>

<activity
android:name=".ListActivity"
android:label="@string/list_name"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
package com.parse.ui.widget.sample;

import android.database.DataSetObserver;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.Toast;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.parse.FindCallback;
import com.parse.ParseException;
import com.parse.ParseObject;
import com.parse.ParseQuery;
import com.parse.ParseQueryAdapter;
import com.parse.widget.util.ParseQueryPager;

import java.util.List;

import bolts.CancellationTokenSource;

public class ListActivity extends AppCompatActivity {

private static final String TAG = "ListActivity";
public class ListActivity extends AppCompatActivity {

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
Expand All @@ -26,32 +33,230 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {

ListView listView = (ListView) findViewById(R.id.list);

ParseQueryAdapter<ParseObject> adapter = new ParseQueryAdapter<>(this,
new ParseQueryAdapter.QueryFactory<ParseObject>() {
final MyAdapter<ParseObject> adapter = new MyAdapter<>(createPager());
listView.setAdapter(adapter);

final SwipeRefreshLayout refreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresh);
refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
final ParseQueryPager<ParseObject> pager = createPager();
pager.loadNextPage(new FindCallback<ParseObject>() {
@Override
public ParseQuery<ParseObject> create() {
return ParseQuery.getQuery("Contact")
.orderByAscending("name")
.setCachePolicy(ParseQuery.CachePolicy.CACHE_THEN_NETWORK);
public void done(List<ParseObject> objects, ParseException e) {
refreshLayout.setRefreshing(false);

if (objects == null && e == null) { // cancelled
return;
}

if (e != null) {
return;
}

adapter.swap(pager);
adapter.notifyDataSetChanged();
}
}, android.R.layout.simple_list_item_1);
adapter.setTextKey("name");
adapter.addOnQueryLoadListener(new ParseQueryAdapter.OnQueryLoadListener<ParseObject>() {
@Override
public void onLoading() {
Log.d(TAG, "loading");
});
}
});
}

@Override
public void onLoaded(List<ParseObject> objects, Exception e) {
Log.d(TAG, "loaded");
if (e != null
&& e instanceof ParseException
&& ((ParseException) e).getCode() != ParseException.CACHE_MISS) {
Toast.makeText(ListActivity.this, "Error: " + e.getMessage(), Toast.LENGTH_LONG).show();
private ParseQueryPager<ParseObject> createPager() {
ParseQuery<ParseObject> query = ParseQuery.getQuery("TestObject");
query.orderByAscending("name");
query.setCachePolicy(ParseQuery.CachePolicy.CACHE_THEN_NETWORK);
return new ParseQueryPager<>(query, 25);
}

public static class MyAdapter<T extends ParseObject> extends BaseAdapter {

public static final int TYPE_ITEM = 0;
public static final int TYPE_NEXT = 1;

private static class ItemViewHolder extends ViewHolder {
TextView textView;

public ItemViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView;
}
}

private static class NextViewHolder extends ViewHolder {
TextView textView;
ProgressBar progressBar;

public NextViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(android.R.id.text1);
progressBar = (ProgressBar) itemView.findViewById(android.R.id.progress);
}

public void setLoading(boolean loading) {
if (loading) {
textView.setVisibility(View.INVISIBLE);
progressBar.setVisibility(View.VISIBLE);
progressBar.setIndeterminate(true);
} else {
textView.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.INVISIBLE);
progressBar.setIndeterminate(false);
}
}
});
listView.setAdapter(adapter);
}

private final Object lock = new Object();
private ParseQueryPager<T> pager;
private CancellationTokenSource cts;

public MyAdapter(ParseQueryPager<T> pager) {
swap(pager);
}

public ParseQueryPager<T> getPager() {
synchronized (lock) {
return pager;
}
}

public void swap(ParseQueryPager<T> pager) {
synchronized (lock) {
if (cts != null) {
cts.cancel();
}
this.pager = pager;
this.cts = new CancellationTokenSource();
}
}

private void loadNextPage() {
final ParseQueryPager<T> pager;
final CancellationTokenSource cts;

synchronized (lock) {
pager = this.pager;
cts = this.cts;
}

// Utilizing callbacks to support CACHE_THEN_NETWORK
pager.loadNextPage(new FindCallback<T>() {
@Override
public void done(List<T> results, ParseException e) {
if (results == null && e == null) { // cancelled
return;
}

if (e != null) {
notifyDataSetChanged();
return;
}

notifyDataSetChanged();
}
}, cts.getToken());
notifyDataSetChanged();
}

@Override
public int getCount() {
ParseQueryPager<T> pager = getPager();
return pager.getObjects().size() + (pager.hasNextPage() ? 1 : 0);
}

@Override
public T getItem(int position) {
List<T> objects = getPager().getObjects();
return position < objects.size() ? objects.get(position) : null;
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public final View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
View view;
if (convertView == null) {
holder = onCreateViewHolder(parent, getItemViewType(position));
view = holder.itemView;
view.setTag(holder);
} else {
view = convertView;
holder = (ViewHolder) view.getTag();
}
onBindViewHolder(holder, position);
return view;
}

public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType) {
case TYPE_ITEM: {
View v = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);
return new ItemViewHolder(v);
}
case TYPE_NEXT: {
View v = inflater.inflate(R.layout.load_more_list_item, parent, false);
v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!getPager().isLoadingNextPage()) {
loadNextPage();
}
}
});
NextViewHolder vh = new NextViewHolder(v);
vh.textView.setText(R.string.load_more);
return vh;
}
default:
throw new IllegalStateException("Invalid view type: " + viewType);
}
}

public void onBindViewHolder(ViewHolder holder, int position) {
switch (getItemViewType(position)) {
case TYPE_ITEM: {
ParseObject item = getItem(position);

ItemViewHolder vh = (ItemViewHolder) holder;
vh.textView.setText(item.getString("name"));
}
break;
case TYPE_NEXT: {
NextViewHolder vh = (NextViewHolder) holder;
vh.setLoading(getPager().isLoadingNextPage());
}
break;
}
}

@Override
public int getViewTypeCount() {
return 2;
}

@Override
public int getItemViewType(int position) {
return position < getPager().getObjects().size() ? TYPE_ITEM : TYPE_NEXT;
}

@Override
public void registerDataSetObserver(DataSetObserver observer) {
super.registerDataSetObserver(observer);
// We use this method as a notification that the ListView is bound to the adapter.
loadNextPage();
}

public static class ViewHolder {
private View itemView;

public ViewHolder(View itemView) {
this.itemView = itemView;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

findViewById(R.id.sample_recycler).setOnClickListener(this);
findViewById(R.id.sample_list).setOnClickListener(this);
}

Expand All @@ -21,6 +22,11 @@ protected void onCreate(Bundle savedInstanceState) {
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.sample_recycler: {
Intent intent = new Intent(this, RecyclerActivity.class);
startActivity(intent);
break;
}
case R.id.sample_list: {
Intent intent = new Intent(this, ListActivity.class);
startActivity(intent);
Expand Down
Loading