RecyclerView freezes when start to scroll after restoring from background - android

Here is my adapter class
public class CategoryAdapter extends RecyclerView.Adapter<CategoryAdapter.ViewHolder> {
List<CategoryItem> mItems;
public CategoryAdapter(Context context) {
super();
Resources res = context.getResources();
mItems = new ArrayList<>();
mItems.add(new CategoryItem(res.getString(R.string.category_book), R.drawable.books));
// ... few items
mItems.add(new CategoryItem(res.getString(R.string.category_clothing), R.drawable.clothes));
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.item_category_selection, viewGroup, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
CategoryItem category = mItems.get(i);
viewHolder.title.setText(category.getTitle());
viewHolder.thumbnail.setImageResource(category.getThumbnail());
}
#Override
public int getItemCount() {
return mItems.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
public TextView title;
public ImageView thumbnail;
public CardView card;
public ViewHolder(View itemView){
super(itemView);
card = (CardView)itemView.findViewById(R.id.card_view);
title = (TextView)itemView.findViewById(R.id.category_title);
thumbnail = (ImageView)itemView.findViewById(R.id.category_thumbnail);
}
}
}
My fragment
public class CategorySelectionFragment extends Fragment {
RecyclerView mRecyclerView;
RecyclerView.LayoutManager mLayoutManager;
RecyclerView.Adapter mAdapter;
public CategorySelectionFragment() { }
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_category_selection, container, false);
mRecyclerView = (RecyclerView)v.findViewById(R.id.recycler_view);
setUpGrid();
return v;
}
private void setUpGrid() {
mRecyclerView.setHasFixedSize(true);
colNum = 3;
mLayoutManager = new GridLayoutManager(getActivity(), colNum);
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new CategoryAdapter(getActivity());
mRecyclerView.setAdapter(mAdapter);
}
When fragment just created (onCreateView called) recyclerview works perfectly, but when app goes to background and then restore scroll start to freeze on the first few items and then continue to work smoothly.
When app restore from background onCreateView method is not called so I try to set up adapter for recyclerview in onStart(), like this:
#Override
public void onStart(){
super.onStart();
// Adapter setting here to avoid freezes, when start to scroll after switching to an app from background.
mRecyclerView.setAdapter(mAdapter);
}
This approach has solved the problem, but it seems like not realy clear way to solve that issue. Since for example, restoring the fragment leads to reset last scrolled position.
Thanks for your help!

Related

RecycleView doesn't work in android fragement

I am writing a app which use a recycleView in fragement. However only the textView in that fragement show,there is nothing in the recycleView ,function like onBindViewHolder() in the recycleView Adapter wasn't been called .Here is my code of recycleViewAdapter and fragement.
Adapter
import java.util.List;
public class ShoppingAdapter extends RecyclerView.Adapter<ShoppingAdapter.MyViewHolder> {
private List<Shopping> localData;
public ShoppingAdapter(List<Shopping> localData) {
this.localData = localData;
}
public static class MyViewHolder extends RecyclerView.ViewHolder{
TextView textView;
ImageView imageView;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
textView =itemView.findViewById(R.id.shopping_text);
imageView = itemView.findViewById(R.id.shopping_img);
}
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
Log.d("test", "onCreateViewHolder: ");
View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.shopping_item,parent,false);
return null;
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
holder.textView.setText(localData.get(position).getTitle());
holder.imageView.setImageResource(localData.get(position).getImageResource());
}
#Override
public int getItemCount() {
return this.localData.size();
}
}
Fragment
public class shoppingFragment extends Fragment {
View view;
List<Shopping> shoppingList;
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initShoppingList();
RecyclerView recyclerView =(RecyclerView) view.findViewById(R.id.shopping_recycle_view);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(view.getContext());
ShoppingAdapter myAdapter=new ShoppingAdapter(shoppingList);
recyclerView.setAdapter(myAdapter);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_shopping, container, false);
return view;
}
public void initShoppingList(){
shoppingList = new ArrayList<Shopping>();
shoppingList.add(new Shopping(R.drawable.data,"data"));
shoppingList.add(new Shopping(R.drawable.position,"position"));
shoppingList.add(new Shopping(R.drawable.floor,"floor"));
}
}
Looks like you are missing 2 crucial things.
onCreateViewHolder should return a view. You return null.
return new MyViewHolder(view);
You forgot to set the LayoutManager to your adapter.
recyclerView.setLayoutManager(linearLayoutManager);
Instead of returning null at onCreateViewHolder, you should return new MyViewHolder(view);
And you forgot to assign the layoutmanager you created on your fragment into your recyclerview (recyclerView.setLayoutManager(linearLayoutManager);)
Also, you don't need to cast recyclerview to recyclerview. You can remove (RecyclerView) from RecyclerView recyclerView =(RecyclerView) view.findViewById(R.id.shopping_recycle_view);

