RecyclerView saving state - android

Anyone have issue that RecyclerView doesn't save scroll position after changing orientation?
mMyAdapter = new MyAdapter(context, MyAdapter.generateKey(this), savedInstanceState);
mMyAdapter.setHasStableIds(true);
mLayoutManager = new LinearLayoutManager(context, VERTICAL, false);
int padding = ResourceUtils.dp2px(context, 8);
mRecycleView.setClipToPadding(false);
mRecycleView.setPadding(0, ResourceUtils.getPixelSize(R.dimen.toolbar_height), 0, padding);
mRecycleView.setOverScrollMode(View.OVER_SCROLL_ALWAYS);
mRecycleView.setLayoutManager(mLayoutManager);
mRecycleView.setAdapter(MyAdapter);
mRecycleView.setHasFixedSize(false);
mRecycleView.setOnScrollListener(mScrollManager); // only to hide Toolbar on scroll
so i'm not modifed onDestroy or OnSaveInstanceState methods, only saving adapters data, so when i'm rotating phone, scroll position of RecyclerView reseting, some advice?

Recently I've improved and created a FlexibleAdapter pattern for all RecyclerView. It is able to maintain the state after rotation.
Very simple to use, just copy 2 classes in your common files + some xml in order to enable the selection (Single/Multi) as it was for ListView.
Please have a look at the description and full working example: https://github.com/davideas/FlexibleAdapter

I understood where i had mistake, i used RecyclerView from
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
//used this instance of recycler view
mRecyclerView = inflater.inflate(R.layout.recycle_fragment, container, false);
return mRecyclerView;
}
but need to
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// instead of searching it after view created
mRecycleView = ButterKnife.findById(getView(), R.id.recycler_view);
}
Problem solved

Related

Empty View in Fragment

I have a question. Currently, I am creating a small Android app with Android Studio. I have two fragments. In fragment 1 I have an overview of tiles. These are passed to the RecyclerView via an adapter. This is all handled in onCreateView.
When clicking on a card, I get to fragment 2 using navigation (NavHostFragment.findNavController(CategoryFragment.this) .navigate(R.id.action_Category_to_Second);) This works.
When I click the back button from fragment 2 (toolbar) to fragment 1, the view remains empty. Why? Or does anyone know a code example where I can rebuild this?
Am I doing something wrong here by overdriving the view?
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.fragment_category, container, false);
categoriesData = new CategoriesService( view.getContext(), this.queue, this.sharedPreferences);
categoriesData.loadData();
CardViewAdapter mAdapter = new CardViewAdapter(view.getContext(), categoriesData.getCategories());
mAdapter.setClickListener(this);
recyclerView = view.findViewById(R.id.categoriesGrid);
recyclerView.setLayoutManager(new GridLayoutManager(view.getContext(), 6));
recyclerView.setAdapter(mAdapter);
view zurückgeben;
}

Which one of these is the best way to access android fragment views?

How are these methods different from each other when trying to get the view?
First:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_a, container, false);
listView = view.findViewById(R.id.listview);
return view;
}
Second:
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
listView = getActivity().findViewById(R.id.listview); }
* some say this is used to get activity views but i used it for getting fragment views(which didn't existed in the activity) and it worked fine.
Third:
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
listView = getView().findViewById(R.id.listview);
}
Three methods are good. In the onCreateView you create the view (!), it's the really first time you can use what you inflated. Then onViewCreated is called with the view you returned in the onCreateView, You can directly use the view given as parameter, it is the same the getView() provides. My advice is to initialise your UI variables here
For onActivityCreated, it is the best place to modify your UI elements. It is called when fragment creation is complete and when fragment is re-attached. There you can use the variables you initialised before, without having to get the activity just for that purpose.

Firebase recyclerView isn't attached to adapter

For some reason my recyclerView doesn't attach to the Firebase RecyclerView adapter. I'm implementing the recyclerView inside a fragment that shows in a tabbed activity. my code (relevant parts):
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = LayoutInflater.from(container.getContext())
.inflate(R.layout.fragment_fresh, container, false);
// Initialize ProgressBar and RecyclerView.
mProgressBar = (ProgressBar)rootView.findViewById(R.id.progressBar);
mSessionRecyclerView = (RecyclerView) rootView.findViewById(R.id.sessionRecyclerView);
mLinearLayoutManager = new LinearLayoutManager(getActivity());
mLinearLayoutManager.setStackFromEnd(true);
mSessionRecyclerView.setLayoutManager(mLinearLayoutManager);
//implement recyclerview
mFirebaseDatabaseReference = FirebaseDatabase.getInstance().getReference();
mFirebaseAdapter = new FirebaseRecyclerAdapter<Session, SessionViewHolder>(
Session.class,
R.layout.item_session,
SessionViewHolder.class,
//change back to SESSIONS_CHILD
mFirebaseDatabaseReference.child("test")) {
#Override
protected void populateViewHolder(final SessionViewHolder viewHolder,
Session session, int position) {
//implementing populateViewHolder..
}
};
mSessionRecyclerView.setLayoutManager(mLinearLayoutManager);
mSessionRecyclerView.setAdapter(mFirebaseAdapter);
return inflater.inflate(R.layout.fragment_fresh, container, false);
}
}
The XML is just a recyclerView and a progressBar.
Worth mentioning that I've gone through this thread.Tried setting recycler's size to wrap_parent, move setAdapter to onCreate, and pretty much every other answer - to no avail.
EDIT: I got this working when inside an activity, but whenever I try from within a fragments I get this error. Also tried with a regular recyclerView and a custom adapter and the same thing happens.
Does the recyclerView attaches itself to an adapter differently in a fragment?
OK, I finally fixed it. The problem was actually in the tabbed activity - the getItem method inside the PlaceHolder fragment created a new instance of PlaceHolder.
Therefore, my fragments hadn't even been created.
None of the threads on the skipping layout advise checking that, hope this helps.

