Recycler view lost after fragment replacement - android-recyclerview

I have a single activity which replaces a fragment containing a recycler view with a fragment containing details of the selected viewholder item. When the back button is pressed the fragment containing the recycler view is restored but the recycler view items are no longer displayed. However, views are restored upon device rotation. All model data is stored in a SQLite database and the adapter list is updated on resume of its fragment .
CrimeListFragment.Java
public class CrimeListFragment extends Fragment {
private Callbacks callbacks;
public interface Callbacks {
public void onItemSelected(UUID id);
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
callbacks = (Callbacks) context;
}
#Override
public void onDetach() {
super.onDetach();
callbacks = null;
}
private RecyclerView crimeListRecycler;
private CrimeListAdapter adapter;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_crime_list, container, false);
crimeListRecycler = view.findViewById(R.id.crime_list);
crimeListRecycler.setLayoutManager(new LinearLayoutManager(getActivity()));
updateUI();
return view;
}
#Override
public void onResume() {
super.onResume();
updateUI();
}
#Override
public void onCreateOptionsMenu(#NonNull Menu menu, #NonNull MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.fragment_crime_list, menu);
MenuItem showSubtitle = menu.findItem(R.id.show_subtitle);
}
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.new_crime:
Crime crime = new Crime();
CrimeLab.get(getActivity()).addCrime(crime);
/*Intent intent = CrimeActivity.createIntent(getActivity(), crime.getId());
startActivity(intent);*/
callbacks.onItemSelected(crime.getId());
return true;
default:
return onOptionsItemSelected(item);
}
}
private void updateUI() {
List<Crime> crimes = CrimeLab.get(getActivity()).getCrimes();
if (adapter == null) {
adapter = new CrimeListAdapter(crimes);
crimeListRecycler.setAdapter(adapter);
} else {
adapter.setCrimesList(crimes);
adapter.notifyDataSetChanged();
}
}
public class CrimeListAdapter extends RecyclerView.Adapter<CrimeListAdapter.CrimeHolder> {
private List<Crime> crimeList;
public CrimeListAdapter(List<Crime> crimes) {
crimeList = crimes;
}
#NonNull
#Override
public CrimeHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(getActivity()).inflate(R.layout.list_item_crime, parent, false);
return new CrimeHolder(view);
}
#Override
public void onBindViewHolder(#NonNull CrimeHolder holder, int position) {
Crime crime = crimeList.get(position);
holder.bind(crime);
}
#Override
public int getItemCount() {
return crimeList.size();
}
public void setCrimesList(List<Crime> crimes) {
crimeList = crimes;
}
public class CrimeHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private Crime crime;
private TextView crimeTitleTextView;
private TextView crimeDateTextView;
public CrimeHolder(#NonNull View itemView) {
super(itemView);
crimeTitleTextView = itemView.findViewById(R.id.crime_title);
crimeDateTextView = itemView.findViewById(R.id.crime_date);
itemView.setOnClickListener(this);
}
public void bind(Crime crime) {
this.crime = crime;
crimeTitleTextView.setText(crime.getTitle());
crimeDateTextView.setText(crime.getDate().toString());
}
#Override
public void onClick(View v) {
callbacks.onItemSelected(crime.getId());
/*Intent intent = CrimeActivity.createIntent(getActivity(), crime.getId());
startActivity(intent);*/
}
}
}
}
MasterActivity
public class MasterActivity extends AppCompatActivity implements CrimeListFragment.Callbacks {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment);
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragment_container);
if (fragment == null) {
fragment = new CrimeListFragment();
fm.beginTransaction()
.add(R.id.fragment_container, fragment)
.commit();
}
}
#Override
public void onItemSelected(UUID id) {
Fragment fragment = CrimeFragment.newInstance(id);
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction()
.replace(R.id.fragment_container, fragment)
.addToBackStack(null)
.commit();
}
}

Please share your code. Something to check when you replace/add your fragment on top of recyclerview fragment.

Related

paging library not showing anything in recyclerview