Recycle view not showing items when I start the app but after going to another fragment and back it works

I have to set up a recycle view inside a fragment. The problem is that when I start the app it shows nothing but if i switch to another fragment and go back all items are there. If i start the app and try to scroll through a the recycle view the first item and the last one will load. I tried searching for an answer but there is nothing useful. I mention i just started working in Android Studio.
That's the fragment code
public class Main_fragment extends Fragment {
TextView titleText;
ArrayList<String> titles = new ArrayList<>();
// Access it from anywhere
static String FoodChoiceVar = "All food"; // Value set for test only. Maybe make an ENUM instead?
public Main_fragment() {
// Needed empty constructor.
}
// Don't edit this method as you won't be able tu use "R".
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
titles.add("Breakfast");titles.add("Morning Snack");titles.add("Lunch");titles.add("AfterNoon Snack");titles.add("Dinner"); titles.add("Night Snack");
}
//Use this instead.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.main_fragment, container, false);
final FragmentActivity c = getActivity();
titleText = view.findViewById(R.id.textViewFoodType);
titleText.setText(FoodChoiceVar + "| MENU");
RecyclerView recyclerView = view.findViewById(R.id.fragmentRecycleView);
LinearLayoutManager layoutManager = new LinearLayoutManager(c);
recyclerView.setLayoutManager(layoutManager);
ViewAdapter adapter = new ViewAdapter(c,titles);
recyclerView.setHasFixedSize(false);
recyclerView.setAdapter(adapter);
return view;
}
The ViewAdapter
public class ViewAdapter extends RecyclerView.Adapter<FoodMenuViewHolder> {
private LayoutInflater layoutInflater;
private List<String> titleData;
public ViewAdapter (Context context,List<String> titleData){
this.layoutInflater = LayoutInflater.from(context);
this.titleData = titleData;
}
#NonNull
#Override
public FoodMenuViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = layoutInflater.inflate(R.layout.layout_menu_item,viewGroup,false);
FoodMenuViewHolder holder = new FoodMenuViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(#NonNull FoodMenuViewHolder foodMenuViewHolder, int i) {
String title = titleData.get(i);
foodMenuViewHolder.titleText.setText(title);
}
#Override
public int getItemCount() {
return titleData.size();
}
}
The view holder
public class FoodMenuViewHolder extends RecyclerView.ViewHolder {
public TextView titleText;
public FoodMenuViewHolder(#NonNull View itemView) {
super(itemView);
titleText = itemView.findViewById(R.id.ItemText);
}
}
I have captured 2 short videos to show what is happening
https://drive.google.com/file/d/17wvlhPUT5R0SN38C2TbgBv_AP8awQUI3/view?usp=sharing
https://drive.google.com/file/d/1LJ0Xg4p8Q4a4nyGPSHdVQhBlYOYYi1Pv/view?usp=sharing
I think that your adapter it's losing itself, so try to get the context for layout inflater from viewgroup in onCreateViewHolder.
this:
public FoodMenuViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
return new FoodMenuViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_menu_item, viewGroup, false);
}
And to avoid anoying error, put a execption in getItemCount().
This:
#Override
public int getItemCount() {
if(titleData != null) {
return titleData.size();
} else {
return 0;
}
}
And try to use context instead of Fragment Activity
final FragmentActivity c = getActivity();
to
final Context c = getContext();

Displaying RecyclerView into fragment