Android, Functions in Adapter never get called

Functions like onCreateViewHolder(), onBindViewHolder(), onAttachedToRecyclerView() never get called. This is what I'm trying to do.
Switch from MainActivity to RecyclerViewActivity when Button1 is clicked, and load fragment_recyclerview into RecyclerViewActivity
switch(id) {
case R.id.aboutMeButton:
getSupportFragmentManager().beginTransaction().replace(R.id.mainContainer, AboutMeFragment.newInstance()).addToBackStack(null).commit();
break;
case R.id.task1Button:
intent = new Intent(this, RecyclerViewActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT );
startActivity(intent);
break;
default:
break;
}
FragmentViewActivity.onCreate()
FragmentViewActivity.onCreate()
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recyclerview);
getSupportFragmentManager().beginTransaction().replace(R.id.recyclerViewContainer, RecyclerViewFragment.newInstance()).commit();
Log.d("AAA", "RecyclerViewActivity.onCreate( )");
}
RecyclerViewFragment.onCreateView():
RecyclerViewFragment.onCreateView(){
final View rootView = inflater.inflate(R.layout.fragment_recyclerview, container, false);
movieData = new MovieData();
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.cardViewContainer);
// Log.d("AAA", "mRecyclerView = " + mRecyclerView.getId());
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
mRecyclerView.setHasFixedSize(true);
// use a linear layout manager
mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
Log.d("AAA", "getActivity() = " + getActivity().toString());
Log.d("AAA", "movieList size = " + movieData.getMoviesList().size());
// specify an adapter (see also next example)
mAdapter = new MovieDataAdapter(getActivity(), movieData.getMoviesList());
mRecyclerView.setAdapter(mAdapter);
return super.onCreateView(inflater, container, savedInstanceState);
}
Adapter.getItemCount() returns 30, however, functions in adapter other than constructor never get called, which leaves me a pure blank
screen. I've no idea what's going on
You are setting your View up in rootView and then, instead of returning that View, you return super.onCreateView():
Instead of the following in onCreateView():
return super.onCreateView(inflater, container, savedInstanceState);
You should return the View you just set up:
return rootView;
first:
don't do any initialization of adapter in Fragment.onCreateView(,,,)
as name says this method should be used to inflate or create view:
so inflate view:
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.recycler_layout, container, false);
}
after u create view use onViewCreated(..) method to initialize and create adapter:
#Override
public void onViewCreated(View view, Bundle savedInstanceState){
// here initialize recycler view
super.onViewCreated(view, savedInstanceState);
}
and as user13 said you need to return inflated view not super created view !!!!*
then u will avoid such problems
second:
depending on fragment/parent component usage (for example you should use different approach when u implement view pager with state or normal adapter, or you retain fragment) sometimes you can or sometimes can't hold reference to inflated view (thus return or not once created view) - but as i sad it's depends what approach do you use

Slow fragment creation

I have a view pager with multiple fragments but, I'm facing some performance problems as the onCreateView of the fragment is really slow. I've seen that the fragment takes some time to create the view, why is this?
In order to solve that I've thought about using a private variable so the view mustn't be recreated each time. The code would be as bellow (as you can see in the code, the content of the fragment is just a recyclerview):
private View iView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if(iView != null) {
return iView;
}
iView = inflater.inflate(R.layout.fr_view, container, false);
rv = (RecyclerView) iView.findViewById(R.id.rv);
rv.setHasFixedSize(true);
final GridLayoutManager iLayoutManager = new GridLayoutManager(getActivity(), MAX_COLUMNS);
rv.setLayoutManager(iLayoutManager);
rv.setAdapter(iAdapter);
rv.setItemAnimator(new DefaultItemAnimator());
return iView;
}
Is that a good solution? Why inflating the view may be taking so time?
Thanks in advance!

Categories

Resources