i'm trying to load bunch of list from room database, with paging library, but somehow that i don't really understand, the list never shown up
i add a repository class between dao and viewmodel, not sure if its the problem but, i configure Paged.list and pagedlistbuilder in there
i've also try to put some breakpoint in pagedListAdapter, but it never called
DAO
#Query("SELECT * FROM DictIndonesia")
public abstract DataSource.Factory<Integer, DictIndonesia> getAllPaged();
REPOSITORY
public class DictRepository {
PagedList.Config pagedListConfid;
.....
public DictRepository(Application application) {
db = DictIndoDatabase.getINSTANCE(application);
indDao = db.dictIdDao();
.....
pagedListConfid = (new PagedList.Config.Builder()
.setEnablePlaceholders(true)
.setPrefetchDistance(10)
.setPageSize(20).build());
}
......
public LiveData<PagedList<DictIndonesia>> getAllWordPaged() {
return new LivePagedListBuilder<>(
indDao.getAllPaged(), pagedListConfid).build();
}
viewmodel
public LiveData<PagedList<DictIndonesia>> getAllWordPaged() {
return dictRepository.getAllWordPaged();
}
ADAPTER
public class WordIndAdapterPaged extends PagedListAdapter<DictIndonesia,WordIndAdapterPaged.WordHolder> {
public WordIndAdapterPaged() {
super(diffcallBack);
}
#NonNull
#Override
public WordHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler, parent, false);
return new WordHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull WordHolder holder, int position) {
holder.bindTo(getItem(position));
}
private static final DiffUtil.ItemCallback<DictIndonesia> diffcallBack = new DiffUtil.ItemCallback<DictIndonesia>() {
#Override
public boolean areItemsTheSame(#NonNull DictIndonesia oldItem, #NonNull DictIndonesia newItem) {
return oldItem.getIdIndo() == newItem.getIdIndo();
}
#Override
public boolean areContentsTheSame(DictIndonesia oldItem, #NonNull DictIndonesia newItem) {
return oldItem == newItem;
}
};
public class WordHolder extends RecyclerView.ViewHolder {
...............
WordHolder(View view) {
super(view);
...............
}
void bindTo(DictIndonesia dictIndonesia) {
word.setText(Html.fromHtml(dictIndonesia.getWord()));
meaning.setText(Html.fromHtml(dictIndonesia.getMeaning()));
}
}
Fragment
public class Fdashboard extends Fragment {
#BindView(R.id.rv_global)
RecyclerView rvGlobal;
private Unbinder unbinder;
WordIndAdapterPaged wordIndAdapterPaged;
private WordViewModel wordViewModel;
public Fdashboard() { }
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_fdashboard, container, false);
unbinder = ButterKnife.bind(this, v);
wordViewModel = ViewModelProviders.of(getActivity()).get(WordViewModel.class);
wordIndAdapterPaged = new WordIndAdapterPaged();
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity());
rvGlobal.setLayoutManager(layoutManager);
rvGlobal.setAdapter(wordIndAdapterPaged);
wordViewModel.getAllWordPaged().observe(this, dictIndonesias -> {
wordIndAdapterPaged.submitList(dictIndonesias); //i think the problem maybe around here
});
return v;
}

change background of all textviews in recyclerview from activity and not from adapter

