New to all this....I have created the following code:
Custom Class Object
public class Category {
private String documentID;
private int id;
private String description;
private boolean active;
private int sort;
public Category(){
//public no-arg constructor needed
}
public Category(int id, String description, boolean active, int sort) {
this.id = id;
this.description = description;
this.active = active;
this.sort = sort;
}
#Exclude
public String getDocumentID() {
return documentID;
}
public void setDocumentID(String documentID) {
this.documentID = documentID;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
public int getSort() {
return sort;
}
public void setSort(int sort) {
this.sort = sort;
}
#Override
public String toString() {
return description;
}
}
MainActivity Class
public class MainActivity extends AppCompatActivity {
// Local XML obect declarations...
private Spinner spinner_Category;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Load the CATEGORY spinner with the ACTIVE categories from the Firestore
spinner_Category = (Spinner)findViewById(R.id.spinner_category);
populateCategories();
spinner_Category.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
Category category = (Category) parent.getSelectedItem();
displayCategoryData(category);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
String message = "Nothing selected";
Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
}
});
}
private void populateCategories(){
// DBHelper dbHelper = DBHelper.getInstance(this);
DBHelper dbHelper = new DBHelper(this);
ArrayList<Category> categoryList = dbHelper.getAllCategories();
ArrayAdapter<Category> adapterCategories = new ArrayAdapter<Category>(this,
android.R.layout.simple_spinner_item, categoryList);
adapterCategories.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner_Category.setAdapter(adapterCategories);
}
private void displayCategoryData(Category category) {
String description = category.getDescription();
int sort = category.getSort();
boolean active = category.isActive();
String userData = "Description: " + description + "\nSort: " + sort + "\nActive: " + active;
Toast.makeText(this, userData, Toast.LENGTH_LONG).show();
}
}
Method from my DBHelper class (a general class object to read/write to the Firestore dBase)
/* Function: getAllCategories
* Return a collection of ACTIVE cattegories from the Firestore */
public ArrayList<Category> getAllCategories() {
final ArrayList<Category> categoryList = new ArrayList<>();
CollectionReference colref = db.collection(COLLECTION_CATEGORIES);
colref.whereEqualTo(CATEGORY_ACTIVE, true)
.get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
for (QueryDocumentSnapshot dcSnapshot: queryDocumentSnapshots) {
Category c = dcSnapshot.toObject(Category.class);
c.setDocumentID(dcSnapshot.getId());
categoryList.add(c);
}
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d(TAG, e.toString());
}
});
return categoryList;
}
And finally the activity_main XML
<RelativeLayout 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"
tools:context=".MainActivity">
<TextView
android:id="#+id/text_view_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginBottom="10sp"
android:text="App Title"
android:textColor="#color/cardview_dark_background"
android:textSize="18sp" />
<Spinner
android:id="#+id/spinner_category"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:padding="16dp" />
The issue is this code may populate the Spinner with Category objects but it doesn't display, initially select or trigger a OnItemSelected event. As this code is practically identical to other code I have used reading records from an SQLite database rather than a Firestore database then I am assuming it's the QueryDocumentSnapshot.toObject() method that alters the collection in some way.
Any advise will be greatly appreciated...
After populating the list,and adding the list to the adapter, run this command:
adapterCategories.notifyDataSetChanged();
Instead of using the default layout resource for the adapter, create a custom one and use it. So in your layout folder, create a layout such as this:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="#color/black"
android:textSize="15sp"
android:textStyle="bold"
/>
and name it spinner_textbox.xml. Then in your activity, instead of this:
ArrayAdapter<Category> adapterCategories = new ArrayAdapter<Category>(this,
android.R.layout.simple_spinner_item, categoryList);
adapterCategories.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
do this:
ArrayAdapter<Category> adapterCategories = new ArrayAdapter<Category>(this,
R.layout.spinner_textbox, categoryList);
adapterCategories.setDropDownViewResource(R.layout.spinner_textbox);
Remember to remove the 'android' so that it finds your custom layout from R.
Related
I have an app that retrieves data from Firebase specifically from Firestore, the thing is the recycler view that shows the data is empty, even though it's working in another fragment with the same logic, I don't know where i am wrong or mistaken! And as i said the fragment is totally empty, besides if i added a TextView or Button it shows normally but the recycler view doesn't show up.
ps: when i copied the same code i changed the layout name and the recycler name to point to the other layout and recycler view of the fragment;
Here is the Fragment
FavoriteFragment.java: the fragment that handles the code.
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_favorite, container, false);
recyclerView = view.findViewById(R.id.fav_recycler);
linearLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(linearLayoutManager);
mAuth = FirebaseAuth.getInstance();
FirebaseUser auth_user = mAuth.getCurrentUser();
db = FirebaseFirestore.getInstance();
//Fetch Users Info
Query query = db.collection("posts")
.orderBy("posttime", Query.Direction.DESCENDING); // order the query by date
FirestoreRecyclerOptions<Posts> response = new FirestoreRecyclerOptions.Builder<Posts>()
.setQuery(query, Posts.class)
.build();
adapter = new MainAdapter(response);
adapter.notifyDataSetChanged();
recyclerView.setAdapter(adapter);
return view;
}
fragment_favorite.xml: the layout of the fragment.
<?xml version="1.0" encoding="utf-8"?>
<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"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".FavoriteFragment">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout_editor_absoluteX="0dp"
tools:layout_editor_absoluteY="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="15dp">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/fav_recycler"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="15dp"/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</FrameLayout>
and
MainAdapter.java: The adapter of the Recycler view, also handles the code that makes an item (in this case a post) to be added or removed from the firestore
public class MainAdapter extends FirestoreRecyclerAdapter<Posts, MainAdapter.ViewHolder> {
/**
* Create a new RecyclerView adapter that listens to a Firestore Query. See {#link
* FirestoreRecyclerOptions} for configuration options.
*
* #param options
*/
public MainAdapter(#NonNull FirestoreRecyclerOptions options) {
super(options);
}
private FirebaseFirestore db;
private DocumentReference documentReference;
private FirebaseAuth mAuth;
boolean isthere = false;
boolean isExist = false;
#Override
protected void onBindViewHolder(#NonNull ViewHolder holder, int position, #NonNull Posts post) {
db = FirebaseFirestore.getInstance();
mAuth = FirebaseAuth.getInstance();
documentReference = db.collection("users").document(mAuth.getUid());
holder.txtTitle.setText(post.getName());
holder.txtDesc.setText(post.getTitle() + "\n" +post.getDesc() + "\n" + post.getBloodtype() + "\n" + post.getCity() + "\n" + post.getNumber()+ "\n" + post.getDeadline());
Glide.with(holder.image.getContext()).load(post.getImage())
.into(holder.image);
holder.root.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Snackbar.make(v, post.getUserid() + "\n" + post.getName() + "\n" +post.getBloodtype() + "\n" + post.getCity(), Snackbar.LENGTH_LONG)
.setAnchorView(R.id.navigation) // Set SnackBar above the BottomNavigationView
.show();
}
});
Posts newPost = new Posts(post.getUserid(), post.getName(), post.getTitle(),post.getDesc(), post.getDeadline(), post.getNumber(),
post.getCity(), post.getBloodtype(), post.getImage(), post.getPosttime(), post.getPostid());
holder.fav.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked) {
// Toast.makeText(buttonView.getContext(), "Added to favorite", Toast.LENGTH_SHORT).show();
if (isExist == false) {
db.collection("users").document(mAuth.getUid()).collection("favorites").document(post.getPostid())
.set(newPost)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
Toast.makeText(buttonView.getContext(), "Succeed \nBoolean: " + isExist, Toast.LENGTH_SHORT).show();
}
});
}
}
else {
// removefromfav(post.getPostid(), buttonView);
documentReference.collection("favorites").document(post.getPostid())
.delete()
.addOnSuccessListener(new OnSuccessListener<Void>() {
public void onSuccess(Void aVoid) {
// Toast.makeText(buttonView.getContext(), "Removed from favorite " + isExist, Toast.LENGTH_SHORT).show();
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
}
});
}
}
});
documentReference.collection("favorites").document(post.getPostid())
.get()
.addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if(task.isSuccessful()){
isExist = task.getResult().exists();
if (isExist == true) {
holder.fav.setChecked(true);
}
}
}
});
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.users_item, parent, false);
return new ViewHolder(view);
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public LinearLayout root;
public TextView txtTitle;
public TextView txtDesc;
public ImageView image;
public ToggleButton fav;
public ViewHolder(View itemView) {
super(itemView);
root = itemView.findViewById(R.id.list_root);
txtTitle = (TextView) itemView.findViewById(R.id.list_title);
txtDesc = (TextView) itemView.findViewById(R.id.list_desc);
image = (ImageView)itemView.findViewById(R.id.list_image);
fav = (ToggleButton)itemView.findViewById(R.id.favbutton);
}
}
}
EDIT:
I added the Posts class
Posts.java:
public class Posts {
private String userid;
private String name;
private String title;
private String desc;
private String deadline;
private String number;
private String city;
private String bloodtype;
private String image;
private String posttime;
private String postid;
public Posts(){
}
public Posts(String userid,String name, String title, String desc, String deadline,
String number, String city, String bloodtype, String image, String posttime, String postid){
this.userid = userid;
this.name = name;
this.title = title;
this.desc = desc;
this.deadline = deadline;
this.number = number;
this.city = city;
this.bloodtype = bloodtype;
this.image = image;
this.posttime = posttime;
this.postid = postid;
}
public String getUserid(){
return userid;
}
public String getName(){
return name;
}
public String getTitle(){
return title;
}
public String getDesc(){
return desc;
}
public String getDeadline(){
return deadline;
}
public String getNumber(){
return number;
}
public String getCity(){
return city;
}
public String getBloodtype(){
return bloodtype;
}
public String getImage(){
return image;
}
public String getPosttime(){
return posttime;
}
public String getPostid(){
return postid;
}
}
And a screenshot of posts in firestore bellow :
Well, i figure it out, i missed the onStart and onStop to start and stop listening for the adapter.
#Override
public void onStart() {
super.onStart();
adapter.startListening();
}
#Override
public void onStop() {
super.onStop();
adapter.stopListening();
}
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 am trying to archive this functionality for my grocery app https://imgur.com/Ugj4BIO
But I am failed to do so!
I am showing you what I am able to archive. if you have any Better Solution let me know.
Here is my Json code from which I am fetching my data from web server right now its localhost
{"cats":
[{"sub_cats":
[{
"sub_id":"1",
"sub_title":"Charger",
"sub_img":"http:\/\/localhost\/adminPohanch\/public\/img\/img23.jpg"
},
{
"sub_id":"2",
"sub_title":"Dummy",
"sub_img":"https:\/\/encrypted-tbn0.gstatic.com\/images?q=tbn:ANd9GcTrRRV2S-HAzHVIfS0EtgfIeWnej05TRN1PqWQCLW44h3NqM9UOtQ"
}
],
"id":"52",
"title":"Electric Equipments",
"img":""}],
"message":"Categories Loaded","success":1}
Here is the retofit's API abstract class's method
#GET("cats.php")
Call<Categories> getCategories();
My Categories Model Class is this
public class Categories {
#SerializedName("id")
#Expose
private String id;
#SerializedName("title")
#Expose
private String title;
#SerializedName("img")
#Expose
private String img;
#SerializedName("sub_id")
#Expose
private String sub_id;
#SerializedName("sub_title")
#Expose
private String sub_title;
#SerializedName("sub_img")
#Expose
private String sub_img;
#SerializedName("cats")
#Expose
private List<Categories> cats = null;
#SerializedName("sub_cats")
#Expose
private List<Categories> sub_cats = null;
#SerializedName("message")
#Expose
private String message;
#SerializedName("success")
#Expose
private Integer success;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getImg() {
return img;
}
public void setImg(String img) {
this.img = img;
}
public String getSub_id() {
return sub_id;
}
public void setSub_id(String sub_id) {
this.sub_id = sub_id;
}
public String getSub_title() {
return sub_title;
}
public void setSub_title(String sub_title) {
this.sub_title = sub_title;
}
public String getSub_img() {
return sub_img;
}
public void setSub_img(String sub_img) {
this.sub_img = sub_img;
}
public List<Categories> getCats() {
return cats;
}
public void setCats(List<Categories> cats) {
this.cats = cats;
}
public List<Categories> getSub_cats() {
return sub_cats;
}
public void setSub_cats(List<Categories> sub_cats) {
this.sub_cats = sub_cats;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Integer getSuccess() {
return success;
}
public void setSuccess(Integer success) {
this.success = success;
}
}
Here is the code for my Activity
from which I am getting result/data and initializing to my Adapter
Call<Categories> callCats = RetrofitBuilder.getInstance().getApi().getCategories();
callCats.enqueue(new Callback<Categories>() {
#Override
public void onResponse(Call<Categories> call, Response<Categories> response) {
Categories cats = response.body();
Log.d("cats", "onResponse: " + cats);
if (cats != null){
List<Categories> catsList = cats.getCats();
Log.d("Categories", "onResponse: " + catsList.size());
Log.d("Categories", "onResponse: " + cats.getCats().toString());
for(int i = 0; i < catsList.size(); i++){
Categories categoriesData = new Categories();
String id = catsList.get(i).getId();
String title = catsList.get(i).getTitle();
String img = catsList.get(i).getImg();
categoriesData.setId(id);
categoriesData.setTitle(title);
categoriesData.setImg(img);
getCatItems.add(categoriesData);
List<Categories> sub = catsList.get(i).getSub_cats();
Toast.makeText(BuyerDashboard.this, ""+sub.size(), Toast.LENGTH_SHORT).show();
for (int j = 0; j < sub.size(); j++){
Categories categories = new Categories();
categories.setId(sub.get(i).getSub_id());
categories.setSub_title(sub.get(i).getSub_title());
categories.setSub_img(sub.get(i).getSub_img());
getSubItems.add(categories);
}
}
ExpandableRecyclerViewAdapter expandableCategoryRecyclerViewAdapter =
new ExpandableRecyclerViewAdapter(getApplicationContext(), getCatItems, getSubItems);
expanderRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
expanderRecyclerView.setAdapter(expandableCategoryRecyclerViewAdapter);
}
}
#Override
public void onFailure(Call<Categories> call, Throwable t) {
Toast.makeText(BuyerDashboard.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
**ExpandableRecyclerViewAdapter **
public class ExpandableRecyclerViewAdapter extends RecyclerView.Adapter<ExpandableRecyclerViewAdapter.ViewHolder> {
List<Categories> nameList ;
List<Integer> counter = new ArrayList<Integer>();
List<Categories> itemNameList;
Context context;
public ExpandableRecyclerViewAdapter(Context context,
List<Categories> nameList,
List<Categories> itemNameList ) {
this.nameList = nameList;
this.itemNameList = itemNameList;
this.context = context;
Log.d("namelist", nameList.toString());
for (int i = 0; i < nameList.size(); i++) {
counter.add(0);
}
}
#NonNull
#Override
public ExpandableRecyclerViewAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.cat_items, viewGroup, false);
ExpandableRecyclerViewAdapter.ViewHolder vh = new ExpandableRecyclerViewAdapter.ViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(#NonNull final ExpandableRecyclerViewAdapter.ViewHolder holder, final int position) {
Categories categories = nameList.get(position);
holder.name.setText(categories.getTitle());
InnerRecyclerViewAdapter itemInnerRecyclerView = new InnerRecyclerViewAdapter(itemNameList, context);
holder.cardRecyclerView.setLayoutManager(new GridLayoutManager(context, 2));
holder.cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (counter.get(position) % 2 == 0) {
holder.cardRecyclerView.setVisibility(View.VISIBLE);
} else {
holder.cardRecyclerView.setVisibility(View.GONE);
}
counter.set(position, counter.get(position) + 1);
}
});
holder.cardRecyclerView.setAdapter(itemInnerRecyclerView);
}
#Override
public int getItemCount() {
return nameList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView name;
ImageButton dropBtn;
RecyclerView cardRecyclerView;
CardView cardView;
public ViewHolder(final View itemView) {
super(itemView);
name = itemView.findViewById(R.id.categoryTitle);
dropBtn = itemView.findViewById(R.id.categoryExpandBtn);
cardRecyclerView = itemView.findViewById(R.id.innerRecyclerView);
cardView = itemView.findViewById(R.id.cardView);
}
}
}
InnerRecyclerViewAdapter For Childs/(sub-categories)
public class InnerRecyclerViewAdapter extends RecyclerView.Adapter<InnerRecyclerViewAdapter.ViewHolder> {
public List<Categories> nameList;
Context context;
public InnerRecyclerViewAdapter(List<Categories> nameList, Context context) {
this.nameList = nameList;
this.context = context;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int i) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.sub_cat_items, parent, false);
InnerRecyclerViewAdapter.ViewHolder vh = new InnerRecyclerViewAdapter.ViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, final int position) {
Categories subCategories = nameList.get(position);
holder.name.setText(subCategories.getTitle());
holder.name.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(context, ProductsActivity.class);
Categories subCategories = nameList.get(position);
i.putExtra("sub_cat_id", subCategories.getId());
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
});
}
#Override
public int getItemCount() {
return nameList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView name;
public ViewHolder(View itemView) {
super(itemView);
name = itemView.findViewById(R.id.itemTextView);
}
}
}
Right now I am not displaying anything for Images I am focusing on Title of categories(parents) and sub-categories (child)
Here is my sub_cat_items file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.CardView
android:id="#+id/cardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<LinearLayout
android:id="#+id/linearLayoutHolder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">
<ImageView
android:id="#+id/sub_cat_img"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:background="#drawable/pohanch" />
<TextView
android:id="#+id/itemTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="5dp"
android:text="Fresh Fruits"
android:textAlignment="center"
android:textSize="14sp" />
</LinearLayout>
</android.support.v7.widget.CardView>
</RelativeLayout>
And the last here is my cat_items File
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
<android.support.v7.widget.CardView
android:id="#+id/cardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="3dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/linearLayoutHolder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="20dp">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:orientation="vertical">
<TextView
android:id="#+id/categoryTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Fruits & Vegetables"
android:textColor="#color/basiccolor"
android:textSize="16sp" />
<ImageButton
android:id="#+id/categoryExpandBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:background="#FFF"
android:src="#drawable/ic_arrow_downward_black_24dp" />
</RelativeLayout>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/innerRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/linearLayoutHolder"
android:background="#f6f6f6"
android:visibility="gone">
</android.support.v7.widget.RecyclerView>
</RelativeLayout>
</android.support.v7.widget.CardView>
</RelativeLayout>
I am successful in displaying Categories (parents) to the output but having issues with subcategories(children)
Here is my output
https://imgur.com/Feq6XBP
Checkout this example code for customized expandableview.
https://github.com/developernadeem/ShopGrocery
RecyclerView is for list not for ExpandableListView maybe you want to check this tutorial: https://www.androidhive.info/2013/07/android-expandable-list-view-tutorial/
Or maybe want to check this library: https://github.com/thoughtbot/expandable-recycler-view
Of course you can use RecyclerView but you have to change the layout doing your own calculations, and making the listener to make the expandable and not expandable
Retrofit returns object
Configure classes this way
public class Category{
List<Cats> cats;
private String message;
private int success;
}
Public class Cats{
List<SubCats> sub_cats;
private String id;
private String title;
private String img;
}
public class SubCats{
private String sub_id;
private String sub_title;
private String sub_img;
}
Now
#GET("cats.php")
Call<Category> getCategories();
Yo need to configure JSON as well, Remove red marked in the image. It seems unnecessary.
Reconfigure the PHP as well
I have used of MVVM and ROOM and databindig in my app.According
Guide to app architecture ,I want to cash data using room.In the xml layout of RecyclerView item, I use CategoryViewModel variable.I get list of categories from Room database withLiveData type. I want to change LiveData<list<CategoryItem>> type to MutableLiveData<ArrayList<CategoryViewModel>> type. Because finally my adapter consume ArrayList<CategoryViewModel> data type.How to get value of LiveData? When I call getValue() method, returns null.
this is CategoryItem model:
#Entity(tableName = "category_table")
public class CategoryItem implements Serializable {
#PrimaryKey
private int id;
private String title;
private String imagePath;
#TypeConverters({SubCategoryConverter.class})
private ArrayList<String> subCategory;
#TypeConverters({DateConverter.class})
private Date lastRefresh;
public CategoryItem(int id, String title, String imagePath, ArrayList<String> subCategory, Date lastRefresh) {
this.id = id;
this.title = title;
this.imagePath = imagePath;
this.subCategory = subCategory;
this.lastRefresh=lastRefresh;
}
public CategoryItem(int id, String title, String imagePath) {
this.id = id;
this.title = title;
this.imagePath = imagePath;
}
public CategoryItem() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getImagePath() {
return imagePath;
}
public void setImagePath(String imagePath) {
this.imagePath = imagePath;
}
public ArrayList<String> getSubCategory() {
return subCategory;
}
public void setSubCategory(ArrayList<String> subCategory) {
this.subCategory = subCategory;
}
public Date getLastRefresh() {
return lastRefresh;
}
public void setLastRefresh(Date lastRefresh) {
this.lastRefresh = lastRefresh;
}
}
this is CategoryViewModel class:
public class CategoryViewModel extends AndroidViewModel {
private String title;
private String imagePath;
private MutableLiveData<ArrayList<CategoryViewModel>> allCategories=new MutableLiveData<>();
private CategoryRepository repository;
public CategoryViewModel(#NonNull Application application) {
super(application);
repository=new CategoryRepository(application, Executors.newSingleThreadExecutor());
}
public void init(CategoryItem categoryItem){
this.title=categoryItem.getTitle();
this.imagePath=categoryItem.getImagePath();
}
public MutableLiveData<ArrayList<CategoryViewModel>> getAllCategories(){
allCategories=repository.getCategory();
return allCategories;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getImagePath() {
return imagePath;
}
}
This is CategoryRepository class:
public class CategoryRepository {
private static final String TAG="CategoryRepository";
private static int FRESH_TIMEOUT_IN_MINUTES = 1;
private final Executor executor;
private APIInterface apiInterface;
public MutableLiveData<ArrayList<CategoryViewModel>> arrayListMutableLiveData=new MutableLiveData<>();
private CategoryDao categoryDao;
private Application application;
public CategoryRepository(Application application,Executor executor) {
this.executor = executor;
this.application = application;
apiInterface= APIClient.getClient().create(APIInterface.class);
LearnDatabase database= LearnDatabase.getInstance(application);
categoryDao=database.categoryDao();
}
public MutableLiveData<ArrayList<CategoryViewModel>> getCategory(){
refreshCategory();
List<CategoryItem> items;
categoryDao.loadCategoryItem();
items=categoryDao.loadCategoryItem().getValue(); // return null
CategoryItem category;
ArrayList<CategoryViewModel> arrayList=new ArrayList<>();
for(int i=0;i<items.size();i++){
category=items.get(i);
CategoryViewModel categoryViewModel=new CategoryViewModel(application);
categoryViewModel.init(category);
arrayList.add(categoryViewModel);
}
arrayListMutableLiveData.setValue(arrayList);
return arrayListMutableLiveData;
}
private void refreshCategory(){
executor.execute(() -> {
String lastRefresh=getMaxRefreshTime(new Date()).toString();
boolean sliderExists =(!(categoryDao.hasCategory(lastRefresh)).isEmpty());
Log.e(TAG,"sliderExist: "+sliderExists);
Log.e(TAG,"lastrefresh: "+lastRefresh);
Log.e(TAG,"hasSlider: "+categoryDao.hasCategory(lastRefresh).toString());
// If user have to be updated
if (!sliderExists) {
Log.e(TAG,"in if");
apiInterface.getCategory().enqueue(new Callback<List<CategoryItem>>() {
#Override
public void onResponse(Call<List<CategoryItem>> call, Response<List<CategoryItem>> response) {
executor.execute(() -> {
List<CategoryItem> categories=response.body();
for (int i=0;i<categories.size();i++){
categories.get(i).setLastRefresh(new Date());
categoryDao.saveCategory(categories.get(i));
}
});
}
#Override
public void onFailure(Call<List<CategoryItem>> call, Throwable t) {
Log.e(TAG,"onFailure "+t.toString());
}
});
}
});
}
private Date getMaxRefreshTime(Date currentDate){
Calendar cal = Calendar.getInstance();
cal.setTime(currentDate);
cal.add(Calendar.MINUTE, -FRESH_TIMEOUT_IN_MINUTES);
return cal.getTime();
}
}
This is xml layout of item of recyclerView:
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data class="CategoryDataBinding">
<variable
name="category"
type="com.struct.red.alltolearn.viewmodel.CategoryViewModel"/>
</data>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="200dp"
android:layout_height="150dp"
app:cardCornerRadius="15dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/imgItemCategory"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:imageUrl="#{category.imagePath}" />
<TextView
android:id="#+id/txtTitleItemCategory"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="#{category.title}"
android:textColor="#FFFFFF"
android:textSize="20sp"
android:textStyle="bold" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</layout>
This is CategoryDao class:
#Dao
public interface CategoryDao {
#Query("SELECT * FROM course_table")
LiveData<List<CategoryItem>> loadCategoryItem();
#Insert(onConflict = OnConflictStrategy.REPLACE)
void saveCategory(CategoryItem category);
#Query("SELECT * FROM category_table WHERE lastRefresh > Date(:lastRefreshMax)")
List<CategoryItem> hasCategory(String lastRefreshMax);
}
And finally I observe MutableLiveData in my Fragment:
private void setupCategoryRecycler() {
categoryViewModel = ViewModelProviders.of(this).get(CategoryViewModel.class);
categoryViewModel.getAllCategories().observe(this, new Observer<ArrayList<CategoryViewModel>>() {
#Override
public void onChanged(#Nullable ArrayList<CategoryViewModel> categoryViewModels) {
Log.e(TAG, "categoryitem: " + categoryViewModels.toString());
categoryAdapter = new CategoryAdapter(getContext(), categoryViewModels);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, true);
linearLayoutManager.setReverseLayout(true);
CategoryRecy.setLayoutManager(linearLayoutManager);
CategoryRecy.setAdapter(categoryAdapter);
}
});
}
Your problem is here, right?
public MutableLiveData<ArrayList<CategoryViewModel>> getCategory(){
...
items=categoryDao.loadCategoryItem().getValue(); // returns null
...
}
This is because your categoryDao.loadCategoryItem() method returns LiveData object. It means that method call will be executed in background thread. So when you call getValue() method the value yet null that moment.
To escape from this you can do two bad things.
1. Call loadCategoryItem() earlier, to have values later when calling getValue();
Your Repository class
public class CategoryRepository {
Livedata<List<CategoryItem>> items; // moved here
...
public void init () {
items=categoryDao.loadCategoryItem();
}
public MutableLiveData<ArrayList<CategoryViewModel>> getCategory(){
ArrayList<CategoryViewModel> arrayList=new ArrayList<>();
List<CategoryItem> currentList = items.getValue();
for(int i=0;i<currentList.size();i++){
...
}
arrayListMutableLiveData.setValue(arrayList);
return arrayListMutableLiveData;
}
}
Your ViewModel class
public class CategoryViewModel extends AndroidViewModel {
public void init(CategoryItem categoryItem){
repository.init(); // added
this.title=categoryItem.getTitle();
this.imagePath=categoryItem.getImagePath();
}
This can work but we have 2 problems. First is that still there is no guarantee that values will not be null. Second problem is that you cannot observe your item changes. Even tho you are returning arrayListMutableLiveData object, which is livedata, you are setting its value manually once, and its value will not be changed unless you call getCategory() again.
2. Second hack is load category items synchronously
public interface CategoryDao {
#Query("SELECT * FROM category_table") LiveData<List<CategoryItem>>loadCategoryItem();
#Query("SELECT * FROM category_table") List<CategoryItem> loadCategoryItemsSync();
In this case your getAllCategories () and getCategory() methods also should work synchronously.
Something like this
public void getCategory(Listener listener){
executor.execute(() -> {
ArrayList<CategoryViewModel> arrayList=new ArrayList<>();
List<CategoryItem> currentList = items.getValue();
for(int i=0;i<currentList.size();i++){
...
}
arrayListMutableLiveData.setValue(arrayList);
listener.onItemsLoaded(arrayListMutableLiveData);
}
}
In this case also we have the second problem -> you cannot observe your item changes.
I wrote this to better clarify the problem. *
The real problem is that you trying use CategoryViewModel for data binding.
Please use CategoryItem instead
I suggest to remove this two rows from viewModel
private String title;
private String imagePath;
Try to solve your problem without parsing data from List to ArrayList.
public LiveData<List<CategoryItem>> getAllCategories(){
if (items == null) {
items = categoryDao.loadCategoryItem()
}
return items;
}
then try to use CategoryItem as data object
<data class="CategoryDataBinding">
<variable
name="category"
type="com.struct.red.alltolearn.///.CategoryItem "/>
</data>
and try to change your adapter to make possible doing this
categoryViewModel = ViewModelProviders.of(this).get(CategoryViewModel.class);
categoryViewModel.getAllCategories().observe(this, new Observer<List<CategoryItem >>() {
#Override
public void onChanged(#Nullable List<CategoryItem > categoryItems) {
categoryAdapter = new CategoryAdapter(getContext(), categoryItems);
...
Maybe you can use a trasnformation?
//this is returned to the observer in setupCategoryRecycler()
return Transformations.switchMap(repository.getCategory()) { result ->
//do any other stuff you need here
allCategories.setValue(result)
}
A transformation can be use to convert one liveData into another. Check: https://developer.android.com/topic/libraries/architecture/livedata#transform_livedata
You're trying to load data from the wrong table course_table
#Query("SELECT * FROM course_table") LiveData>
loadCategoryItem();
It should be category_table
Your items=categoryDao.loadCategoryItem().getValue() will not have any value unless you call observe on it.
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