I've got methods:
private void initImageBitmaps() {
mImageUrls.add("imageUrl");
mNames.add("abcd");
initRecyclerView();
}
private void initRecyclerView() {
Log.d(TAG, "initRecyclerView: init recyclerview.");
RecyclerView recyclerView = findViewById(R.id.recyclerv_view);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, mNames, mImageUrls);
recyclerView.setAdapter(adapter);
//recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setLayoutManager(new GridLayoutManager(this, 2));
}
Which add images to my recyclerview.
If it was in activity I would call initImageBitmaps() inside OnCreate. Unfortunately I have to use it in fragment and the question is: how to implement these methods to class which extends Fragment? Of course everything will be displayed into RecyclerView with recycler_view id in xml.
EDIT:
My Adapter:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>{
private static final String TAG = "RecyclerViewAdapter";
private ArrayList<String> mImageNames = new ArrayList<>();
private ArrayList<String> mImages = new ArrayList<>();
private Context mContext;
public RecyclerViewAdapter(WallpapersFragment context, ArrayList<String> imageNames, ArrayList<String> images ) {
mImageNames = imageNames;
mImages = images;
mContext = context;
//Rquired is android.content.context and found is WallpapersFragment from my project
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_listitem, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position) {
Log.d(TAG, "onBindViewHolder: called.");
Glide.with(mContext)
.asBitmap()
.load(mImages.get(position))
.into(holder.image);
holder.imageName.setText(mImageNames.get(position));
holder.parentLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(mContext, GalleryActivity.class);
intent.putExtra("image_url", mImages.get(position));
intent.putExtra("image_name", mImageNames.get(position));
mContext.startActivity(intent);
}
});
}
#Override
public int getItemCount() {
return mImageNames.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
ImageView image;
TextView imageName;
RelativeLayout parentLayout;
public ViewHolder(View itemView) {
super(itemView);
image = itemView.findViewById(R.id.image);
imageName = itemView.findViewById(R.id.image_name);
parentLayout = itemView.findViewById(R.id.parent_layout);
}
}
}
It compiles only when I comment mContext = context; in adapter. Then the error is:
java.lang.NullPointerException: You cannot start a load on a not yet attached View or a Fragment where getActivity() returns null (which usually occurs when getActivity() is called before the Fragment is attached or after the Fragment is destroyed).
There is an onCreate() method in the Fragment class, but that method is different from activity's onCreate().
public static class ExampleFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.example_fragment, container, false);
}
#Override
public void onViewCreated (View view, Bundle savedInstanceState) {
initRecyclerView();
}
}
Read more about fragments here: Fragments
initRecyclerView(view);
And then:
recyclerView = view.findViewById(R.id.recyclerv_view);
You can initialize your recycler view in following lifecycle callback:
onViewCreated()
and can also populate data method here like
initRecyclerView()
initImageBitmaps()
and for data refresh you can call notifyDatasetChanged() on adapter.
try this...
public class ExampleFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view= inflater.inflate(R.layout.example_fragment, container, false);
initImageBitmaps(view);
return view;
}
private void initImageBitmaps(View view) {
mImageUrls.add("imageUrl");
mNames.add("abcd");
initRecyclerView(View view);
}
private void initRecyclerView(View view) {
Log.d(TAG, "initRecyclerView: init recyclerview.");
RecyclerView recyclerView = view.findViewById(R.id.recyclerv_view); // init recyclerview
GridLayoutManager layoutManager = new GridLayoutManager(getContext(), 2);// declare layoutmanager
recyclerView.setLayoutManager(layoutManager); // set layoutmanager
RecyclerViewAdapter adapter = new RecyclerViewAdapter(getContext(), mNames, mImageUrls); // init adapter
recyclerView.setAdapter(adapter); // set adapter in recyclerveiw
}
EDIT
Replace WallpapersFragment with Context in adapter
public RecyclerViewAdapter(Context context, ArrayList<String> imageNames, ArrayList<String> images ) {
mImageNames = imageNames;
mImages = images;
mContext = context;
//Rquired is android.content.context and found is WallpapersFragment from my project
}

swipe cards with recycle view