I have a recyclerview with a textview and the clicked textview gets a background around it.I also have a button within the activity which should put a background to all the items in the recyclerview ie..to show all selected.I am putting my activity and adapter code.please help me
my activity code
set_all_days.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
CommonUtility.selectedDays.clear();
CommonUtility.selectedDays.addAll(daysList);
//loadDays();
}
});
my adapter
public class DaysAdapter<T> extends RecyclerView.Adapter<DaysAdapter.ViewHolder> {
private ArrayList<String> list=new ArrayList<>();
private Context mContext;
private RecyclerViewClickListener mListener;
public DaysAdapter(ArrayList<String> data, Context context, RecyclerViewClickListener listener) {
list = data;
//languageListFiltered = filteredData;
mContext = context;
mListener = listener;
}
#Override
public void onBindViewHolder(DaysAdapter.ViewHolder viewHolder, final int position) {
viewHolder.titleTextView.setText(list.get(position));
// viewHolder.lang_radio.setChecked(position == mSelectedItem);
}
#Override
public int getItemCount() {
return list.size();
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
LayoutInflater inflater = LayoutInflater.from(mContext);
final View view = inflater.inflate(R.layout.days_list_item, viewGroup, false);
return new ViewHolder(view);
}
class ViewHolder extends RecyclerView.ViewHolder {
public TextView titleTextView;
public ViewHolder(final View inflate) {
super(inflate);
titleTextView = (TextView)inflate.findViewById(R.id.text_day);
View.OnClickListener clickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
if(!CommonUtility.selectedDays.contains(titleTextView.getText().toString()))
{
titleTextView.setBackground(mContext.getResources().getDrawable(R.drawable.green_circle));
titleTextView.setTextColor(mContext.getResources().getColor(R.color.white));
CommonUtility.selectedDays.add(titleTextView.getText().toString());
Log.d("added",titleTextView.getText().toString());
}
else
{
int index=CommonUtility.selectedDays.indexOf(titleTextView.getText().toString());
CommonUtility.selectedDays.remove(index);
titleTextView.setBackground(null);
Log.d("removed",titleTextView.getText().toString());
titleTextView.setTextColor(mContext.getResources().getColor(R.color.black));
}
}
};
itemView.setOnClickListener(clickListener);
titleTextView.setOnClickListener(clickListener);
}
}
}

How to play the song when an item is clicked in recyclerView (no buttons)?

I am creating a music app and I have listed my songs in RecyclerView. What I want is when I click any song(inside the red marked area), the song should play, just like in modern music players. I don't want any play, stop buttons on my RecyclerView. Any help would be appreciated! Thanks in advance!
Songs.java
public class Songs extends Fragment {
private static final String TAG = "Songs";
RecyclerView recyclerView;
private ArrayList<SongInfoModel> SongList = new ArrayList<SongInfoModel>();
SongAdapter songAdapter;
SongInfoModel s;
private MediaPlayer mediaPlayer;
ScaleInAnimationAdapter alphaAdapter;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.songs_activity, container, false);
recyclerView = (RecyclerView)view.findViewById(R.id.recyclerView);
mediaPlayer = new MediaPlayer();
LinearLayoutManager linearLayoutManager = new
LinearLayoutManager(getContext());
recyclerView.setLayoutManager(linearLayoutManager);
SongInfoModel s= new SongInfoModel("Cheap Thrills","Sia",null, null,
"http://mp3fb.com/wp-includes/inc/down.php?
id=hyCQomZzosfGBvVON0tRV7xfiL2GdtKXbTsBrZh_3NM&t=Sia%2B-
%2BCheap%2BThrils%2B%D0%A0%D0%B5%D0%BC%D0%B8%D0%BA%D1%81.mp3
&hash=true",null,null);
SongList.add(s);
songAdapter = new SongAdapter(getContext(),SongList);
alphaAdapter = new ScaleInAnimationAdapter(songAdapter);
alphaAdapter.setDuration(1000);
alphaAdapter.setInterpolator(new OvershootInterpolator());
alphaAdapter.setFirstOnly(false);
recyclerView.setAdapter(alphaAdapter);
Collections.sort(SongList, new Comparator<SongInfoModel>(){
public int compare(SongInfoModel a, SongInfoModel b){
return a.getSongName().compareTo(b.getSongName());
}
});
return view;
}
SongAdapter.java:
public class SongAdapter extends
RecyclerView.Adapter<SongAdapter.SongHolder>
{
ArrayList<SongInfoModel> SongList = new ArrayList<>();
Context context;
MediaPlayer mediaPlayer;
SongInfoModel obj;
public SongAdapter(Context context, ArrayList<SongInfoModel> SongList) {
this.context = context;
this.SongList = SongList;
}
#Override
public SongAdapter.SongHolder onCreateViewHolder(ViewGroup parent, int
viewType)
{
View view = LayoutInflater.from(context).inflate(R.layout.row_song,
parent, false);
return new SongHolder(view);
}
#Override
public void onBindViewHolder(final SongAdapter.SongHolder holder, final
int
position) {
final SongInfoModel songInfoModel = SongList.get(position);
holder.songName.setText(songInfoModel.SongName);
holder.artistName.setText(songInfoModel.ArtistName);
}
#Override
public int getItemCount() {
return SongList.size();
}
public class SongHolder extends RecyclerView.ViewHolder {
TextView songName;
TextView artistName;
TextView duration;
public SongHolder(View itemView) {
super(itemView);
songName = (TextView)itemView.findViewById(R.id.SongName);
artistName= (TextView)itemView.findViewById(R.id.ArtistName);
duration = itemView.findViewById(R.id.duration);
}
}
}
First, Create an Interface in Adapter class like this -
private CustomOnClickListener customOnClickListener;
public interface CustomOnClickListener{
void onClick(int position);
}
After that Implement View.OnClickListener in View holder class
class TracksViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
public TracksViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
customOnClickListener.onClick(getAdapterPosition());
}
After that Implement CustomOnClickListener in your Fragment or Activity class.

