I am trying uamp sample, whenever orientation changes MediaBrowserFragment recyclerview state is lost(its scroll position is not maintained).
My problem is how to maintain scroll position in uamp sample.
I know I can save scroll position and restore it later but since recyclerView itself maintains scroll state I don't want that hacks.
I tried pushing this simple fragment instead of MediaBrowserFragment and its maintaining its scroll
public class TestFragment extends Fragment {
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View mRootView = inflater.inflate(R.layout.fragment_test, container, false);
RecyclerView recyclerView = (RecyclerView) mRootView.findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setAdapter(new RecAdapter());
return mRootView;
}
private class RecAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_text, null);
return new ItemViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
((ItemViewHolder) holder).title.setText(""+ position);
}
#Override
public int getItemCount() {
return 200;
}
}
private class ItemViewHolder extends RecyclerView.ViewHolder {
TextView title;
ItemViewHolder(View itemLayoutView) {
super(itemLayoutView);
title = (TextView) itemLayoutView.findViewById(R.id.title);
}
}
}
Update
I raised the issue with uamp
https://github.com/googlesamples/android-UniversalMusicPlayer/issues/217
you can just add configChanges in your manifest file as below:
<activity android:name=".YourActivity"
android:configChanges="orientation|screenSize"/>
Related
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);
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();
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);
}
I have a RecyclerView with a GridLayout. My data is a List of ordered objects by date. I need to add a divider if next item has different date that current one. Here is my class:
public class ImageContentFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
recyclerView = (RecyclerView) mainView.findViewById(R.id.rc_recycler_view);
adapter = new ContentAdapter(recyclerView.getContext());
recyclerView.setAdapter(adapter);
recyclerView.setHasFixedSize(true);
int tilePadding = getResources().getDimensionPixelSize(R.dimen.tile_padding);
recyclerView.setPadding(tilePadding, tilePadding, tilePadding, tilePadding);
recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), sPrefs.getInt(GRID_COL_KEY, GRID_SPAN_COUNT)));
return mainView;
}
public class ContentAdapter extends RecyclerView.Adapter<ContentAdapter.MyViewHolder> {
public class MyViewHolder extends RecyclerView.ViewHolder {
public ImageView picture;
public TextView name;
public boolean selected = false;
public MyViewHolder(View view) {
super(view);
picture = (ImageView) itemView.findViewById(R.id.tile_picture);
name = (TextView) itemView.findViewById(R.id.tile_title);
}
}
public ContentAdapter(Context context) {
mUlrPictures = getImageUrlForFolder(mediaStorageDir);
}
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_image, parent, false);
GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams) v.getLayoutParams();
lp.height = sPrefs.getInt(ICON_SIZE_KEY, ITEM_HEIGHT_MEDIUM);
v.setLayoutParams(lp);
return new MyViewHolder(v);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
String imUrl = mUlrPictures.get(position % mUlrPictures.size()).getUrl();
holder.name.setText(mUlrPictures.get(position % mUlrPictures.size()).getUrl());
holder.selected = mUlrPictures.get(position % mUlrPictures.size()).getSelected();
}
}
#Override
public int getItemCount() {
return mUlrPictures.size();
}
}
}
What is the best way to do that? It also would be great to add a TextView with divider.
Add a view in item_image.xml file with height 2dp & width fill_parent, it works as a divider, assign id as well.
onBindViewHolder method write one logic to check the dates based on the position, if true then make it visible the divider view, if not make the divider View.gone
Hope this will help you
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!