I'm building a RecyclerView in a Fragment, which brings in data from Firebase database and suppose to show them on a CardView. I wrote all the code as shown below but all that appears upon running is an empty RecyclerView Fragment with the method getItemCount() returning always 0.
card_item.xml
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/cardView"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_margin="10dp"
android:orientation="horizontal"
card_view:cardCornerRadius="5dp"
card_view:cardElevation="5dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorPrimary">
<TextView
android:id="#+id/primaryText"
android:layout_width="300dp"
android:layout_height="60dp"
android:textColor="#color/colorPrimary"
android:textSize="24sp" />
<TextView
android:id="#+id/subText"
android:layout_width="300dp"
android:layout_height="60dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:textColor="#color/colorPrimary"
android:textSize="14sp" />
<TextView
android:id="#+id/rateValue"
android:layout_width="300dp"
android:layout_height="60dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="#+id/subText"
android:textColor="#color/colorPrimary"
android:textSize="24sp" />
</RelativeLayout>
fragment_profile.xml
<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="match_parent"
android:background="#F1F1F1"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/placesRecycler"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
PlacesModel.java
public class PlaceModel {
private String mPrimaryText, mSubText, mRateValue;
public PlaceModel() {
}
public PlaceModel(String mCardImage, String mPrimaryText,
String mSubText, String mRateValue) {
//this.mCardImageURL = mCardImage;
this.mPrimaryText = mPrimaryText;
this.mSubText = mSubText;
this.mRateValue = mRateValue;
}
public void setmPrimaryText(String mPrimaryText) {
this.mPrimaryText = mPrimaryText;
}
public void setmSubText(String mSubText) {
this.mSubText = mSubText;
}
public void setmRateValue(String mRateValue) {
this.mRateValue = mRateValue;
}
public String getmPrimaryText() {
return mPrimaryText;
}
public String getmSubText() {
return mSubText;
}
public String getmRateValue() {
return mRateValue;
}}
PlacesAdapter.java
public class PlacesAdapter extends RecyclerView.Adapter<PlacesAdapter.PlacesViewHolder> {
private ArrayList<PlaceModel> cardContents;
private Context context;
public PlacesAdapter(Context context, ArrayList<PlaceModel> cardContents) {
this.cardContents = cardContents;
this.context = context;
}
#Override
public PlacesViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.card_item, parent, false);
return new PlacesViewHolder(view);
}
#Override
public void onBindViewHolder(PlacesViewHolder holder, int position) {
PlaceModel place = cardContents.get(position);
holder.primaryText.setText(place.getmPrimaryText());
holder.subText.setText(place.getmSubText());
holder.rateValue.setText(place.getmRateValue());
}
#Override
public int getItemCount() {
return cardContents.size();
}
public class PlacesViewHolder extends RecyclerView.ViewHolder {
CardView cardView;
public TextView primaryText, subText, rateValue;
public PlacesViewHolder(View itemView) {
super(itemView);
cardView = (CardView) itemView.findViewById(R.id.cardView);
primaryText = (TextView) itemView.findViewById(R.id.primaryText);
subText = (TextView) itemView.findViewById(R.id.subText);
rateValue = (TextView) itemView.findViewById(R.id.rateValue);
}
}}
FirebaseConnector.java
public class FirebaseConnector {
DatabaseReference db;
PlaceModel placeModel = new PlaceModel();
ArrayList<PlaceModel> cardContent = new ArrayList<>();
public FirebaseConnector(DatabaseReference db) {
this.db = db;
}
public ArrayList<PlaceModel> retrieve() {
db.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return cardContent;
}
private void fetchData(DataSnapshot dataSnapshot) {
cardContent.clear(); //clear card content from last usage
for (DataSnapshot ds : dataSnapshot.getChildren()) {
placeModel = ds.child("Place Model").getValue(PlaceModel.class);
cardContent.add(placeModel);
}
}}
ProfileFragment.java
public class ProfileFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
/////////////////////////////////////////////////////////////
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
private RecyclerView placesRecycler;
private PlacesAdapter placesAdapter;
private FirebaseConnector connector;
private DatabaseReference ref;
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
public ProfileFragment() {
// Required empty public constructor
}
// TODO: Rename and change types and number of parameters
public static ProfileFragment newInstance(String param1, String param2) {
ProfileFragment fragment = new ProfileFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_profile, container, false);
mAuth = FirebaseAuth.getInstance();
//Initialize Database..
ref = FirebaseDatabase.getInstance().getReference();
connector = new FirebaseConnector(ref);
//Initialize RecyclerView
placesRecycler = (RecyclerView)v.findViewById(R.id.placesRecycler);
placesRecycler.setLayoutManager(new LinearLayoutManager(this.getActivity()));
//Adapter
placesAdapter = new PlacesAdapter(this.getActivity(), connector.retrieve());
placesRecycler.setAdapter(placesAdapter);
Toast.makeText(getActivity(), "We have "+placesAdapter.getItemCount()+" cards", Toast.LENGTH_LONG).show();
return v;
}
#Override
public void onStart() {
super.onStart();
if (mAuth.getCurrentUser() == null) {
startActivity(new Intent(getActivity(), LoginActivity.class));
}
}
public void updateUI() {
if (mAuth.getCurrentUser() == null) {
startActivity(new Intent(getActivity(), LoginActivity.class));
}
}}
Database trial structure
Database trial structure
I see that retrieve method will return empty array list because it won't wait for the listener to finish (note that listener works in another thread)
You may make move the listener to the profile fragment and every time you update the ArrayList write
placesRecycler.notifydatasetchanged();
Related
I'm trying to put my firestore data within a recyclerview in Android. The app comes up with no errors, however no data shows up.
public class Diseaselist extends AppCompatActivity {
private TextView textView;
private FirebaseFirestore mDatabaseRef;
private Query mChartsQuery;
private RecyclerView mRecycler;
private FirebaseAuth mAuth;
private FirestoreRecyclerAdapter<Upload, ProductViewHolder> adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_diseaselist);
RecyclerView recyclerView = findViewById(R.id.goodmeme);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
mAuth = FirebaseAuth.getInstance();
FirebaseUser currentUser = mAuth.getCurrentUser();
String useruid = currentUser.getUid();
Query query = rootRef.collection("users").document(useruid).collection("diagnoses")
.orderBy("disease", Query.Direction.ASCENDING);
FirestoreRecyclerOptions<Upload> options = new FirestoreRecyclerOptions.Builder<Upload>()
.setQuery(query, Upload.class)
.build();
adapter = new FirestoreRecyclerAdapter<Upload, ProductViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull ProductViewHolder holder, int position, #NonNull Upload productModel) {
holder.setProductName(productModel.getDisease());
}
#NonNull
#Override
public ProductViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
android.view.View views = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_diseaselist, parent, false);
return new ProductViewHolder(views);
}
};
recyclerView.setAdapter(adapter);
}
#Override
protected void onStart() {
super.onStart();
adapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
if (adapter != null) {
adapter.stopListening();
}
}
private class ProductViewHolder extends RecyclerView.ViewHolder {
private android.view.View view;
ProductViewHolder(android.view.View itemView) {
super(itemView);
view = itemView;
}
void setProductName(final String productName) {
CardView cview =view.findViewById(R.id.cardview);
textView = view.findViewById(R.id.texty);
textView.setText(productName);
cview.setOnClickListener(new android.view.View.OnClickListener() {
#Override
public void onClick(android.view.View view) {
Toast.makeText(getApplicationContext(), productName, Toast.LENGTH_SHORT).show();
}
});
}
}
Layout File:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".Diseaselist"
tools:orientation="vertical">
<TextView
android:id="#+id/texty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
android:text="30sp"/>
<android.support.v7.widget.CardView
android:id="#+id/cardview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
<ImageView
android:id="#+id/person_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginRight="16dp" />
<TextView
android:id="#+id/person_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toRightOf="#+id/person_photo"
android:textSize="30sp" />
<TextView
android:id="#+id/person_age"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/person_name"
android:layout_toRightOf="#+id/person_photo" />
</RelativeLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/goodmeme"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Firestore structure Firestore Structure Screenshot 2
Upload Class code:
package com.Provendor.Provendor;
import android.os.Parcel;
import android.os.Parcelable;
import java.io.Serializable;
import java.util.Calendar;
public class Upload implements Parcelable {
private String mName;
private String mImageUrl;
private String mdisease;
private String mdate;
private float mconfidence;
#Override
public int describeContents() {
return 0;
}
// write your object's data to the passed-in Parcel
#Override
public void writeToParcel(Parcel out, int flags) {
out.writeFloat(mconfidence);
out.writeString(mName);
out.writeString(mImageUrl);
out.writeString(mdisease);
out.writeString(mdate);
}
// this is used to regenerate your object. All Parcelables must have a CREATOR that implements these two methods
public static final Parcelable.Creator<Upload> CREATOR = new Parcelable.Creator<Upload>() {
public Upload createFromParcel(Parcel in) {
return new Upload(in);
}
public Upload[] newArray(int size) {
return new Upload[size];
}
};
// example constructor that takes a Parcel and gives you an object populated with it's values
private Upload(Parcel in) {
mconfidence = in.readInt();
mName = in.readString();
mImageUrl = in.readString();
mdisease = in.readString();
mdate = in.readString();
}
public Upload() {
mName= ""; //empty constructor needed
}
public Upload(String name, String imageUrl, String disease, float confidence) {
if (name.trim().equals("")) {
name = "No Name";
}
mdisease=disease;
mdate=java.text.DateFormat.getDateTimeInstance().format(Calendar.getInstance().getTime());
mName = name;
mImageUrl = imageUrl;
mconfidence=confidence;
}
public String getName() {
return mName;
}
public String getDisease() {
return mdisease;
}
public float getConfidence() {
return mconfidence;
}
public String getDate() {
return mdate;
}
public void setName(String name) {
mName = name;
}
public void setdate() {
mdate=java.text.DateFormat.getDateTimeInstance().format(Calendar.getInstance().getTime());
}
public void setDisease(String disease) {
mdisease = disease;
}
public void setConfidence(float confidence) {
mconfidence = confidence;
}
public String getImageUrl() {
return mImageUrl;
}
public void setImageUrl(String imageUrl) {
mImageUrl = imageUrl;
}
}
I expect the output to produce a list of diseases based on the firestore collection, however the recyclerview is left empty. When attached to debug, no errors come up! Thanks for looking this over!
You aren't getting anything from the database because the name of your fields inside the Upload class are different than the name of the fields that exist in the database. Both should match. To solve this, you either change all the name of your fields inside your Upload class to match the properties that exist in the database or your can use annotations. Because I see that you are using private fields and public getters, you should use the PropertyName annotation only in front of the getter, for instance your getName() getter should look like this:
#PropertyName("name")
public String getName() {
return mName;
}
I'm new to the concepts of RecyclerView and Firebase; I'm working on this chat app that takes input from the user (message) and takes the DisplayName(Google sign in, so the Username) and stores it to the realtime database of the Firebase. The storing of the "mAuthor" and "mMessage" is working fine, the problem arises when I'm trying to retrieve the data and display it in the recyclerView. There's no crash error as per the Logcat, however, there's nothing getting displayed on my chat app screen (in the recyclerView).
The dependencies of firebase and recyclerView have been carefully added.
Here's my activity class:
private String mDisplayName;
private EditText mMessage;
private ImageView mSendButton;
private RecyclerView mRecycler;
private DatabaseReference mDatabaseReference;
private MyAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
mMessage=(EditText) findViewById(R.id.messageInput);
mSendButton=(ImageView) findViewById(R.id.sendButton);
setupDisplayName();
mDatabaseReference= FirebaseDatabase.getInstance().getReference();
mRecycler=(RecyclerView) findViewById(R.id.chat_recycler_view);
mRecycler.setHasFixedSize(true);
LinearLayoutManager layoutManager= new LinearLayoutManager(ChatActivity.this);
mRecycler.setLayoutManager(layoutManager);
mMessage.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
sendMessage();
return true;
}
});
mSendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
sendMessage();
}
});
}
private void setupDisplayName(){
Intent mIntent= getIntent();
String option= mIntent.getStringExtra("Options");
if(option.equals("normal")){
SharedPreferences prefs= getSharedPreferences(RegisterActivity.CHAT_PREFS,0);
mDisplayName=prefs.getString(RegisterActivity.DISPLAY_NAME_KEY,null);
Log.d("Google","Shared prefs: DisplayName:"+mDisplayName);
}
else if(option.equals("google")){
SharedPreferences prefs= getSharedPreferences(MainActivity.CHAT_PREFS,0);
mDisplayName=prefs.getString(MainActivity.DISPLAY_NAME_KEY,null);
Log.d("Google","Shared prefs: DisplayName:"+mDisplayName);
}
if(mDisplayName==null)
mDisplayName="Anonymous";
}
private void sendMessage() {
String input= mMessage.getText().toString();
if(!input.equals("")){
Log.d("Google","I sent something");
InstantMessage mObject= new InstantMessage(mDisplayName, input);
mDatabaseReference.child("messages").push().setValue(mObject);
mMessage.setText("");
}
}
#Override
public void onStart() {
super.onStart();
mAdapter= new MyAdapter(mDatabaseReference, mDisplayName);
mRecycler.setAdapter(mAdapter);
}
#Override
public void onStop(){
super.onStop();
mAdapter.CleanUp();
}
Here's my Model class:
public class InstantMessage {
private String mAuthor;
private String mMessage;
public InstantMessage(String mAuthor, String mMessage) {
this.mAuthor = mAuthor;
this.mMessage = mMessage;
}
public InstantMessage() {
}
public String getmAuthor() {
return mAuthor;
}
public void setmAuthor(String mAuthor) {
this.mAuthor = mAuthor;
}
public void setmMessage(String mMessage) {
this.mMessage = mMessage;
}
public String getmMessage() {
return mMessage;
}
}
Here's my Adapter class:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private DatabaseReference mReference;
private String mDisplayName;
private List<InstantMessage> mList;
private ChildEventListener mListener= new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
InstantMessage msg= dataSnapshot.getValue(InstantMessage.class);
mList.add(msg);
Log.d("Google","Datasnapshot added:"+dataSnapshot.toString());
notifyDataSetChanged();
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
public MyAdapter( DatabaseReference mReference, String mDisplayName) {
this.mReference = mReference.child("messages");
mReference.addChildEventListener(mListener);
this.mDisplayName = mDisplayName;
mList= new ArrayList<>();
}
#NonNull
#Override
public MyAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_chat_row, parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MyAdapter.ViewHolder holder, int position) {
holder.mAuthorName.setText(mList.get(position).getmAuthor());
holder.mText.setText(mList.get(position).getmMessage());
}
#Override
public int getItemCount() {
Log.d("Google","Item count:"+mList.size());
return mList.size();
}
public void CleanUp(){
mReference.removeEventListener(mListener);
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView mAuthorName;
TextView mText;
public ViewHolder(View itemView) {
super(itemView);
mAuthorName=(TextView) itemView.findViewById(R.id.Chatauthor);
mText= (TextView) itemView.findViewById(R.id.Chatmessage);
}
}
}
I'm not sure what I'm doing wrong. In the log statement of onChildAdded method, the datasnapshot.toString() returns legit values. However, the Log.d("Google","Item Count:"+mList.size()) returns ItemCount: 1 everytime
PS: Here's the data that is being sent to the firebase: https://imageshack.com/a/img922/1458/HoOWxO.png
My activity_chat_row.xml code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/Chatauthor"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:layout_gravity="start"
android:textColor="#3CB371"
android:gravity="center_vertical"
android:textSize="15sp"
android:textStyle="bold"
android:text="Author"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/Chatmessage"
android:layout_gravity="start"
android:gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:padding="10dp"
android:textSize="15sp"
android:text="Text"
android:textColor="#android:color/primary_text_light"
/>
</LinearLayout>
I have been reading the different answers here on StackOverflow and tried to implement their solutions but I am still getting the error:
RecyclerView﹕ No adapter attached; skipping layout,
So I initialize my recycler view in onCreateView in my fragment like this :
public class StatusFragment extends Fragment {
DatabaseReference databaseStatus;
ProgressDialog progressDialog;
List<ElectricityClass> list = new ArrayList<ElectricityClass>();
RecyclerView recyclerView;
RecyclerView.Adapter adapter;
public StatusFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_status, container, false);
recyclerView = rootView.findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
progressDialog = new ProgressDialog(getActivity());
progressDialog.setMessage("Loading Data from Firebase Database");
progressDialog.show();
databaseStatus = FirebaseDatabase.getInstance().getReference().child("Electricity");
databaseStatus.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
ElectricityClass electricityClass = dataSnapshot.getValue(ElectricityClass.class);
list.add(electricityClass);
}
recyclerView.setLayoutManager(new LinearLayoutManager(getContext().getApplicationContext()));
adapter = new RecyclerViewAdapter(getContext().getApplicationContext(), list);
recyclerView.setAdapter(adapter);
progressDialog.dismiss();
}
#Override
public void onCancelled(DatabaseError databaseError) {
progressDialog.dismiss();
}
});
return rootView;
}
}
my RecyclerViewAdapter class :
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
Context context;
List<ElectricityClass> dataList;
public RecyclerViewAdapter(Context context, List<ElectricityClass> list) {
this.dataList = list;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_items, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
ElectricityClass studentDetails = dataList.get(position);
holder.StudentNameTextView.setText(studentDetails.getName());
holder.StudentNumberTextView.setText(studentDetails.getType());
}
#Override
public int getItemCount() {
return dataList.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
public TextView StudentNameTextView;
public TextView StudentNumberTextView;
public ViewHolder(View itemView) {
super(itemView);
StudentNameTextView = itemView.findViewById(R.id.ShowStudentNameTextView);
StudentNumberTextView = itemView.findViewById(R.id.ShowStudentNumberTextView);
}
}
}
My list Electricity Class :
class ElectricityClass {
private String id;
private String email;
private String name;
private String type;
private String detail;
private String location;
private String date;
private String imgurl;
public ElectricityClass() {
// Required empty public constructor
}
public ElectricityClass(String id, String currentUserString, String imageUrl, String nameString, String typeString, String detailString, String locationString, String dateString){
this.id = id;
this.email = currentUserString;
this.name =nameString;
this.type = typeString;
this.detail = detailString;
this.location = locationString;
this.date = dateString;
this.imgurl = imageUrl;
}
public String getImgurl() {
return imgurl;
}
public void setImgurl(String imgurl) {
this.imgurl = imgurl;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
}
and here is my The layout in the fragment:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/recyclerView"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
And the layout of an item:
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/cardview1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
card_view:cardElevation="5dp"
card_view:contentPadding="5dp"
card_view:cardCornerRadius="5dp"
card_view:cardMaxElevation="5dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ECEFF1"
android:padding="10dp">
<TextView
android:id="#+id/StudentName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Student Name: "
android:textColor="#000"
android:textSize="20dp" />
<TextView
android:id="#+id/ShowStudentNameTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Show Student Name"
android:textColor="#000"
android:textSize="20dp"
android:layout_alignParentTop="true"
android:layout_toRightOf="#+id/StudentName"
android:layout_toEndOf="#+id/StudentName"
android:layout_marginLeft="19dp"
android:layout_marginStart="19dp" />
<TextView
android:id="#+id/StudentNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Phone Number: "
android:textColor="#000"
android:textSize="20dp"
android:layout_below="#+id/StudentName"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<TextView
android:id="#+id/ShowStudentNumberTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Show Number"
android:textColor="#000"
android:textSize="20dp"
android:layout_marginLeft="11dp"
android:layout_marginStart="11dp"
android:layout_below="#+id/ShowStudentNameTextView"
android:layout_toRightOf="#+id/StudentNumber"
android:layout_toEndOf="#+id/StudentNumber" />
</RelativeLayout>
</android.support.v7.widget.CardView>
now it shows,
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView$Adapter.notifyDataSetChanged()' on a null object reference
here I define my List2
public class StatusFragment extends Fragment {
DatabaseReference databaseStatus;
ProgressDialog progressDialog;
List<ElectricityClass> list2 = new ArrayList<ElectricityClass>();
List<ElectricityClass> list = new ArrayList<ElectricityClass>();
RecyclerView recyclerView;
RecyclerView.Adapter adapter;
and inside onDataChanged(),
public void onDataChange(DataSnapshot snapshot) {
for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
ElectricityClass electricityClass = dataSnapshot.getValue(ElectricityClass.class);
list2.add(electricityClass);
}
refreshRv((ArrayList<ElectricityClass>) list2);
adapter = new RecyclerViewAdapter(getContext().getApplicationContext(), list);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
progressDialog.dismiss();
}
private void refreshRv(ArrayList<ElectricityClass> list2){
list.clear();
list.addAll(list2);
}
You are doing this wrong setting layout and adapter inside that onDataChange method. Rather create a private function that will instantiate your adapter, will set it to RecyclerView and will set layout manager too. (you may want to define the list from constructor of the adapter also like this list = new ArrayList<>(); )
When you are done with this function, call it in onCreateView method of the fragment, and inside onDataChange just call a refresh function(also private) that will clear your list(or not depending on your behaviour), add all new values and notify your adapter using adapter.notifyDataSetChanged() method.
Hope this will help you :)
EDIT: as someone mentioned in a comment, your error is just telling you that adapter is not set to RecyclerView, probably because onDataChanged() was not called. My explanation from above will solve the problem for sure
EDIT:
Define another list let's say list2, replace list.add(); with list2.add(); inside that for from onDataSetChanged();
Then after for, call this function
private void refreshRv(ArrayList<YourDataType> list2){
list.clear();
list.addAll(list2);
adapter.notifyDataSetChanged();
}
this works for me
#felicity just add this function properly
private void refreshRv(ArrayList<YourDataType> list2)
{
list.clear();
list.addAll(list2);
adapter.notifyDataSetChanged();
}
as lonut J.Bejan said
Recyclerview doesnt call any Adapter method :onBindViewHolder,onCreateViewHolder therefor the adapter is empty
here is my code :
public class PostsFragment extends Fragment {
public static final String TAG = "PostsFragment";
private static final String KEY_LAYOUT_POSITION = "layoutPosition";
private static final String KEY_TYPE = "type";
public static final int TYPE_HOME = 1001;
public static final int TYPE_FEED = 1002;
private int mRecyclerViewPosition = 0;
private OnPostSelectedListener mListener;
private RecyclerView mRecyclerView;
private RecyclerView.Adapter<PostViewHolder> mAdapter;
public PostsFragment() {
// Required empty public constructor
}
public static PostsFragment newInstance(int type) {
PostsFragment fragment = new PostsFragment();
Bundle args = new Bundle();
args.putInt(KEY_TYPE, type);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_posts, container, false);
rootView.setTag(TAG);
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.my_recycler_view);
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setReverseLayout(true);
linearLayoutManager.setStackFromEnd(true);
mRecyclerView.setLayoutManager(linearLayoutManager);
if (savedInstanceState != null) {
// Restore saved layout manager type.
mRecyclerViewPosition = (int) savedInstanceState
.getSerializable(KEY_LAYOUT_POSITION);
mRecyclerView.scrollToPosition(mRecyclerViewPosition);
// TODO: RecyclerView only restores position properly for some tabs.
}
switch (getArguments().getInt(KEY_TYPE)) {
case TYPE_HOME:
Log.d(TAG, "Restoring recycler view position (following): " + mRecyclerViewPosition);
FirebaseUtil.getCurrentUserRef().child("following").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(final DataSnapshot followedUserSnapshot, String s) {
String followedUserId = followedUserSnapshot.getKey();
String lastKey = "";
if (followedUserSnapshot.getValue() instanceof String) {
lastKey = followedUserSnapshot.getValue().toString();
}
Log.d(TAG, "followed user id: " + followedUserId);
Log.d(TAG, "last key: " + lastKey);
FirebaseUtil.getPeopleRef().child(followedUserId).child("posts")
.orderByKey().startAt(lastKey).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(final DataSnapshot postSnapshot, String s) {
HashMap<String, Object> addedPost = new HashMap<String, Object>();
addedPost.put(postSnapshot.getKey(), true);
FirebaseUtil.getFeedRef().child(FirebaseUtil.getCurrentUserId())
.updateChildren(addedPost).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
FirebaseUtil.getCurrentUserRef().child("following")
.child(followedUserSnapshot.getKey())
.setValue(postSnapshot.getKey());
}
});
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
FirebaseUtil.getFeedRef().child(FirebaseUtil.getCurrentUserId())
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
final List<String> postPaths = new ArrayList<>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Log.d(TAG, "adding post key: " + snapshot.getKey());
postPaths.add(snapshot.getKey());
}
mAdapter = new FirebasePostQueryAdapter(postPaths,
new FirebasePostQueryAdapter.OnSetupViewListener() {
#Override
public void onSetupView(PostViewHolder holder, Post post, int position, String postKey) {
setupPost(holder, post, position, postKey);
}
});
}
#Override
public void onCancelled(DatabaseError firebaseError) {
}
});
break;
default:
throw new RuntimeException("Illegal post fragment type specified.");
}
mRecyclerView.setAdapter(mAdapter);
}
private FirebaseRecyclerAdapter<Post, PostViewHolder> getFirebaseRecyclerAdapter(Query query) {
return new FirebaseRecyclerAdapter<Post, PostViewHolder>(
Post.class, R.layout.post_item, PostViewHolder.class, query) {
#Override
public void populateViewHolder(final PostViewHolder postViewHolder,
final Post post, final int position) {
setupPost(postViewHolder, post, position, null);
}
#Override
public void onViewRecycled(PostViewHolder holder) {
super.onViewRecycled(holder);
}
};
}
private void setupPost(final PostViewHolder postViewHolder, final Post post, final int position, final String inPostKey) {
postViewHolder.setPhoto(post.getThumb_url());
postViewHolder.setText(post.getText());
postViewHolder.setTimestamp(DateUtils.getRelativeTimeSpanString(
(long) post.getTimestamp()).toString());
final String postKey;
if (mAdapter instanceof FirebaseRecyclerAdapter) {
postKey = ((FirebaseRecyclerAdapter) mAdapter).getRef(position).getKey();
} else {
postKey = inPostKey;
}
Author author = post.getAuthor();
postViewHolder.setAuthor(author.getFull_name(), author.getUid());
postViewHolder.setIcon(author.getProfile_picture(), author.getUid());
ValueEventListener likeListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
postViewHolder.setNumLikes(dataSnapshot.getChildrenCount());
if (dataSnapshot.hasChild(FirebaseUtil.getCurrentUserId())) {
postViewHolder.setLikeStatus(PostViewHolder.LikeStatus.LIKED, getActivity());
} else {
postViewHolder.setLikeStatus(PostViewHolder.LikeStatus.NOT_LIKED, getActivity());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
FirebaseUtil.getLikesRef().child(postKey).addValueEventListener(likeListener);
postViewHolder.mLikeListener = likeListener;
postViewHolder.setPostClickListener(new PostViewHolder.PostClickListener() {
#Override
public void showComments() {
Log.d(TAG, "Comment position: " + position);
mListener.onPostComment(postKey);
}
#Override
public void toggleLike() {
Log.d(TAG, "Like position: " + position);
mListener.onPostLike(postKey);
}
});
}
#Override
public void onDestroy() {
super.onDestroy();
if (mAdapter != null && mAdapter instanceof FirebaseRecyclerAdapter) {
((FirebaseRecyclerAdapter) mAdapter).cleanup();
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save currently selected layout manager.
int recyclerViewScrollPosition = getRecyclerViewScrollPosition();
Log.d(TAG, "Recycler view scroll position: " + recyclerViewScrollPosition);
savedInstanceState.putSerializable(KEY_LAYOUT_POSITION, recyclerViewScrollPosition);
super.onSaveInstanceState(savedInstanceState);
}
private int getRecyclerViewScrollPosition() {
int scrollPosition = 0;
// TODO: Is null check necessary?
if (mRecyclerView != null && mRecyclerView.getLayoutManager() != null) {
scrollPosition = ((LinearLayoutManager) mRecyclerView.getLayoutManager())
.findFirstCompletelyVisibleItemPosition();
}
return scrollPosition;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p/>
*/
public interface OnPostSelectedListener {
void onPostComment(String postKey);
void onPostLike(String postKey);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnPostSelectedListener) {
mListener = (OnPostSelectedListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnPostSelectedListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
}
the adapter class
public class FirebasePostQueryAdapter extends RecyclerView.Adapter<PostViewHolder> {
private final String TAG = "PostQueryAdapter";
private List<String> mPostPaths;
private OnSetupViewListener mOnSetupViewListener;
public FirebasePostQueryAdapter(List<String> paths, OnSetupViewListener onSetupViewListener) {
if (paths == null || paths.isEmpty()) {
mPostPaths = new ArrayList<>();
} else {
mPostPaths = paths;
}
mOnSetupViewListener = onSetupViewListener;
}
#Override
public PostViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.post_item, parent, false);
return new PostViewHolder(v);
}
public void setPaths(List<String> postPaths) {
mPostPaths = postPaths;
notifyDataSetChanged();
}
public void addItem(String path) {
mPostPaths.add(path);
notifyItemInserted(mPostPaths.size());
}
#Override
public void onBindViewHolder(final PostViewHolder holder, int position) {
DatabaseReference ref = FirebaseUtil.getPostsRef().child(mPostPaths.get(position));
// TODO: Fix this so async event won't bind the wrong view post recycle.
ValueEventListener postListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Post post = dataSnapshot.getValue(Post.class);
Log.d(TAG, "post key: " + dataSnapshot.getKey());
mOnSetupViewListener.onSetupView(holder, post, holder.getAdapterPosition(),
dataSnapshot.getKey());
}
#Override
public void onCancelled(DatabaseError firebaseError) {
Log.e(TAG, "Error occurred: " + firebaseError.getMessage());
}
};
ref.addValueEventListener(postListener);
holder.mPostRef = ref;
holder.mPostListener = postListener;
}
#Override
public void onViewRecycled(PostViewHolder holder) {
super.onViewRecycled(holder);
holder.mPostRef.removeEventListener(holder.mPostListener);
}
#Override
public int getItemCount() {
return mPostPaths.size();
}
public interface OnSetupViewListener {
void onSetupView(PostViewHolder holder, Post post, int position, String postKey);
}
}
the main class
public class FeedsActivity extends AppCompatActivity implements PostsFragment.OnPostSelectedListener {
private static final String TAG = "FeedsActivity";
private FloatingActionButton mFab;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_feeds);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ViewPager viewPager = (ViewPager) findViewById(R.id.feeds_view_pager);
FeedsPagerAdapter adapter = new FeedsPagerAdapter(getSupportFragmentManager());
adapter.addFragment(PostsFragment.newInstance(PostsFragment.TYPE_HOME), "HOME");
adapter.addFragment(PostsFragment.newInstance(PostsFragment.TYPE_FEED), "FEED");
viewPager.setAdapter(adapter);
viewPager.setCurrentItem(1);
TabLayout tabLayout = (TabLayout) findViewById(R.id.feeds_tab_layout);
tabLayout.setupWithViewPager(viewPager);
mFab = (FloatingActionButton) findViewById(R.id.fab);
mFab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user == null || user.isAnonymous()) {
Toast.makeText(FeedsActivity.this, "You must sign-in to post.", Toast.LENGTH_SHORT).show();
return;
}
Intent newPostIntent = new Intent(FeedsActivity.this, NewPostActivity.class);
startActivity(newPostIntent);
}
});
}
#Override
public void onPostComment(String postKey) {
Intent intent = new Intent(this, CommentsActivity.class);
intent.putExtra(CommentsActivity.POST_KEY_EXTRA, postKey);
startActivity(intent);
}
#Override
public void onPostLike(final String postKey) {
final String userKey = FirebaseUtil.getCurrentUserId();
final DatabaseReference postLikesRef = FirebaseUtil.getLikesRef();
postLikesRef.child(postKey).child(userKey).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
// User already liked this post, so we toggle like off.
postLikesRef.child(postKey).child(userKey).removeValue();
} else {
postLikesRef.child(postKey).child(userKey).setValue(ServerValue.TIMESTAMP);
}
}
#Override
public void onCancelled(DatabaseError firebaseError) {
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_feeds, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
// TODO: Add settings screen.
return true;
} else if (id == R.id.action_profile) {
startActivity(new Intent(this, ProfileActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
class FeedsPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public FeedsPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
}
activity_feeds.xml
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
>
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways|snap"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<android.support.design.widget.TabLayout
android:id="#+id/feeds_tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/feeds_view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
/>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="#dimen/fab_margin"
android:src="#android:drawable/ic_input_add"
android:tint="#android:color/white"/>
post_item.xml
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_margin="8dp"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:padding="10dp">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/post_author_icon"
android:layout_width="#dimen/post_author_icon_size"
android:layout_height="#dimen/post_author_icon_size"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>
<TextView
android:id="#+id/post_author_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="#id/post_author_icon"
android:layout_marginLeft="4dp"
style="#style/Base.TextAppearance.AppCompat.Title"
android:textColor="#android:color/primary_text_light_nodisable"
android:text="Unknown"/>
<TextView
android:id="#+id/post_timestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_gravity="end"
android:textColor="#android:color/primary_text_light"
android:textSize="18sp" />
</RelativeLayout>
<ImageView
android:id="#+id/post_photo"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:scaleType="centerCrop" />
<TextView
android:id="#+id/post_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="false"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:textColor="#android:color/primary_text_light"
android:textSize="16sp"
android:ellipsize="end" />
<TextView
android:id="#+id/post_num_likes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:textColor="#android:color/secondary_text_light"
android:textSize="14sp" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="6dp">
<ImageView
android:id="#+id/post_like_icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="#drawable/heart_full"/>
<ImageView
android:id="#+id/post_comment_icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginLeft="6dp"
android:layout_toRightOf="#id/post_like_icon"
android:src="#drawable/ic_chat_24dp"
android:tint="#color/blue_grey_500"/>
</RelativeLayout>
</LinearLayout>
fragment_posts.xml
<FrameLayout 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=".PostsFragment">
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
You are setting the adapter on the recyclerview before the adapter has been initialised. Try:
mAdapter = new FirebasePostQueryAdapter(postPaths,
new FirebasePostQueryAdapter.OnSetupViewListener() {
#Override
public void onSetupView(PostViewHolder holder, Post post, int position, String postKey) {
setupPost(holder, post, position, postKey);
}
});
mRecyclerView.setAdapter(mAdapter);
What is the best way to use firebase with ViewPager.
Expected Output
How can I use ViewPager with Firebase such that it notifies the firebase for the position and gets and attaches the data accordingly?
Person.java
public class Person {
private String name;
private String email;
private String hobby;
public Person(){
}
public Person(String name , String email , String hobby){
this.name= name;
this.email = email;
this.hobby = hobby;
}
public void setName(String name) {
this.name = name;
}
public void setEmail(String email) {
this.email = email;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
public String getHobby() {
return hobby;
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
private ViewPager viewPager;
// private FirebaseAuth mAuth;
List<Person> person;
private Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
person = new ArrayList<>();
// mAuth = FirebaseAuth.getInstance();
context = this;
viewPager = (ViewPager) findViewById(R.id.pagerView);
viewPager.setAdapter(new MyPagerAdapter(getSupportFragmentManager(), person, context));
}
class MyPagerAdapter extends FragmentPagerAdapter {
String[] tabsArray;
private List<Person> personInAdapter = new ArrayList<>();
private Context context;
// int icons[] = {R.drawable.white_home, R.drawable.white_heart,
// R.drawable.white_star, R.drawable.white_heart, R.drawable.white_star};
public MyPagerAdapter(FragmentManager fm, List<Person> person, Context context) {
super(fm);
personInAdapter = person;
this.context = context;
tabsArray = getResources().getStringArray(R.array.TABS);
}
// #Override
// public CharSequence getPageTitle(int position) {
// return tabsArray[position];
// }
#Override
public Fragment getItem(int position) {
return MyFragment.getInstance(position );
}
#Override
public int getCount() {
return personInAdapter.size();
}
}
}
MyFragment.java
public class MyFragment extends Fragment {
private TextView upperText;
private TextView lowerText;
List<Person> personInAdapter = new ArrayList<>();
private Context context;
private DatabaseReference databaseReference;
public static MyFragment getInstance(int position) {
MyFragment myFragment = new MyFragment();
Bundle args = new Bundle();
args.putInt("position", position);
myFragment.setArguments(args);
return myFragment;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_my, container, false);
upperText = (TextView) view.findViewById(R.id.myFragmentUpperText);
lowerText = (TextView) view.findViewById(R.id.myFragmentLowerText);
databaseReference = FirebaseUtil.getBaseRef().child("Person");
int i = getArguments().getInt("position");
ValueEventListener postListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get Post object and use the values to update the UI
for (DataSnapshot personSnapshot: dataSnapshot.getChildren()) {
Person person = personSnapshot.getValue(Person.class);
upperText.setText(person.getName());
lowerText.setText(person.getEmail());
Log.i("Data In Person ", person.toString());
}
// [END_EXCLUDE]
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
// [START_EXCLUDE]
}
};
databaseReference.addValueEventListener(postListener);
// Bundle bundle = getArguments();
// if (bundle != null) {
// textView.setText("The value is" +i);
// }
return view;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
}
I have tried firebase with the FirebaseRecyclerView and implemented the same in a custom Recyclerview and it worked like charm
FirebaseRecyclerAdapter<Blog, BlogViewHolder> firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Blog, BlogViewHolder>(
Blog.class,
R.layout.blog_row,
BlogViewHolder.class,
mDatabaseReference
) {
#Override
protected void populateViewHolder(BlogViewHolder viewHolder, Blog model, int position) {
viewHolder.setDesc(model.getDesc());
viewHolder.setTitle(model.getTitle());
viewHolder.setImage(getApplicationContext(), model.getImageUrl());
mGoogleNow.progressiveStop();
mGoogleNow.setVisibility(View.GONE);
}
};
mBlogList.setAdapter(firebaseRecyclerAdapter);
}
public void LogoutFromFirebase(View view) {
mAuth.signOut();
}
public static class BlogViewHolder extends RecyclerView.ViewHolder {
NetworkImageView networkImageView;
ImageLoader imageLoader;
View mView;
public BlogViewHolder(View itemView) {
super(itemView);
mView = itemView;
}
public void setTitle(String title) {
TextView sTitle = (TextView) mView.findViewById(R.id.TitleTextView);
sTitle.setText(title);
}
public void setDesc(String desc) {
TextView sDesc = (TextView) mView.findViewById(R.id.descriptionTextView);
sDesc.setText(desc);
}
public void setImage(Context context, String image) {
networkImageView = (NetworkImageView) mView.findViewById(R.id.imageBlogPost);
imageLoader = CustomVolleyRequest.getInstance(context)
.getImageLoader();
imageLoader.get(image, ImageLoader.getImageListener(networkImageView,
R.drawable.crop_image_menu_crop, android.R.drawable
.ic_dialog_alert));
networkImageView.setImageUrl(image, imageLoader);
// Picasso.with(context).load(image).into(networkImageView);
}
}
Finally after toiling hard on SO and various other blogs I was able to use the data I get from the Firebase into something very similar to ViewPager : Horizontal RecyclerView with LinearSnapHelper. You need to override findTargetSnapPosition and then you are done.
Firstly Add RecyclerView to your Activity/Fragment
<android.support.v7.widget.RecyclerView
android:layout_below="#+id/sign_in_button"
android:layout_width="match_parent"
android:orientation="horizontal"
android:id="#+id/blog_list"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
In my case I have used a CardView inside the RecyclerView
blog_row.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_margin="15dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<com.android.volley.toolbox.NetworkImageView
android:id="#+id/imageBlogPost"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:paddingBottom="15dp"
android:src="#drawable/common_google_signin_btn_text_light_normal" />
<TextView
android:id="#+id/TitleTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:text="Post Title Here"
android:textSize="16sp" />
<TextView
android:id="#+id/descriptionTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Post Description Here"
android:paddingBottom="15dp"
android:textSize="14sp" />
</LinearLayout>
</android.support.v7.widget.CardView>
In your Activity/Fragment
private RecyclerView mBlogList;
LinearLayoutManager layoutManager
= new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
mBlogList = (RecyclerView) findViewById(R.id.blog_list);
mBlogList.setHasFixedSize(true);
mBlogList.setLayoutManager(layoutManager);
LinearSnapHelper snapHelper = new LinearSnapHelper() {
#Override
public int findTargetSnapPosition(RecyclerView.LayoutManager lm, int velocityX, int velocityY) {
View centerView = findSnapView(lm);
if (centerView == null)
return RecyclerView.NO_POSITION;
int position = lm.getPosition(centerView);
int targetPosition = -1;
if (lm.canScrollHorizontally()) {
if (velocityX < 0) {
targetPosition = position - 1;
} else {
targetPosition = position + 1;
}
}
if (lm.canScrollVertically()) {
if (velocityY < 0) {
targetPosition = position - 1;
} else {
targetPosition = position + 1;
}
}
final int firstItem = 0;
final int lastItem = lm.getItemCount() - 1;
targetPosition = Math.min(lastItem, Math.max(targetPosition, firstItem));
return targetPosition;
}
};
snapHelper.attachToRecyclerView(mBlogList);
Last Step is to set adapter to RecyclerView
mBlogList.setAdapter(firebaseRecyclerAdapter);
Using this we can get ViewPager Effect Like this.
Image Source