Restore scroll position

I have a simple fragment which retrieve data from Firebase database.
I use firebase recycler view to display retrieving data. And after scrolling or screen rotation I can't force recycler view (or linear layout manager) restore scroll position.
I found here some answers but they don't work.
My code is:
public class NewsListFragment extends ParentNewsFragment {
static int color_naval, color_black;
private boolean mProcessLikes = false;
private DatabaseReference mDatabaseLikes;
private DatabaseReference mDatabaseViews;
private FirebaseAuth mAuth;
private int position = 0;
public static NewsListFragment getInstance() {
return new NewsListFragment();
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDatabaseReference = FirebaseDatabase.getInstance().getReference()
.child("App_news");
mDatabaseLikes = FirebaseDatabase.getInstance().getReference().child("news_likes");
mDatabaseViews = FirebaseDatabase.getInstance().getReference().child("news_views");
mAuth = FirebaseAuth.getInstance();
mQuery = mDatabaseReference.orderByChild("pos").startAt("100");
color_naval = getResources().getColor(R.color.colorPrimary);
color_black = getResources().getColor(R.color.colorBlack);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.rv_choose, container, false);
rv = (RecyclerView) rootView.findViewById(R.id.rv_choose);
lm = new LinearLayoutManager(getActivity());
rv.setLayoutManager(lm);
rv.setHasFixedSize(true);
return rootView;
}
#Override
public void onPause() {
super.onPause();
position = lm.findFirstVisibleItemPosition();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("position", position);
}
#Override
public void onViewStateRestored(#Nullable Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
if(savedInstanceState != null) {
position = savedInstanceState.getInt("position");
}
}
#Override
public void onResume() {
super.onResume();
if (position != 0) {
lm.scrollToPosition(position);
showToast(position+"");
}
}
#Override
public void onStart() {
super.onStart();
FirebaseRecyclerAdapter<NewsList, NewsListViewHolder> adapter =
new FirebaseRecyclerAdapter<NewsList, NewsListViewHolder>(
NewsList.class,
R.layout.frag_newslist_card_view,
NewsListViewHolder.class,
mQuery
) {
#Override
protected void populateViewHolder(NewsListViewHolder viewHolder, final NewsList model, int position) {
final String post_key = getRef(position).getKey();
viewHolder.setDate(model.getDate()+",");
viewHolder.setTime(model.getTime());
viewHolder.setTitle(model.getTitle());
viewHolder.setImage(getContext(), model.getImage());
viewHolder.setEye(model.getCode());
viewHolder.setThumb(post_key);
viewHolder.thumb.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mProcessLikes = true;
mDatabaseLikes.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (mProcessLikes){
if (dataSnapshot.child(post_key).hasChild(mAuth.getCurrentUser().getUid())){
mDatabaseLikes.child(post_key).child(mAuth.getCurrentUser().getUid())
.removeValue();
mProcessLikes = false;
}
else {
mDatabaseLikes.child(post_key).child(mAuth.getCurrentUser().getUid())
.setValue("like");
mProcessLikes = false;
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});
viewHolder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mDatabaseViews.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (!dataSnapshot.child(post_key).hasChild(mAuth.getCurrentUser().getUid())) {
mDatabaseViews.child(post_key).child(mAuth.getCurrentUser().getUid())
.setValue("view");
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
mChooserListener.chooseNews(model.getCode());
}
});
}
};
rv.setAdapter(adapter);
}
public static class NewsListViewHolder extends RecyclerView.ViewHolder {
//some text here
}
}
method showToast in the end shows real number of position but recyclerview starts from the beginning.
any ideas?
Make sure you are not reloading data from the server or wherever you are retrieving data.
Add is not null check in your fragment's onCreateView or activity's onCreate like:
if(savedInstanceState != null){
...
}else{
loadData();
}
Replace your linear layout manager with something similar to the following. I have used this implementation many times when using RecyclerView in fragments. Let me know how it goes
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
mLayoutManager.setReverseLayout(true);
mLayoutManager.setStackFromEnd(true);
yourItem.setLayoutManager(mLayoutManager);

