I've created a recyclerView into a fragment. Everything goes well but when i scroll in the list of elements, the attributes change without reason
Here is the code of the fragment:
public class HistorySectionFragment extends Fragment {
private static final String TAG = HistorySectionFragment.class.getSimpleName();
static ArrayList<String> a;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
RecyclerView recyclerView = (RecyclerView) inflater.inflate(
R.layout.recycler_view, container, false);
ContentAdapter adapter = new ContentAdapter();
recyclerView.setAdapter(adapter);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
return recyclerView;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
static TextView card_title;
static TextView card_text;
public ViewHolder(LayoutInflater inflater, ViewGroup parent) {
super(inflater.inflate(R.layout.item_card, parent, false));
card_title = (TextView)itemView.findViewById(R.id.card_title);
card_text = (TextView)itemView.findViewById(R.id.card_text);
}
}
public static class ContentAdapter extends RecyclerView.Adapter<ViewHolder>{
// Set numbers of Card in RecyclerView.
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext()), parent);
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position) {
final String name = MainActivity.getTestByPosition(position).getName();
holder.card_title.setText(name);
final String description = MainActivity.getTestByPosition(position).getDescription();
holder.card_text.setText(description);
}
#Override
public int getItemCount() {
return MainActivity.getSize();
}
}
}
The problem is when the recyclerview calls to create new elements.
EDIT:
When i say the attributes change i mean the information of each cardView change doing scroll
I have a feeling the views in your RecyclerView are not stable. When the views get recycled, the ids are being saved and the data is mismatched.
Trying doing this.
recyclerView.setHasStableIds(false);
Firstly why you use inflater for the recyclerview? the best way is to declare your recyclerview in xml file and get the recyclerview via findviewById.
Secondly, what do you mean about the attributes change without reason
And finally:it's not very appreciate to use viewholder and adapter like that,
http://javatechig.com/android/android-recyclerview-example
SOLVED.
The problem was in the recycler and in the viewHolder are both Static classes.
Related
Problem Statement
I have a problem of data being changed in fragment whenever the data is modified in the BottomSheetDialogFragment
App Description
In my app I have the MainActivity which host 2 Fragment in it's ViewPager. 1st Fragment for app content and 2nd Fragment (let's call it GalleryFragment) that shows the gallery view. User can tap on gallery item which loads up the BottomSheet (let's call it GalleryBottomSheet) - that hosts RecyclerView to show gallery item in full screen. Now initially app feeds the GalleryFragment with the ArrayList to show the gallery items. When user clicks on the Gallery item, this ArrayList is passed to the GalleryBottomSheet.
So What's Happening
What's happening is whenever I am removing an item from the ArrayList in my GalleryBottomSheet, It automatically also remove that item in the ArrayList of GalleryFragment. In short, Any update in the Arraylist from GalleryBottomSheet impacting the ArrayList in GalleryFragment
What do you want
I want seperation of concerns. I don't want the change made in the ArrayList of GalleryBottomSheet to impact the original ArrayList of GalleryFragment
Show me the damn code
To make this question concise, I am adding only the important part of the code.
~ GalleryFragment.java
public class GalleryFragment extends Fragment {
private RecyclerView recyclerView;
private ArrayList<String> arrayList = new ArrayList<>(); //This is the one which will be passed to the GalleryBottomSheet
private GalleryAdapter galleryAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_gallery, container, false);
//setting up all the UI work...
arrayList = FindFiles(); //FindFiles is a private function searching for all file in the dir and adding the path as a string to the arraylist
galleryAdapter = new GalleryAdapter(getActivity()); //init the adapter
recyclerView.setAdapter(galleryAdapter); //setting the adapter
return view;
}
}
private class GalleryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final Activity activity;
GalleryAdapter(Activity context) {
this.activity = context;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.gallery_content_item, parent, false);
return new ItemViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
if(holder instanceof ItemViewHolder){
//setting up stuff..
}
}
#Override
public int getItemCount() {
return arrayList.size();
}
private class ItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
ImageView imageView;
ItemViewHolder(View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.imageView);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
Bundle bundle = new Bundle();
bundle.putStringArrayList("list", arrayList);
GalleryBottomSheet galleryBottomSheet= GalleryBottomSheet.newInstance();
galleryBottomSheet.setOnRefreshListener( new GalleryBottomSheet.GalleryInterface() {
#Override
public void onRefresh() {
//here the actual arrayList size reduced even though the arrayList that was modified exist in GalleryBottomSheet
System.out.println("CURRENT LIST SIZE: " + arrayList.size());
}
});
galleryBottomSheet.setArguments(bundle);
galleryBottomSheet.show(getParentFragmentManager(), "galleryPager");
}
}
~ GalleryBottomSheet.java
public class GalleryBottomSheet extends BottomSheetDialogFragment {
static GalleryBottomSheet newInstance() {
return new GalleryBottomSheet();
}
public interface GalleryInterface {
void onRefresh();
}
private RecyclerView recyclerView;
private ViewAdapter viewAdapter;
private Button deleteBtn;
private GalleryInterface galleryInterface;
public void setOnRefreshListener( GalleryInterface galleryInterface){
this.galleryInterface = galleryInterface;
}
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
//.. setting up sheetDialog
return bottomSheetDialog;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(BottomSheetDialogFragment.STYLE_NO_FRAME, R.style.GalleryBottomStyle);
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.gallery_sheet, container, false);
Bundle bundle = getArguments();
ArrayList<String> filePathArr = bundle.getStringArrayList("list"); //here arrayList from GalleryFragment
//Setting up all UI views...
deleteBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int positionPager = recyclerView.computeVerticalScrollOffset(); //just for demo, in the actual app we are using addOnScrollListener for position
filePathArr.remove(positionPager);
viewAdapter.notifyItemRemoved(positionPager);
galleryInterface.onRefresh(); //this is where GalleryFragment shows that the arraylist is modified too.
Toast.makeText(getActivity(), "Deleted Successfully",Toast.LENGTH_SHORT).show();
}
});
return view;
}
//setting up viewAdapter and other stuff
}
Well, it turns out the main problem is that object is stored in memory by reference. By modifying the arrayList from GalleryBottomSheet it also changes the original arrayList since the exact arrayList was referred in GalleryBottomSheet from GalleryFragment. The solution is to simply initializing a new ArrayList in GalleryBottomSheet
Changing from:
ArrayList<String> filePathArr = bundle.getStringArrayList("list");
to:
ArrayList<String> filePathArr = new ArrayList<>(bundle.getStringArrayList("list"));
This question already has an answer here:
showing RecyclerView on fragment with data from Firebase
(1 answer)
Closed 3 years ago.
I am not able to attach the Firestore Recycler Adapter in the fragment.
I googled many things but no good yet.
The fragment is one of the tabs of the bottomtablayout.
The data is retrieved from a single collection. I want represent the list of multlipe-user post in a single view.
I have tried the below code but to no good yet.
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
//just change the fragment_dashboard
//with the fragment you want to inflate
//like if the class is HomeFragment it should have R.layout.home_fragment
//if it is DashboardFragment it should have R.layout.fragment_dashboard
View view = inflater.inflate(R.layout.fragment_home, container, false);
final FragmentActivity c = getActivity();
LinearLayoutManager layoutManager = new LinearLayoutManager(c);
Query query = PostsRef.orderBy("timestamp", Query.Direction.DESCENDING);
FirestoreRecyclerOptions<PostsModel> options = new FirestoreRecyclerOptions.Builder<PostsModel>()
.setQuery(query, PostsModel.class)
.build();
adapter = new PostsAdapter(options);
recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(c));
recyclerView.setAdapter(adapter);
mParent =view.findViewById(R.id.relative_home);
return inflater.inflate(R.layout.fragment_home, null);
}
Adapter Code
public class PostsAdapter extends FirestoreRecyclerAdapter<PostsModel, PostsAdapter.PostsHolder> {
private OnItemClickListener listener;
public PostsAdapter(#NonNull FirestoreRecyclerOptions<PostsModel> options) {
super(options);
}
#Override
protected void onBindViewHolder(#NonNull PostsHolder holder, int position, #NonNull PostsModel model) {
//retrieve the fields here
holder.textViewTitle.setText(model.getPostTitle());
holder.textViewDescription.setText(model.getPostContent());
holder.textViewPriority.setText(String.valueOf(model.getSpinnerC()));
holder.AuthorName.setText(model.getName());
holder.AuthorGender.setText(model.getGender());
}
#NonNull
#Override
public PostsHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.post_list_layout,
parent, false);
return new PostsHolder(v);
}
public void deleteItem(int position) {
getSnapshots().getSnapshot(position).getReference().delete();
}
class PostsHolder extends RecyclerView.ViewHolder {
TextView textViewTitle;
TextView textViewDescription;
TextView textViewPriority;
TextView AuthorName;
TextView AuthorGender;
public PostsHolder(View itemView) {
super(itemView);
textViewTitle = itemView.findViewById(R.id.quote1);
textViewDescription = itemView.findViewById(R.id.name1);
textViewPriority = itemView.findViewById(R.id.timestamp1);
}
}
}
You're inflating the other view in the onCreateView method.
return inflater.inflate(R.layout.fragment_home, null);
I'm trying to implement RecyclerView in an app. I followed the android hive guide but the items won't show. After a lot of checks I still couldn't find the problem.
Do I need to use implementation RecylerView in my build.app I'm using androidX
I'm using this RecylcerView in a fragment not activity
My adapter class:
public class CouponsAdapter extends RecyclerView.Adapter<CouponsAdapter.ViewHolder> {
private List<CouponsModel> couponsList;
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView productIds,couponUsage,couponLimit,couponAmount,couponCode,couponType,date;
public ViewHolder(#NonNull View itemView) {
super(itemView);
productIds=(TextView)itemView.findViewById(R.id.products_ids);
couponUsage=(TextView)itemView.findViewById(R.id.usage_limit);
couponAmount=(TextView)itemView.findViewById(R.id.coupon_amount);
couponCode=(TextView)itemView.findViewById(R.id.coupon_code);
couponType=(TextView)itemView.findViewById(R.id.coupon_type);
date=(TextView)itemView.findViewById(R.id.date);
}
}
public CouponsAdapter (List<CouponsModel> couponsList){
this.couponsList=couponsList;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.coupons_list,parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
CouponsModel couponsModel=couponsList.get(position);
holder.date.setText(couponsModel.getDate());
holder.couponType.setText(couponsModel.getCouponType());
holder.couponCode.setText(couponsModel.getCouponCode());
holder.couponAmount.setText(couponsModel.getCouponAmount());
holder.couponUsage.setText(couponsModel.getCouponUsage());
holder.productIds.setText(couponsModel.getProductIds());
}
#Override
public int getItemCount() {
if(couponsList.size() == 0)
return 1;
return couponsList.size();
}
My fragment :
// Inflate the layout for this fragment
View view= inflater.inflate(R.layout.fragment_coupons, container, false);
recyclerView=view.findViewById(R.id.coupons_recyler_view);
couponsAdapter=new CouponsAdapter(couponsModelList);
recyclerView.setAdapter(couponsAdapter);
int x=32;
couponsModelList.add(new CouponsModel(x,x,x,x,"free50","free",x));
couponsAdapter.notifyDataSetChanged();
return view;
}
You should set Layout Manager to your RecyclerView.
If layout manager is not set, you will get the following error: No layout manager attached; Skipping layout
You are missing Layout-manager .Just add this line to your code.
recyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
I have a List<String> listOfNames that contains names. How to print them all using RecyclerView?
I was looking for a simple way of doing this and after some time of fiddling around, I think I have found a way.
Here I use an ArrayList of Strings.
Adapter Class
public class TagsAdapter extends RecyclerView.Adapter<TagsAdapter.TagsViewHolder> {
ArrayList<String> arrayList;
public TagsAdapter(ArrayList<String> arrayList) {
this.arrayList = arrayList;
}
#NonNull
#Override
public TagsViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_holder_tags_chips, parent, false);
return new TagsAdapter.TagsViewHolder(layoutView);
}
#Override
public void onBindViewHolder(#NonNull final TagsViewHolder holder, final int position) {
holder.tagText.setText(arrayList.get(position));
}
#Override
public int getItemCount() {
return arrayList.size();
}
public class TagsViewHolder extends RecyclerView.ViewHolder {
public TextView tagText;
public TagsViewHolder(View view) {
super(view);
tagText = view.findViewById(R.id.chipTextView);
}
}
}
Now in the Activity or fragment you want to show the recycler view, initialize your recycler view to the view in the xml
Tags.Java
private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
private RecyclerView.Adapter adapter;
In the same place add this method. I am assuming that the array list already has strings in it
private void getTags() {
recyclerView = view.findViewById(R.id.view);
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setHasFixedSize(false);
layoutManager = new LinearLayoutManager(requireActivity(), LinearLayoutManager.HORIZONTAL, false);
//I have made my recycler view horizontal, if you want it vertical, just change the horizontal above to vertical.
recyclerView.setLayoutManager(layoutManager);
adapter = new TagsAdapter(tagsArray);
recyclerView.setAdapter(adapter);
}
I know this is an old question but might help someone who wants a simple and straightforward way of doing this.
Hi Simple example for recycler view.
Follow below steps:
Declare in global this variable
private RecyclerView recyclerview;
Use this where you get response from server and make one model class using GSON plugin just copy and paste your response.After use that.
Gson gson = new Gson();
CreateYourModel createYourModel = gson.fromJson(response_data, YourActivity.class);
RecyclerAdapter mAdapter = new RecyclerAdapter(createYourModel);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
recyclerview.setLayoutManager(mLayoutManager);
recyclerview.setItemAnimator(new DefaultItemAnimator());
recyclerview.setAdapter(mAdapter);
recyclerview.setNestedScrollingEnabled(false);
This is your Recycler adapter just use same.
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {
private CreateYourModel mList;
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView tvdate;
public MyViewHolder(View view) {
super(view);
tvdate = (TextView) view.findViewById(R.id.tvdate);
}
}
public RecyclerAdapterCreateYourModel mList) {
this.mList = mList;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.youritemview, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.tvsummuryloan_repayment_date.setText(setyourdatafromlist);
}
#Override
public int getItemCount() {
return mList.size();
}
}
You can follow any tutorial on google.
Thanks
Im trying to add a listview inside a fragment witch is also inside a tabhost. the app is not crashing or anything, but the list view is not showing anything.
Here is my code:
Class for the tabPager
public class TabPagerAdapter extends FragmentPagerAdapter {
public TabPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
switch (index) {
case 0:
return new FragmentHome();
case 1:
return new FragmentBadges();
case 2:
return new FragmentBenefits();
}
return null;
}
Following is the fragment where I want the listview:
public class FragmentBadges extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_badges_list, null);
BadgesListAdapter adapter = new BadgesListAdapter(this.getActivity(), getCurrentBadges());
ListView badgeslist = (ListView) rootView.findViewById(R.id.badges_list);
badgeslist.setAdapter(adapter);
badgeslist.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
//TODO do some
}
});
return rootView;
}
And following is the adapter:
public class BadgesListAdapter extends ArrayAdapter<String> {
private final Activity context;
private List<Badge> badges;
public BadgesListAdapter(Activity context, List<Badge> badges) {
super(context, R.layout.fragment_badges_listrow);
this.context = context;
this.badges = badges;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View rowView= inflater.inflate(R.layout.fragment_badges_listrow, null, true);
TextView txtTitle = (TextView) rowView.findViewById(R.id.text);
ImageView imageView = (ImageView) rowView.findViewById(R.id.img);
txtTitle.setText(badges.get(position).getName());
imageView.setImageResource(badges.get(position).getDrawableValue());
return rowView;
}
while debugging I found out that the getView method inside the badgesListAdapter is never called.
I have this same code for another app but without the tabpager and there it all works perfectly...
Check whether getCurrentBadges() method not returns empty list. If so there is no data to show in ListView.
I was able to make it work by inhering ListFragment in FragmentBadges, following this tutorial https://www.youtube.com/watch?v=heR4zhj_wV0