-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Firestore paging adapter #1178
Firestore paging adapter #1178
Changes from 30 commits
5109b4c
cbaaca7
8e08336
75240b7
4d68a56
6af779c
2a5f554
51c0d95
09f6a6d
a7153be
11668e2
db39ddf
efc0095
45901b7
4a684f3
754f945
1ea8834
eddcbed
276f677
ea8144c
75e206a
cef8528
154ecde
5391e97
c749cf4
877fb21
202857d
85967cb
e199385
bf0ac33
8bede03
a081a7f
fb64181
00a4818
1e02f0e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
package com.firebase.uidemo.database.firestore; | ||
|
||
import android.arch.paging.PagedList; | ||
import android.os.Bundle; | ||
import android.support.annotation.NonNull; | ||
import android.support.v7.app.AppCompatActivity; | ||
import android.support.v7.widget.LinearLayoutManager; | ||
import android.support.v7.widget.RecyclerView; | ||
import android.util.Log; | ||
import android.view.LayoutInflater; | ||
import android.view.Menu; | ||
import android.view.MenuItem; | ||
import android.view.View; | ||
import android.view.ViewGroup; | ||
import android.widget.ProgressBar; | ||
import android.widget.TextView; | ||
import android.widget.Toast; | ||
|
||
import com.firebase.ui.firestore.paging.FirestorePagingAdapter; | ||
import com.firebase.ui.firestore.paging.FirestorePagingOptions; | ||
import com.firebase.ui.firestore.paging.LoadingState; | ||
import com.firebase.uidemo.R; | ||
import com.google.android.gms.tasks.OnCompleteListener; | ||
import com.google.android.gms.tasks.Task; | ||
import com.google.firebase.firestore.CollectionReference; | ||
import com.google.firebase.firestore.FirebaseFirestore; | ||
import com.google.firebase.firestore.Query; | ||
import com.google.firebase.firestore.WriteBatch; | ||
|
||
import java.util.Locale; | ||
|
||
import butterknife.BindView; | ||
import butterknife.ButterKnife; | ||
|
||
public class FirestorePagingActivity extends AppCompatActivity { | ||
|
||
private static final String TAG = "FirestorePagingActivity"; | ||
|
||
@BindView(R.id.paging_recycler) | ||
RecyclerView mRecycler; | ||
|
||
@BindView(R.id.paging_loading) | ||
ProgressBar mProgressBar; | ||
|
||
private FirebaseFirestore mFirestore; | ||
private CollectionReference mItemsCollection; | ||
|
||
@Override | ||
protected void onCreate(Bundle savedInstanceState) { | ||
super.onCreate(savedInstanceState); | ||
setContentView(R.layout.activity_firestore_paging); | ||
ButterKnife.bind(this); | ||
|
||
mFirestore = FirebaseFirestore.getInstance(); | ||
mItemsCollection = mFirestore.collection("items"); | ||
|
||
setUpAdapter(); | ||
} | ||
|
||
private void setUpAdapter() { | ||
Query baseQuery = mItemsCollection.orderBy("value", Query.Direction.ASCENDING); | ||
|
||
PagedList.Config config = new PagedList.Config.Builder() | ||
.setEnablePlaceholders(false) | ||
.setPrefetchDistance(10) | ||
.setPageSize(20) | ||
.build(); | ||
|
||
FirestorePagingOptions<Item> options = new FirestorePagingOptions.Builder<Item>() | ||
.setLifecycleOwner(this) | ||
.setQuery(baseQuery, config, Item.class) | ||
.build(); | ||
|
||
FirestorePagingAdapter<Item, ItemViewHolder> adapter = | ||
new FirestorePagingAdapter<Item, ItemViewHolder>(options) { | ||
@NonNull | ||
@Override | ||
public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, | ||
int viewType) { | ||
View view = LayoutInflater.from(parent.getContext()) | ||
.inflate(R.layout.item_item, parent, false); | ||
return new ItemViewHolder(view); | ||
} | ||
|
||
@Override | ||
protected void onBindViewHolder(@NonNull ItemViewHolder holder, | ||
int position, | ||
Item model) { | ||
holder.bind(model); | ||
} | ||
|
||
@Override | ||
protected void onLoadingStateChanged(@NonNull LoadingState state) { | ||
switch (state) { | ||
case LOADING_INITIAL: | ||
case LOADING_MORE: | ||
mProgressBar.setVisibility(View.VISIBLE); | ||
break; | ||
case LOADED: | ||
mProgressBar.setVisibility(View.GONE); | ||
break; | ||
case ERROR: | ||
showToast("An error occurred."); | ||
retry(); | ||
break; | ||
} | ||
} | ||
}; | ||
|
||
mRecycler.setLayoutManager(new LinearLayoutManager(this)); | ||
mRecycler.setAdapter(adapter); | ||
} | ||
|
||
@Override | ||
public boolean onCreateOptionsMenu(Menu menu) { | ||
getMenuInflater().inflate(R.menu.menu_firestore_paging, menu); | ||
return true; | ||
} | ||
|
||
@Override | ||
public boolean onOptionsItemSelected(MenuItem item) { | ||
if (item.getItemId() == R.id.item_add_data) { | ||
showToast("Adding data..."); | ||
createItems().addOnCompleteListener(this, new OnCompleteListener<Void>() { | ||
@Override | ||
public void onComplete(@NonNull Task<Void> task) { | ||
if (task.isSuccessful()) { | ||
showToast("Data added."); | ||
} else { | ||
Log.w(TAG, "addData", task.getException()); | ||
showToast("Error adding data."); | ||
} | ||
} | ||
}); | ||
|
||
return true; | ||
} | ||
return super.onOptionsItemSelected(item); | ||
} | ||
|
||
private Task<Void> createItems() { | ||
WriteBatch writeBatch = mFirestore.batch(); | ||
|
||
for (int i = 0; i < 250; i++) { | ||
String title = "Item " + i; | ||
|
||
String id = String.format(Locale.getDefault(), "item_%03d", i); | ||
Item item = new Item(title, i); | ||
|
||
writeBatch.set(mItemsCollection.document(id), item); | ||
} | ||
|
||
return writeBatch.commit(); | ||
} | ||
|
||
private void showToast(String message) { | ||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); | ||
} | ||
|
||
public static class Item { | ||
|
||
public String text; | ||
public int value; | ||
|
||
public Item() {} | ||
|
||
public Item(String text, int value) { | ||
this.text = text; | ||
this.value = value; | ||
} | ||
|
||
} | ||
|
||
public static class ItemViewHolder extends RecyclerView.ViewHolder { | ||
|
||
@BindView(R.id.item_text) | ||
TextView mTextView; | ||
|
||
@BindView(R.id.item_value) | ||
TextView mValueView; | ||
|
||
ItemViewHolder(View itemView) { | ||
super(itemView); | ||
ButterKnife.bind(this, itemView); | ||
} | ||
|
||
void bind(Item item) { | ||
mTextView.setText(item.text); | ||
mValueView.setText(String.valueOf(item.value)); | ||
} | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<RelativeLayout | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Awwww, relative layout? 😞 I like me some constraints! 😂 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well technically, |
||
xmlns:android="http://schemas.android.com/apk/res/android" | ||
xmlns:tools="http://schemas.android.com/tools" | ||
android:layout_width="match_parent" | ||
android:layout_height="match_parent" | ||
tools:context="com.firebase.uidemo.database.firestore.FirestorePagingActivity"> | ||
|
||
<ProgressBar | ||
android:id="@+id/paging_loading" | ||
style="?android:attr/progressBarStyleHorizontal" | ||
android:layout_width="match_parent" | ||
android:layout_height="wrap_content" | ||
android:layout_marginTop="-6dp" | ||
android:background="@android:color/transparent" | ||
android:indeterminate="true" | ||
tools:ignore="NegativeMargin" /> | ||
|
||
<android.support.v7.widget.RecyclerView | ||
android:id="@+id/paging_recycler" | ||
android:layout_width="match_parent" | ||
android:layout_height="wrap_content" | ||
android:layout_below="@+id/paging_loading" | ||
android:paddingLeft="16dp" | ||
android:paddingRight="16dp" | ||
android:paddingTop="8dp" | ||
android:clipToPadding="false" | ||
tools:listitem="@layout/item_item" /> | ||
|
||
</RelativeLayout> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<LinearLayout | ||
xmlns:android="http://schemas.android.com/apk/res/android" | ||
xmlns:tools="http://schemas.android.com/tools" | ||
android:layout_width="match_parent" | ||
android:layout_height="wrap_content" | ||
android:layout_marginBottom="8dp" | ||
android:paddingLeft="16dp" | ||
android:paddingRight="16dp" | ||
android:paddingTop="8dp" | ||
android:paddingBottom="8dp" | ||
android:background="@drawable/ic_chat_message_background" | ||
android:orientation="vertical"> | ||
|
||
<TextView | ||
android:id="@+id/item_text" | ||
android:layout_width="wrap_content" | ||
android:layout_height="wrap_content" | ||
android:textIsSelectable="false" | ||
android:textSize="16sp" | ||
android:textStyle="bold" | ||
tools:text="My Text" /> | ||
|
||
<TextView | ||
android:id="@+id/item_value" | ||
android:layout_width="wrap_content" | ||
android:layout_height="wrap_content" | ||
android:textIsSelectable="false" | ||
android:textSize="12sp" | ||
tools:text="1234" /> | ||
|
||
</LinearLayout> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<menu | ||
xmlns:android="http://schemas.android.com/apk/res/android" | ||
xmlns:app="http://schemas.android.com/apk/res-auto"> | ||
|
||
<item | ||
android:id="@+id/item_add_data" | ||
android:title="@string/menu_add_data" | ||
app:showAsAction="never" /> | ||
|
||
</menu> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering what the best practices should be... I think we should store the collection as a field, but use the full
FirebaseFirestore.getInstance()
for other stuff like the batch. And make it final/inline the assignment? Yay, nay?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gonna do all of that besides the inline assignment (not a fan of that in classes where you don't have a constructor, like
Activity
orFragment
)