android only show first viewpager inside recyclerview

i have a viewpager with FragmentStatePagerAdapter inside recyclerview
and its show only the first row in recyclerview
please help me
viewpager adapter:
public class CustomPagerAdapter extends FragmentStatePagerAdapter {
private static int NUM_ITEMS = 3;
public CustomPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
Log.e("fragmentManager",fragmentManager.toString());
}
// Returns total number of pages
#Override
public int getCount() {
return NUM_ITEMS;
}
// Returns the fragment to display for that page
#Override
public Fragment getItem(int position) {
Fragment currentFragment;
switch (position) {
case 0:
currentFragment=new FirstFragment();
break;
case 1:
currentFragment=new SecondFragment();
break;
case 2:
currentFragment=new ThirdFragment();
break;
default:
currentFragment=new FirstFragment();
break;
}
return currentFragment;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
recyclerview adapter:
public class JobAdapter extends RecyclerView.Adapter<JobAdapter.JobHolder> {
private Context context;
private List<String> mJobList = new ArrayList<>();
public JobAdapter(List<String> mJobList,Context context) {
this.mJobList = mJobList;
this.context=context;
}
#Override
public JobHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(context);
View view = layoutInflater.inflate(R.layout.find_job_line_content, parent, false);
return new JobHolder(view);
}
#Override
public void onBindViewHolder(final JobHolder holder, int position) {
configurePagerHolder(holder, position);
}
private void configurePagerHolder(JobHolder holder, int position) {
//Job job= mJobList.get(position);
CustomPagerAdapter adapter = new CustomPagerAdapter(((MainActivity)context).getSupportFragmentManager());
holder.viewPager.setAdapter(adapter);
adapter.notifyDataSetChanged();
holder.viewPager.setCurrentItem(1);
Log.e("configurePagerHolder",position+"");
}
public int getItemCount() {``
return mJobList.size();
}
public class JobHolder extends RecyclerView.ViewHolder{
ViewPager viewPager;
public JobHolder(View itemView) {
super(itemView);
viewPager=(ViewPager)itemView.findViewById(R.id.slidesPager);
}
}
main:
public class MainActivity extends AppCompatActivity {
RecyclerView mRecyclerView;
JobAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView)findViewById(R.id.find_jobs_recyclerview);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this,
LinearLayoutManager.VERTICAL,false));
mRecyclerView.setHasFixedSize(true);
List<String> list=new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
adapter = new JobAdapter(list,this);
mRecyclerView.setAdapter(adapter);
}
}
Very late answer but it might help some people...
Try using ViewPager2 ( an improved version of ViewPager) : https://developer.android.com/training/animation/screen-slide-2
In my case it solved the problem.