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
Related
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.
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 am trying to create recyclerview inside recyclerview which is retrieving the data from Firebase.
So far, I have two recyclerview adapters. GenreAdapter and AnimeInsideGenreAdapter classes.
I was able to show GenreAdapter data into my HomeFragment, but the AnimeInsideGenreAdapter is not showing any data and I have no idea why. I've been looking for my problem on Google but still not getting any luck.
So here are my classes and layouts:
GenreAdapter.class
public class GenreAdapter extends RecyclerView.Adapter {
private List<Genre> genreList;
private Context context;
private List<Anime> perAnimes;
private RecyclerView rvPerAnime;
private RecyclerView.Adapter adapterPerAnime;
class ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder {
FontAppCompatTextView genre_id, genre_title;
LinearLayout main;
public ViewHolder(final View itemView) {
super(itemView);
main = itemView.findViewById(R.id.main_layout);
genre_id = itemView.findViewById(R.id.genre_id);
genre_title = itemView.findViewById(R.id.genre_title);
}
}
public GenreAdapter(List<Genre> genreList, Context context) {
this.genreList = genreList;
this.context = context;
}
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_genre, parent, false));
}
public void onBindViewHolder(ViewHolder holder, int position) {
Genre genre = this.genreList.get(position);
holder.genre_id.setText(genre.id);
holder.genre_title.setText(genre.genre);
perAnimes = new ArrayList<>();
DatabaseReference databaseAnime = FirebaseDatabase.getInstance().getReference("anime");
Query query_anime = databaseAnime.orderByChild("genreid").equalTo(genre.id);
query_anime.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
perAnimes.clear();
if (dataSnapshot.exists()) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Anime anime = snapshot.getValue(Anime.class);
perAnimes.add(anime);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
perAnimes.sort(new Comparator<Anime>() {
#Override
public int compare(Anime compare1, Anime compare2) {
return compare1.getTitle().compareToIgnoreCase(compare2.getTitle());
}
});
}
adapterPerAnime.notifyDataSetChanged();
} else {
perAnimes.clear();
adapterPerAnime.notifyDataSetChanged();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
rvPerAnime = holder.itemView.findViewById(R.id.rvanime);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
rvPerAnime.setLayoutManager(linearLayoutManager);
rvPerAnime.setHasFixedSize(true);
adapterPerAnime = new AnimeInsideGenreAdapter(perAnimes, context);
rvPerAnime.setAdapter(adapterPerAnime);
Animation up_from_bottom = AnimationUtils.loadAnimation(context, R.anim.up_from_bottom);
holder.itemView.startAnimation(up_from_bottom);
}
public int getItemCount() {
return this.genreList.size();
}
}
item_genre.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/main_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.pixplicity.fontview.FontAppCompatTextView
android:id="#+id/genre_title"
style="#style/FontTextViewStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
android:singleLine="true"
android:text="Genre Anime"
android:textColor="#f59e24"
android:textSize="14dp"
android:textStyle="bold" />
<com.pixplicity.fontview.FontAppCompatTextView
android:id="#+id/genre_id"
style="#style/FontTextViewStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="ID Genre"
android:textColor="#7c7c7c"
android:textSize="12dp"
android:visibility="gone" />
<android.support.v7.widget.RecyclerView
android:id="#+id/rvanime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp" />
</LinearLayout>
AnimeInsideGenreAdapter.class
public class AnimeInsideGenreAdapter extends RecyclerView.Adapter<AnimeInsideGenreAdapter.ViewHolder> {
List<Anime> perAnimes;
private Context context;
private Random mRandom = new Random();
class ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder {
public FontAppCompatTextView anime_id, anime_title;
public ImageView img_anime;
public LinearLayout main;
public ViewHolder(final View itemView) {
super(itemView);
main = itemView.findViewById(R.id.main_layout);
anime_id = itemView.findViewById(R.id.anime_id);
anime_title = itemView.findViewById(R.id.anime_title);
img_anime = itemView.findViewById(R.id.img_anime);
Animation up_from_bottom = AnimationUtils.loadAnimation(itemView.getContext(), R.anim.up_from_bottom);
itemView.startAnimation(up_from_bottom);
}
}
public AnimeInsideGenreAdapter(List<Anime> perAnimes, Context context) {
this.perAnimes = perAnimes;
this.context = context;
}
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_anime_inside_genre, parent, false));
}
public void onBindViewHolder(final ViewHolder holder, final int position) {
final Anime perAnime = this.perAnimes.get(position);
holder.anime_id.setText(perAnime.getId());
holder.anime_title.setText(perAnime.getTitle());
Toast.makeText(context, perAnime.toString(), Toast.LENGTH_SHORT).show();
Picasso.with(context).load(perAnime.getImgcover()).fit().into(holder.img_anime);
holder.img_anime.getLayoutParams().width = getRandomIntInRange(270,200);
holder.img_anime.getLayoutParams().height = 250;
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
}
});
}
public int getItemCount() {
return this.perAnimes.size();
}
// Custom method to get a random number between a range
protected int getRandomIntInRange(int max, int min){
return mRandom.nextInt((max-min)+min)+min;
}
}
item_anime_inside_genre.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/main_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:orientation="vertical"
card_view:cardCornerRadius="4dp"
card_view:cardElevation="4dp"
card_view:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
<com.pixplicity.fontview.FontAppCompatTextView
android:id="#+id/anime_id"
style="#style/FontTextViewStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
android:singleLine="true"
android:text="Anime ID"
android:textColor="#f59e24"
android:textSize="14dp"
android:textStyle="bold" />
<ImageView
android:id="#+id/img_anime"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"/>
<com.pixplicity.fontview.FontAppCompatTextView
android:id="#+id/anime_title"
style="#style/FontTextViewStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Anime Title"
android:textColor="#7c7c7c"
android:textSize="12dp" />
</LinearLayout>
</android.support.v7.widget.CardView>
Genre.class
public class Genre {
String id;
String genre;
public Genre() {
}
public Genre(String id, String genre) {
this.id = id;
this.genre = genre;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getGenre() {
return genre;
}
public void setGenre(String genre) {
this.genre = genre;
}}
Anime.class
public class Anime {
String id;
String genreid;
String title;
String description;
String imgcover;
public Anime() {
}
public Anime(String id, String genreid, String title, String description, String imgcover) {
this.id = id;
this.genreid = genreid;
this.title = title;
this.description = description;
this.imgcover = imgcover;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getGenreid() {
return genreid;
}
public void setGenreid(String genreid) {
this.genreid = genreid;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getImgcover() {
return imgcover;
}
public void setImgcover(String imgcover) {
this.imgcover = imgcover;
}}
I need to show the anime list from Firebase inside each genres adapter.
Any help will be much appreciated.
Thank you.
I am retrieving JSON data and parcing it by Retrofit. I want to display it on RecyclerView but can't make it display the views. Where am I doing it wrong? Here MainActivity, Model and ListFlowerAdapter are given
public class MainActivity extends AppCompatActivity {
private ListFlowerAdapter mListFlowerAdapter;
private RecyclerView mRecyclerView;
private RetrofitClient mRetrofitClient;
LinearLayoutManager linearLayoutManager;
//private List<FlowerModel> myFlowers;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
configViews();
mRetrofitClient = new RetrofitClient();
Call<List<FlowerModel>> listCall = mRetrofitClient.getFlowerService().getAllFlowers();
listCall.enqueue(new Callback<List<FlowerModel>>() {
#Override
public void onResponse(Call<List<FlowerModel>> call, Response<List<FlowerModel>> response) {
if (response.isSuccessful()) {
List<FlowerModel> flowerList = response.body();
for (int i = 0; i < flowerList.size(); i++) {
FlowerModel flowerModel = flowerList.get(i);
mListFlowerAdapter.addFlower(flowerModel);
}
} else {
int sc = response.code();
switch (sc) {
}
}
}
#Override
public void onFailure(Call<List<FlowerModel>> call, Throwable t) {
}
});
}
private void configViews() {
mRecyclerView = findViewById(R.id.recycler_view);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool());
linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(linearLayoutManager);
mListFlowerAdapter = new ListFlowerAdapter();
mRecyclerView.setAdapter(mListFlowerAdapter);
//mRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext(),LinearLayoutManager.VERTICAL,false));
//mListFlowerAdapter = new ListFlowerAdapter();
// mRecyclerView.setAdapter(mListFlowerAdapter);
}
}
ListFlowerAdapter class
public class ListFlowerAdapter extends RecyclerView.Adapter<ListFlowerAdapter.MyViewHolder> {
private static final String TAG = ListFlowerAdapter.class.getSimpleName();
private Context context;
private List<FlowerModel> myFlowers;
public ListFlowerAdapter() {
myFlowers = new ArrayList<>();
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View row = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_item, null, false);
return new MyViewHolder(row);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
FlowerModel currFlower = myFlowers.get(position);
holder.mName.setText(currFlower.getName());
holder.mPrice.setText(Double.toString(currFlower.getPrice()));
Picasso.with(holder.itemView.getContext()).load("http://services.hanselandpetal.com/photos/" + currFlower.getPhoto()).into(holder.mPhoto);
}
#Override
public int getItemCount() {
return myFlowers.size();
}
public void addFlower(FlowerModel flowerModel) {
myFlowers.add(flowerModel);
notifyDataSetChanged();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
private ImageView mPhoto;
private TextView mName, mPrice;
public MyViewHolder(View itemView) {
super(itemView);
mPhoto = itemView.findViewById(R.id.flower_photo);
mName = itemView.findViewById(R.id.flower_name);
mPrice = itemView.findViewById(R.id.flower_price);
}
}
}
FlowerModel class
public class FlowerModel implements Serializable {
#Expose
private String category;
#Expose
private String price;
#Expose
private String instructions;
#Expose
private String photo;
#Expose
private String name;
#Expose
private int productId;
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public double getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getInstructions() {
return instructions;
}
public void setInstructions(String instructions) {
this.instructions = instructions;
}
public String getPhoto() {
return photo;
}
public void setPhoto(String photo) {
this.photo = photo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getProductId() {
return productId;
}
public void setProductId(int productId) {
this.productId = productId;
}
}
XML
<?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="wrap_content"
android:padding="5dp"
android:orientation="horizontal">
<ImageView
android:id="#+id/flower_photo"
android:layout_width="150dp"
android:layout_height="150dp"
android:background="#mipmap/ic_launcher"
android:scaleType="centerCrop" />
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/flower_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Large"
android:text="Large Text" />
<TextView
android:id="#+id/flower_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Medium"
android:text="Medium Text" />
</LinearLayout>
<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:orientation="vertical"
android:padding="16dp"
tools:context=".MainActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Stop Downloading" />
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
android:visibility="visible" />
Could you help me with the issue, please? Thank you very much.
Don't notify your adapter recursively,
Your code :
for (int i = 0; i < flowerList.size(); i++) {
FlowerModel flowerModel = flowerList.get(i);
mListFlowerAdapter.addFlower(flowerModel); // Called from here
}
Code from adapter
public void addFlower(FlowerModel flowerModel) {
myFlowers.add(flowerModel);
notifyDataSetChanged(); // Notifying everytime
}
Instead, you should add all data to adapter and notify only once : (Updated code)
for (int i = 0; i < flowerList.size(); i++) {
FlowerModel flowerModel = flowerList.get(i);
mListFlowerAdapter.addFlower(flowerModel);
}
mListFlowerAdapter.notifyDataSetChanged(); // Notify like this
Code from adapter
public void addFlower(FlowerModel flowerModel) {
myFlowers.add(flowerModel);
//notifyDataSetChanged(); Remove from here
}
Pass activity context to the adapter and use that context for populating item on list view.
private Context mContext;
public ListFlowerAdapter(Context context) {
myFlowers = new ArrayList<>();
this.mContext = context;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View row = LayoutInflater.from(mContext).inflate(R.layout.row_item, parent, false);
return new MyViewHolder(row);
}
From activity send the activity context for initializing the adapter like this
mListFlowerAdapter = new ListFlowerAdapter(this);
And for adding a new item
public void addFlowers(List<FlowerModel> flowerModels) {
for (int i = 0; i < flowerModels.size(); i++) {
FlowerModel flowerModel = flowerModels.get(i);
myFlowers.add(flowerModel);
}
notifyDataSetChanged();
}
And successful response just send the list for updating the adapter
List<FlowerModel> flowerList = response.body();
mListFlowerAdapter.addFlowers(flowerList);
Hope this will help.
Try to remove this line:
mRecyclerView.setHasFixedSize(true);
And add this in the XML file:
android:fillViewport="true"
Without that line, your RecyclerView content initial height is 0 (empty list), and with the fixed size it can't grow although you add items to the adapter.