I am trying to implement a custom PagerAdapter implementing Firebase the same way that FirebaseListAdapter and FirebaseRecyclerAdapter do. I have looked at the source code on GitHub here but I am getting a couple errors in Android Studio. Here is my FirebasePagerAdapter utilizing a lot of classes from the given link:
public abstract class FirebasePagerAdapter<T> extends PagerAdapter implements FirebaseAdapter, ChangeEventListener {
private static String TAG = "firebasepageradapter";
protected final Activity mActivity;
protected final ObservableSnapshotArray<T> mSnapshots;
protected final int mLayout;
/**
* @param activity The {@link Activity} containing the {@link android.support.v4.view.ViewPager}
* @param modelLayout This is the layout used to represent a single list item. You will be
* responsible for populating an instance of the corresponding view with the
* data from an instance of modelClass.
* @param snapshots The data used to populate the adapter
*/
public FirebasePagerAdapter(Activity activity,
ObservableSnapshotArray<T> snapshots,
@LayoutRes int modelLayout) {
mActivity = activity;
mSnapshots = snapshots;
mLayout = modelLayout;
startListening();
}
/**
* @param parser a custom {@link SnapshotParser} to convert a {@link DataSnapshot} to the model
* class
* @param query The Firebase location to watch for data changes. Can also be a slice of a
* location, using some combination of {@code limit()}, {@code startAt()}, and
* {@code endAt()}. <b>Note, this can also be a {@link DatabaseReference}.</b>
* @see #FirebasePagerAdapter(Activity, ObservableSnapshotArray, int)
*/
public FirebasePagerAdapter(Activity activity,
SnapshotParser<T> parser,
@LayoutRes int modelLayout,
Query query) {
this(activity, new FirebaseArray<>(query, parser), modelLayout);
}
/**
* @see #FirebasePagerAdapter(Activity, SnapshotParser, int, Query)
*/
public FirebasePagerAdapter(Activity activity,
Class<T> modelClass,
@LayoutRes int modelLayout,
Query query) {
this(activity, new ClassSnapshotParser<>(modelClass), modelLayout, query);
}
@Override
public int getCount() {
return mSnapshots.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return false;
}
@Override
public void startListening() {
if (!mSnapshots.isListening(this)) {
mSnapshots.addChangeEventListener(this);
}
}
@Override
public void cleanup() {
mSnapshots.removeChangeEventListener(this);
}
@Override
public Object getItem(int position) {
return mSnapshots.get(position).getKey().hashCode();
}
@Override
public DatabaseReference getRef(int position) {
return mSnapshots.get(position).getRef();
}
@Override
public void onChildChanged(ChangeEventListener.EventType type, DataSnapshot snapshot, int index, int oldIndex) {
notifyDataSetChanged();
}
@Override
public void onDataChanged() {
}
@Override
public void onCancelled(DatabaseError error) {
Log.w(TAG, error.toException());
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = mActivity.getLayoutInflater().inflate(mLayout, container, false);
T model = getItem(position);
// Call out to subclass to marshall this model into the provided view
populateView(view, model, position);
return view;
}
/**
* Each time the data at the given Firebase location changes,
* this method will be called for each item that needs to be displayed.
* The first two arguments correspond to the mLayout and mModelClass given to the constructor of
* this class. The third argument is the item's position in the list.
* <p>
* Your implementation should populate the view using the data contained in the model.
*
* @param v The view to populate
* @param model The object containing the data used to populate the view
* @param position The position in the list of the view being populated
*/
protected abstract void populateView(View v, T model, int position);
}
Classes used from given link:
I have intensely searched Google and SO for an example or solution but despite the need for a FirebasePagerAdapter, no one has come up with a solution or at least made it public. I would like to get this working and make it public for other developers that may find it useful.
The errors I am getting are with T model = getItem(position);
in instantiateItem method "incompatible types: required T, found object"
and with this(activity, new FirebaseArray<>(query, parser), modelLayout);
"cannot infer arguments".
My hope is that by resolving those errors, the adapter would work as expected.
I have solved the issue by changing the getItem method to a GenericType public T getItem(int position)
. It works perfectly now. Here is my complete FirebasePagerAdapter class:
public abstract class FirebasePagerAdapter<T> extends PagerAdapter implements FirebaseAdapter, ChangeEventListener {
private static String TAG = "firebasepageradapter";
protected final Activity mActivity;
protected final ObservableSnapshotArray<T> mSnapshots;
protected final int mLayout;
/**
* @param activity The {@link Activity} containing the {@link android.support.v4.view.ViewPager}
* @param modelLayout This is the layout used to represent a single list item. You will be
* responsible for populating an instance of the corresponding view with the
* data from an instance of modelClass.
* @param snapshots The data used to populate the adapter
*/
public FirebasePagerAdapter(Activity activity,
ObservableSnapshotArray<T> snapshots,
@LayoutRes int modelLayout) {
mActivity = activity;
mSnapshots = snapshots;
mLayout = modelLayout;
startListening();
}
/**
* @param parser a custom {@link SnapshotParser} to convert a {@link DataSnapshot} to the model
* class
* @param query The Firebase location to watch for data changes. Can also be a slice of a
* location, using some combination of {@code limit()}, {@code startAt()}, and
* {@code endAt()}. <b>Note, this can also be a {@link DatabaseReference}.</b>
* @see #FirebasePagerAdapter(Activity, ObservableSnapshotArray, int)
*/
public FirebasePagerAdapter(Activity activity,
SnapshotParser<T> parser,
@LayoutRes int modelLayout,
Query query) {
this(activity, new FirebaseArray<>(query, parser), modelLayout);
}
/**
* @see #FirebasePagerAdapter(Activity, SnapshotParser, int, Query)
*/
public FirebasePagerAdapter(Activity activity,
Class<T> modelClass,
@LayoutRes int modelLayout,
Query query) {
this(activity, new ClassSnapshotParser<>(modelClass), modelLayout, query);
}
@Override
public int getCount() {
return mSnapshots.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public void startListening() {
if (!mSnapshots.isListening(this)) {
mSnapshots.addChangeEventListener(this);
}
}
@Override
public void cleanup() {
mSnapshots.removeChangeEventListener(this);
}
@Override
public T getItem(int position) {
return mSnapshots.getObject(position);
}
@Override
public DatabaseReference getRef(int position) {
return mSnapshots.get(position).getRef();
}
@Override
public void onChildChanged(ChangeEventListener.EventType type, DataSnapshot snapshot, int index, int oldIndex) {
notifyDataSetChanged();
}
@Override
public void onDataChanged() {
}
@Override
public void onCancelled(DatabaseError error) {
Log.w(TAG, error.toException());
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = mActivity.getLayoutInflater().inflate(mLayout, container, false);
//T model = getItem(position);
T model = getItem(position);
// Call out to subclass to marshall this model into the provided view
populateView(view, model, position);
container.addView(view);
return view;
}
/**
* Each time the data at the given Firebase location changes,
* this method will be called for each item that needs to be displayed.
* The first two arguments correspond to the mLayout and mModelClass given to the constructor of
* this class. The third argument is the item's position in the list.
* <p>
* Your implementation should populate the view using the data contained in the model.
*
* @param v The view to populate
* @param model The object containing the data used to populate the view
* @param position The position in the list of the view being populated
*/
protected abstract void populateView(View v, T model, int position);
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((RelativeLayout)object);
}
}
I have posted everything needed for this to work on GitHub for anyone else that may find it useful. You can find it here