-
-
Save ameron32/34329dbd5856bf5ea7c3 to your computer and use it in GitHub Desktop.
package YOUR.PACKAGE.HERE; | |
/* | |
* The MIT License (MIT) | |
* | |
* Copyright (c) <2015> <ameron32> | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
* THE SOFTWARE. | |
*/ | |
import android.support.v7.widget.RecyclerView; | |
import com.parse.FindCallback; | |
import com.parse.ParseException; | |
import com.parse.ParseObject; | |
import com.parse.ParseQuery; | |
import com.parse.ParseQueryAdapter.QueryFactory; | |
import java.util.ArrayList; | |
import java.util.List; | |
/** | |
* NEARLY IDENTICAL REPLACEMENT FOR ParseQueryAdapter ON ListView. | |
* REQUIRES THAT YOU SUBCLASS TO CREATE ViewHolder, onBindViewHolder(), and onCreateViewHolder | |
* AS ENFORCED BY THE RECYCLERVIEW PATTERN. | |
* | |
* TESTED SUCCESSFULLY with RecyclerView v7:21.0.3 | |
* AND with SuperRecyclerView by Malinskiy | |
* @ https://github.com/Malinskiy/SuperRecyclerView | |
* SHOULD WORK WITH UltimateRecyclerView | |
*/ | |
public abstract class ParseRecyclerQueryAdapter<T extends ParseObject, U extends RecyclerView.ViewHolder> | |
extends RecyclerView.Adapter<U> | |
{ | |
private final QueryFactory<T> mFactory; | |
private final boolean hasStableIds; | |
private final List<T> mItems; | |
// PRIMARY CONSTRUCTOR | |
public ParseRecyclerQueryAdapter(final QueryFactory<T> factory, final boolean hasStableIds) { | |
mFactory = factory; | |
mItems = new ArrayList<T>(); | |
mDataSetListeners = new ArrayList<OnDataSetChangedListener>(); | |
mQueryListeners = new ArrayList<OnQueryLoadListener<T>>(); | |
this.hasStableIds = hasStableIds; | |
setHasStableIds(hasStableIds); | |
loadObjects(); | |
} | |
// ALTERNATE CONSTRUCTOR | |
public ParseRecyclerQueryAdapter(final String className, final boolean hasStableIds) { | |
this(new QueryFactory<T>() { | |
@Override public ParseQuery<T> create() { | |
return ParseQuery.getQuery(className); | |
} | |
}, hasStableIds); | |
} | |
// ALTERNATE CONSTRUCTOR | |
public ParseRecyclerQueryAdapter(final Class<T> clazz, final boolean hasStableIds) { | |
this(new QueryFactory<T>() { | |
@Override public ParseQuery<T> create() { | |
return ParseQuery.getQuery(clazz); | |
} | |
}, hasStableIds); | |
} | |
/* | |
* REQUIRED RECYCLERVIEW METHOD OVERRIDES | |
*/ | |
@Override | |
public long getItemId(int position) { | |
if (hasStableIds) { | |
return position; | |
} | |
return super.getItemId(position); | |
} | |
@Override public int getItemCount() { | |
return mItems.size(); | |
} | |
public T getItem(int position) { return mItems.get(position); } | |
public List<T> getItems() { return mItems; } | |
/** | |
* Apply alterations to query prior to running findInBackground. | |
*/ | |
protected void onFilterQuery(ParseQuery<T> query) { | |
// provide override for filtering query | |
} | |
public void loadObjects() { | |
dispatchOnLoading(); | |
final ParseQuery<T> query = mFactory.create(); | |
onFilterQuery(query); | |
query.findInBackground(new FindCallback<T>() {; | |
@Override public void done( | |
List<T> queriedItems, | |
@Nullable ParseException e) { | |
if (e == null) { | |
mItems.clear(); | |
mItems.addAll(queriedItems); | |
dispatchOnLoaded(queriedItems, e); | |
notifyDataSetChanged(); | |
fireOnDataSetChanged(); | |
} | |
} | |
}); | |
} | |
public interface OnDataSetChangedListener { | |
public void onDataSetChanged(); | |
} | |
private final List<OnDataSetChangedListener> mDataSetListeners; | |
public void addOnDataSetChangedListener(OnDataSetChangedListener listener) { | |
mDataSetListeners.add(listener); | |
} | |
public void removeOnDataSetChangedListener(OnDataSetChangedListener listener) { | |
if (mDataSetListeners.contains(listener)) { | |
mDataSetListeners.remove(listener); | |
} | |
} | |
protected void fireOnDataSetChanged() { | |
for (int i = 0; i < mDataSetListeners.size(); i++) { | |
mDataSetListeners.get(i).onDataSetChanged(); | |
} | |
} | |
public interface OnQueryLoadListener<T> { | |
public void onLoaded( | |
List<T> objects, Exception e); | |
public void onLoading(); | |
} | |
private final List<OnQueryLoadListener<T>> mQueryListeners; | |
public void addOnQueryLoadListener( | |
OnQueryLoadListener<T> listener) { | |
if (!(mQueryListeners.contains(listener))) { | |
mQueryListeners.add(listener); | |
} | |
} | |
public void removeOnQueryLoadListener( | |
OnQueryLoadListener<T> listener) { | |
if (mQueryListeners.contains(listener)) { | |
mQueryListeners.remove(listener); | |
} | |
} | |
private void dispatchOnLoading() { | |
for (OnQueryLoadListener<T> l : mQueryListeners) { | |
l.onLoading(); | |
} | |
} | |
private void dispatchOnLoaded(List<T> objects, ParseException e) { | |
for (OnQueryLoadListener<T> l : mQueryListeners) { | |
l.onLoaded(objects, e); | |
} | |
} | |
} |
Hi there!! Thank you very much for this awesome gist!! It works perfectly for basic functionality!! Are you willing to continue the development of this adapter implementing other methods of parsequeryadapter like loadNextPage, loadObjects etc.?? Having spoken with parse they told me that they are going to create a parsequeryadapter for recyclerview but they don't know when.
Again thank you very much for your time!! Really helped what you have done!!
Ralphilius, you are welcome!
Answer (best I got):
hasStableIds: from what I understand stableIds allows the RecyclerView to do some internal recordkeeping that saves effort and processing, thereby improving performance. This is a RecyclerView setting that I never modified, so research into RecyclerView + hasStableIds should get you a better answer. However, stableIds affects some capabilities. I have always used "stableIds = true" and it seems to act normally.
msrowley, you are welcome!
Answer:
I looked into what it would take to loadNextPage, and essentially pagination in general, and I was a little frustrated at the setPage and setLimit restictions built into the Parse SDK. There was some movement on the SDK somewhat recently, I remember seeing. I wondered how they would improve or change the pagination procedures. Long story short, I looked into it, I didn't like the limitations of the most obvious way of handling it, and I decided to hold back on it for now.
How and where can I use loadObjects() ?
This is awesome, thank you.
I got a question, what does hasStableIds mean?