This not like question its more like discussion
I'm using swipe cards from this library 'link.fls:swipestack:0.3.0'
With the help of these cards i'm creating recycle view on every card but the data is been repeating for every card
i have used adapter to generate cards and inside this adapter i have initialized recycle view
So my question is how to use recycle view with these swipe cards with non repeating values on every card...
Thanks in advance
Adapter code
public class ParentExamsCardAdapter extends BaseAdapter {
private Context mContext;
private List<ParentExamCards_Pojo> parentExamCardsPojoList = new ArrayList<>();
private RecyclerView recyclerView;
private ParentExamsDataAdapter dataAdapter;
public ParentExamsCardAdapter(Context mContext, List<ParentExamCards_Pojo> parentExamCardsPojoList, ParentExamsDataAdapter dataAdapter) {
this.mContext = mContext;
this.parentExamCardsPojoList = parentExamCardsPojoList;
this.dataAdapter = dataAdapter;
}
#Override
public int getCount() {
return parentExamCardsPojoList.size();
}
#Override
public Object getItem(int i) {
return i;
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int position, View view, ViewGroup viewGroup) {
View itemView = LayoutInflater.from(mContext).inflate(R.layout.single_parent_exams_swipecards, viewGroup, false);
ParentExamCards_Pojo pojoCards = parentExamCardsPojoList.get(position);
CardView cardView = itemView.findViewById(R.id.singleParentExamsCards_cardView);
LinearLayout linearLayout = itemView.findViewById(R.id.singleParentExamsCards_linear);
TextView textView_Title = itemView.findViewById(R.id.singleParentExamsCards_txtTitle);
cardView.setBackgroundColor(pojoCards.getColor());
textView_Title.setText(pojoCards.getExamname());
recyclerView = itemView.findViewById(R.id.singleParentExamsCards_recycleView);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(mContext);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.addItemDecoration(new DividerItemDecoration(mContext, LinearLayoutManager.VERTICAL));
recyclerView.setAdapter(dataAdapter);
return itemView;
}
#Override
public int getItemViewType(int position) {
return position;
}
}
ParentExamsDataAdapter
public class ParentExamsDataAdapter extends RecyclerView.Adapter<ParentExamsDataAdapter.MyViewHolder>{
private Context mContext;
private List<List<ParentExams_Pojo>> parentExamsPojoDataList = new ArrayList<>();
public ParentExamsDataAdapter(Context mContext, List<List<ParentExams_Pojo>> parentExamsPojoDataList) {
this.mContext = mContext;
this.parentExamsPojoDataList = parentExamsPojoDataList;
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView textView_name;
TextView textView_date;
TextView textView_time;
public MyViewHolder(View itemView) {
super(itemView);
textView_name=itemView.findViewById(R.id.singleParentExamsData_txtName);
textView_date=itemView.findViewById(R.id.singleParentExamsData_txtDate);
textView_time=itemView.findViewById(R.id.singleParentExamsData_txtTime);
}
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.single_parent_exams_data, parent, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
ParentExams_Pojo pojoData=parentExamsPojoDataList.get(position).get(position);
holder.textView_name.setText(pojoData.getSubjectname()+"-"+pojoData.getSubjectaspectname());
holder.textView_date.setText(pojoData.getExamdate());
holder.textView_time.setText(pojoData.getStarttime());
}
#Override
public int getItemCount() {
return parentExamsPojoDataList.size();
}
}
Basically You have to Set different adapter(ParentExamsDataAdapter(exams[position].getmarks)) inside the getview() method of ParentExamCardAdapter. The problem here is you are sending one instance of adapter to your parent adapter from Activity or Fragment I guess. And you are setting this for every CardAdapter.
Edit:
Adding suggested code changes from the comments to the answer.
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(mContext);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.addItemDecoration(new DividerItemDecoration(mContext, LinearLayoutManager.VERTICAL));
recyclerView.setAdapter(new ParentExamsDataAdapter(**list of items**));
found the solution your are passing same adapter to every recyclerview in every card that is one reason for your problem in ParentExamsCardAdapter
recyclerView.setAdapter(dataAdapter);
the data adapter is same for every postion
the arraylist value is same for aa recyclerview
pass List List ParentExams_Pojo arraylist to ParentExamsCardAdapter use its size in getItemCount
then in onbindviewholder use the arraylist.get(position) to pass to adapter then in adapter use List ParentExams_Pojo to get the list and its size in getitemcount it will solve i think
thus you will have only 1 positon in the adapyter
ParentExams_Pojo pojoData=parentExamsPojoDataList.get(position)

How to grey out fragment activity in android on condition

I want to grey out fragment activity on some condition, I am trying to set a flag in pojo class and checking every time i try to grey out an activity.
I do not know where exactly the logic should be placed. I tried to put it inside a onCreateView() method, but it gave me an null pointer exception.
Please find the code below for your reference.
#SuppressLint("ValidFragment")
public class QuizTab extends Fragment {
private static final String TAG = "QuizTab";
RecyclerView recyclerView;
View view;
LinearLayout linearLayout;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.quiztab, container, false);
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
if(flag){
grey out logic ---- not working
}
getQuizContent();
setupRecyclerView(recyclerView);
return view;
}
private void setupRecyclerView(RecyclerView recyclerView) {
recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext()));
recyclerView.setAdapter(new SimpleStringRecyclerViewAdapter(getActivity()));
}
public class SimpleStringRecyclerViewAdapter extends RecyclerView.Adapter<SimpleStringRecyclerViewAdapter.ViewHolder> {
private Context mContext;
public class ViewHolder extends RecyclerView.ViewHolder {
public final LinearLayout mLinearlayout;
public ViewHolder(View view) {
super(view);
mLinearlayout = (LinearLayout) view.findViewById(R.id.mcq);
}
}
public SimpleStringRecyclerViewAdapter(Context context) {
mContext = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.quiztab_mcq, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
}
#Override
public int getItemCount() {
return 1;
}
}
}
LinearLayout in this case is parent of fragment i tryed to paint fragment but failure so i did something like that
if(flag){
LinearLayout layout = view.findViewById(R.id.parentOffragment);
layout.setBackgroundColor(Color.GRAY);
}

Categories

Resources