RecylerView Adapter causing memory leak when using on Click interface - java

In my RecyclerView.Adapter I have defined this interface:
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
The Fragment which contains the RecyclerView implements this interface.
After 4 or 5 orientation changes LeakCanary reports a memory leak:
My Fragment looks like this:
public class ImagesFragment extends Fragment implements ImageAdapter.OnItemClickListener {
private static final String IMAGES_FRAGMENT_TAG = "ImagesFragment";
private int SPAN_COUNT = 2;
private String categoryName;
private String categoryURL;
private int ImageCount;
protected RecyclerView mRecyclerView;
protected RecyclerView.LayoutManager mLayoutManager;
protected static ImageAdapter mAdapter;
#Override
public void onItemClick(View view, int position) {
Toast.makeText(mContext, "Clicked:" + String.valueOf(position), Toast.LENGTH_SHORT).show();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
this.categoryName = args.getString("category");
this.categoryURL = args.getString("URL");
this.ImageCount = args.getInt("Count");
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.images_recycler_view, container, false);
rootView.setTag(IMAGES_FRAGMENT_TAG);
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.imagesRecyclerView);
mRecyclerView.addItemDecoration(new CategoryItemDecoration(px, SPAN_COUNT, mCurrentLayoutType));
mLayoutManager = new GridLayoutManager(getActivity().getApplicationContext(), SPAN_COUNT);
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new ImageAdapter(categoryURL, this.ImageCount, this);
mRecyclerView.setAdapter(mAdapter);
return rootView;
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putString(IMAGES_FRAGMENT_TAG, IMAGES_FRAGMENT_TAG);
super.onSaveInstanceState(outState);
}
#Override
public void onDestroyView() {
super.onDestroyView();
System.out.println("OnDestroyView");
if (mRecyclerView != null) {
mRecyclerView.setAdapter(null);
}
}
#Override
public void onDestroy() {
super.onDestroy();
RefWatcher refWatcher = MyApplication.getRefWatcher(getActivity());
refWatcher.watch(this);
}
}
My Adapter:
public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ImagesViewHolder> {
private static final String IMAGES_FRAGMENT_TAG = "ImagesFragment";
private Context mContext;
private static OnItemClickListener onItemClickListener;
private Integer imageCount;
public ImageAdapter(String url, Integer imageCount, OnItemClickListener itemListener) {
this.ROOTURL = url;
this.imageCount = imageCount;
this.onItemClickListener = itemListener;
}
#Override
public int getItemCount() {
return imageCount;
}
#Override
public ImagesViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
this.mContext = parent.getContext();
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.images_viewitem, parent, false);
ImagesViewHolder imagesViewHolder = new ImagesViewHolder(v);
return imagesViewHolder;
}
#Override
public void onBindViewHolder(final ImagesViewHolder holder, int position) {
Glide.with(mContext)
.load("URL")
.asBitmap()
.centerCrop()
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(new BitmapImageViewTarget(holder.image) {
#Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
super.onLoadFailed(e, errorDrawable);
Log.e(IMAGES_FRAGMENT_TAG, "on load failed");
}
#Override
public void onResourceReady(Bitmap bitmap, GlideAnimation<? super Bitmap> glideAnimation) {
super.onResourceReady(bitmap, glideAnimation);
holder.image.setImageBitmap(bitmap);
}
});
}
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
public static class ImagesViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private static final int PALETTE_SIZE = 24;
CardView cv;
ImageView image;
RelativeLayout mImageViewWrapper;
ImagesViewHolder(View itemView) {
super(itemView);
cv = (CardView) itemView.findViewById(R.id.imagesCardView);
image = (ImageView) itemView.findViewById(R.id.images_ImageView);
mImageViewWrapper = (RelativeLayout) itemView.findViewById(R.id.Images_imageViewWrapper);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
onItemClickListener.onItemClick(v, this.getLayoutPosition());
}
}
}

Your problem is this line in your Fragment:
protected static ImageAdapter mAdapter;
And this line in your Adapter:
private static OnItemClickListener onItemClickListener;
NEVER use static for variables. Just don't do it unless you really know what you are doing. The static keyword causes your ImageAdapter and OnClickListener to stick around after the Fragment is garbage collected. It means that the variable mAdapter is not part of any instance of your Fragment but instead part of the class itself - which of course is an instant memory leak! Remove those and you should be fine.
And by the way you could have figured this out by yourself fairly quickly. Look again at the LeakCanary output:
It says that the static variable onItemClickListener in the ImageAdapter leaks an ImagesFragment instance - or in other words exactly what I am telling you in this answer.
Also you should read this answer to learn more about memory leaks.

Related

Get different data via Retrofit for the Fragment in FragmentPagerAdapter for the several tablayout tabs

Conditions:
I have an Activity and I'm creating PagerAdapter extends FragmentPagerAdapter with one Fragment class. TabLayout includes 10 tabs. I have TabLayout.addOnTabSelectedListener and there in onTabSelected() I am updating some custom variable in app's SharedPreferences which depends on current tab name and tab index. Tab's names are not static - there are loading from server too.
My task:
With this value I should make a retrofit2 Call to my server and load values in adapter with recyclerview for my Fragment.
My problem:
I am loading the same data for the different tabs, which should contatin different data! I am understand that this happens because in all cases I have the same SharedPreferences variable's value so I am making retrofit Call with same conditions.
setOffscreenPageLimit() can't be setted to 0 - default is 1 according documentation:
https://developer.android.com/reference/kotlin/androidx/viewpager/widget/ViewPager#setoffscreenpagelimit;
setUserVisibleHint() on SO I've found this like some variant for solving my problem, but it can't be overrided because is deprecated now.
Solution:
I think I should save previous and next tab name in some way and then I can make different parallel retrofit Calls with different conditions. When tab selected I can get current, previous and next tab name. But how, where and when I should make two more retrofit calls?
UPD 08.02.2022: Still thinking about this problem.
Code:
SomeActivity.java
public class SomeActivity extends BaseActivity {
private String TAG="SomeActivity";
private Context context;
private TabLayout tabs;
private ViewPager viewpager;
private ProgressBar PBLoading;
private PagerAdapter_SomePAdapter adapter;
List<String> names = new ArrayList<>();
private String[] tabTitles;
public String previousTabName;
public String nextTabName;
public int counterForPreviousTabName;
public int counterForNextTabName;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
context = getApplicationContext();
String categories = AppPreferences.getCategories(context);
tabTitles = categories.split(";");
tabs = findViewById(R.id.tabs);
viewpager = findViewById(R.id.viewpager);
PBLoading = findViewById(R.id.PBLoading);
tabs.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
#Override
public void onTabSelected(TabLayout.Tab tab) {
Log.d(TAG, "onTabSelected");
AppPreferences.setCurrentValueForRetrofit(getApplicationContext(), tab.getPosition());
counterForPreviousTabName = tmpTab.getPosition() - 1;
counterForNextTabName = tmpTab.getPosition() + 1;
//here I can get tab names.
}
});
adapter = new PagerAdapter_SomePAdapter(getSupportFragmentManager(), SomeActivity.this);
viewpager.setAdapter(adapter);
adapter.updateTitleData(tabTitles);
tabs.setupWithViewPager(viewpager);
adapter.notifyDataSetChanged();
}
}
PagerAdapter_SomePAdapter.java:
public class PagerAdapter_SomePAdapter extends FragmentPagerAdapter {
int PAGE_COUNT = 2;
private String[] tabTitles = new String[] { "", ""};
private Context mContext;
Fragment_fragment fragment_fragment;
String TAG = "PagerAdapter_SomePAdapter";
public PagerAdapter_SomePAdapter(FragmentManager fm, Context context) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
mContext = context;
fragment_fragment = new Fragment_fragment();
}
#Override public int getCount() {
return PAGE_COUNT;
}
#Override public Fragment getItem(int position) {
return fragment_fragment.newInstance(position + 1, tabTitles[position]);
}
#Override public CharSequence getPageTitle(int position) {
return tabTitles[position];
}
public void updateTitleData(String[] tabTitlesNew) {
tabTitles = tabTitlesNew;
PAGE_COUNT = tabTitlesNew.length;
notifyDataSetChanged();
}
}
Fragment_fragment.java:
public class Fragment_fragment extends Fragment {
private String TAG = "Fragment_fragment";
private static final String ARG_PAGE = "ARG_PAGE";
private int mPage;
private View rootView;
private RecyclerView RV;
private Adapter_Items adapter;
public static Fragment_fragment newInstance(int page, String tabName) {
Bundle args = new Bundle();
args.putInt(ARG_PAGE, page);
Fragment_fragment fragment = new Fragment_fragment();
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mPage = getArguments().getInt(ARG_PAGE);
}
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
mContext=context;
}
#SuppressLint("ClickableViewAccessibility")
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.content_list, container, false);
RV = rootView.findViewById(R.id.recycler_view);
new loadDataAS().execute();
return rootView;
}
private void loadData(){
//retrofit call code;
}
class loadDataAS extends AsyncTask<Void, Void, Void> {
final ProgressDialog progress = new ProgressDialog(mContext);
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... arg0) {
loadData();
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
adapter = new Adapter_Items(arguments, arguments2, arguments3);
RV.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}
}
Adapter_Items:
public class Adapter_Items extends RecyclerView.Adapter<Adapter_Items.ViewHolder>{
private LayoutInflater mInflater;
private Context mContext;
private static String TAG = "Adapter_Items";
public Adapter_Items(List<Integer>arguments, List<String>arguments2, List<String>arguments3){
//initializing arguments
}
// inflates the row layout from xml when needed
#NotNull
#Override
public ViewHolder onCreateViewHolder(#NotNull ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.recycle_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
//setting view's information
}
#Override
public int getItemCount() {
return arguments.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
}
}
}
First thing,
fragment should contain different data
Saving tab name after tab selected will not work. You should remove this
AppPreferences.setCurrentValueForRetrofit(getApplicationContext(),
tab.getPosition());
You should call retrofit code inside the fragment with the tabName (Not from sharedPref) to get data for that tab.
For this, make the following changes,
You are already passing the tabName to fragment instance
newInstance(int page, String tabName)
use that tabName and pass to your AsyncTask -> loadData() as
loadData(tabName);
Then you can use that in your retrofit call and get the data.
Note:
setOffscreenPageLimit()
This method will load fragments just before they are completely visible. It would be useful and a great user experience to display data directly rather than fetching only when user selects the tab.

Handling onClicks of RecyclerView inside a Fragment

I am trying to implement RecyclerView inside a Fragment. I have designed a CustomAdapter(StateAdapter) class to load the contents of RecyclerView and an interface StateAdapterOnClickHandler to handle onClicks of the items inside RecyclerView but clicking on item doesn't work.
Here's my HomeFragment.java which extends Fragment. I am unable to figure out how to initialize the StateAdapterOnClickHandler and where to call its method onItemClick()
public class HomeFragment extends Fragment implements StateAdapter.StateAdapterOnClickHandler {
private View homeFragment;
private RecyclerView recyclerView;
private StateAdapter stateAdapter;
private List<String> states;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public static HomeFragment newInstance() {
HomeFragment homeFragment = new HomeFragment();
return homeFragment;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
homeFragment = inflater.inflate(R.layout.fragment_home,container,false);
recyclerView = homeFragment.findViewById(R.id.recyclerview_states);
states = Arrays.asList(getResources().getStringArray(R.array.india_states));
LinearLayoutManager layoutManager = new LinearLayoutManager(container.getContext(),LinearLayoutManager.VERTICAL,false);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
stateAdapter = new StateAdapter();
stateAdapter.setStateNames(states);
recyclerView.setAdapter(stateAdapter);
return homeFragment;
}
#Override
public void onItemClick(String state) {
Intent intent = new Intent(getActivity(),DetailActivity.class);
intent.putExtra("State",state);
startActivity(intent);
}
}
Here's my StateAdapter class
public class StateAdapter extends RecyclerView.Adapter<StateAdapter.StateViewHolder> {
private List<String> stateNames;
private final StateAdapterOnClickHandler stateAdapterOnClickHandler;
StateAdapter(StateAdapterOnClickHandler stateAdapterOnClickHandler){
this.stateAdapterOnClickHandler = stateAdapterOnClickHandler;
}
public interface StateAdapterOnClickHandler {
void onItemClick(String state);
}
#Override
public StateAdapter.StateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
int idForListItem = R.layout.state_layout;
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(idForListItem,parent,false);
return new StateViewHolder(view);
}
#Override
public void onBindViewHolder(StateAdapter.StateViewHolder holder, int position) {
String stateName = stateNames.get(position);
holder.mTextView.setText(stateName);
}
#Override
public int getItemCount() {
if(stateNames == null) return 0;
return stateNames.size();
}
public class StateViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public final TextView mTextView;
public StateViewHolder(View itemView) {
super(itemView);
mTextView = (TextView) itemView.findViewById(R.id.tv_state_name);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
int clickedPostion = getAdapterPosition();
String state = stateNames.get(clickedPostion);
stateAdapterOnClickHandler.onItemClick(state);
}
}
public void setStateNames(List<String> states) {
stateNames = states;
notifyDataSetChanged();
}
}
Please, tell me what's wrong with the code while handling the clicks. I am new to Android Programming and this is first time I am working with Fragments. Thanks for helping.

How to start fragment from PagerAdapter

I want to start Fragment in my custom pager adapter. However, I do not know how to get the getSupportFragmentManager() to begin the transaction.
Thank you very much for your time and assistance in this matter.
This is my code, custom adapter for Pager:
public static class SlideShowAdapter extends PagerAdapter {
private ArrayList<Movie> popularMovieList;
private LayoutInflater inflater;
private Context context;
public SlideShowAdapter(Context context, ArrayList<Movie> popularMovieList) {
this.context = context;
this.popularMovieList =popularMovieList;
inflater = LayoutInflater.from(context);
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public int getCount()
{
return popularMovieList.size();
}
#Override
public Object instantiateItem(ViewGroup view, final int position) {
View myImageLayout = inflater.inflate(R.layout.slide, view, false);
ImageView myImage = (ImageView) myImageLayout
.findViewById(R.id.slideShowImg);
Picasso.with(context).load(popularMovieList.get(position).getImage()).into(myImage);
view.addView(myImageLayout, 0);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
MovieFragment movieFragment = MovieFragment
.newInstance(popularMovieList.get(position),popularMovieList.get(position).getGenre());
/***These code below does not work*/
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.fragArea,movieFragment)
.addToBackStack(null)
.commit();
}
});
return myImageLayout;
}
If you want to use FragmentManager in SlideShowAdapter:
One approach is to pass its instance to SlideShowAdapter constructor
Another one is to pass your Activity as FragmentActivity or AppCompatActivity (Activity class does not have getSupportFragmentManager() method) to its constructor and then do myActivity.getSupportFragmentManager().
I got the solution based on #Amin Mousavi suggestion.
public static class SlideShowAdapter extends PagerAdapter {
private ArrayList<Movie> popularMovieList;
private LayoutInflater inflater;
private FragmentActivity context;
public SlideShowAdapter(FragmentActivity context, ArrayList<Movie> popularMovieList) {
this.context = context;
this.popularMovieList =popularMovieList;
inflater = LayoutInflater.from(context);
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public int getCount()
{
return popularMovieList.size();
}
#Override
public Object instantiateItem(ViewGroup view, final int position) {
View myImageLayout = inflater.inflate(R.layout.slide, view, false);
ImageView myImage = (ImageView) myImageLayout
.findViewById(R.id.slideShowImg);
Picasso.with(context).load(popularMovieList.get(position).getImage()).into(myImage);
view.addView(myImageLayout, 0);
myImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
MovieFragment movieFragment = MovieFragment
.newInstance(popularMovieList.get(position),popularMovieList.get(position).getGenre());
/***These code below does not work*/
context.getSupportFragmentManager().beginTransaction()
.replace(R.id.fragArea,movieFragment)
.addToBackStack(null)
.commit();
}
});
return myImageLayout;
}

Set onclicklistener in recyclerview

My adaptor class:
public class Adaptor extends RecyclerView.Adapter<Adaptor.Holder>{
private ArrayList<Winkel> winkels;
private LayoutInflater inflater;
private ImageView icon;
private ItemCLickCallback itemCLickCallback;
public interface ItemCLickCallback {
void onItemClick(int p);
void onSecItemClick(int p);
}
public void setItemCLickCallback(final ItemCLickCallback itemCLickCallback1){
;this.itemCLickCallback = itemCLickCallback;
}
public Adaptor (ArrayList<Winkel> winkels,Context c){
this.inflater = LayoutInflater.from(c);
this.winkels = winkels;
}
#Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.list_item,parent,false);
return new Holder(view);
}
#Override
public void onBindViewHolder(Holder holder, int position) {
Winkel winkel = winkels.get(position);
holder.title.setText(winkel.getNaam());
if (winkel.isFavourtite()){
holder.icon.setImageResource(R.drawable.ic_star_black_18dp);
}
else{
holder.icon.setImageResource(R.drawable.ic_star_border_black_18dp);
}
}
#Override
public int getItemCount() {
return winkels.size();
}
class Holder extends RecyclerView.ViewHolder implements View.OnClickListener{
private TextView title;
private View container;
private ImageView icon;
public Holder(View itemView) {
super(itemView);
title = (TextView)itemView.findViewById(R.id.lbl_item_text);
container = itemView.findViewById(R.id.cont_item_root);
icon = (ImageView) itemView.findViewById(R.id.im_item_icon_secondary);
icon.setOnClickListener(this);
container.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(v.getId()==R.id.cont_item_root){
itemCLickCallback.onItemClick(getAdapterPosition());
}
else{
itemCLickCallback.onSecItemClick(getAdapterPosition());
}
}
}
}
#Override
public void onClick(View v) {
}
}
}
Code where it gets implemented (my issue is here at adaptor.setItemClickCallback(context)
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Adaptor adaptor = new Adaptor(winkels,context);
recyclerview.setLayoutManager(new LinearLayoutManager(context));
recyclerview.addItemDecoration(new VerticalSpace(30));
recyclerview.setAdapter(adaptor);
adaptor.setItemCLickCallback(context);
}
Called from fragment overview:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_overview, container, false);
mRecyclerView = (RecyclerView) view.findViewById(R.id.recycle);
ODKortrijkWebservice webs = new ODKortrijkWebservice(this.getActivity(),mRecyclerView);
webs.execute();
return view;
}
How do I set the context for ItemCLickCallback(this)? It should be context (at least I think so?) because that's what gets passed from the fragment but I can't seem to figure out how to get this to work, so some help would be appreciated. Basically I want to add onclicklisteners for every item in my recyclerview, and the recyclerview is created by using data from a webservice, hence why the adaptor class is called from the class where I get the data from the web service, which gets excecuted in my fragment. Thank you.
I recommend you to make ODKortrijkWebservice.Callback like following.
In your ODKortrijkWebservice:
public class ODKortrijkWebservice extends AsyncTask<...> {
private Callback mCallback;
public interface Callback {
void onSuccess(ArrayList<Winkel> winkels);
}
public ODKortrijkWebservice(Context context, Callback callback) {
...
mCallback = callback;
...
}
#Override
protected void onPostExecute(Void aVoid) {
...
mCallback.onSuccess(winkels);
}
}
In your Fragment:
public class YourFragment extends Fragment implements ODKortrijkWebservice.Callback, Adaptor.ItemCLickCallback {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_overview, container, false);
mRecyclerView = (RecyclerView) view.findViewById(R.id.recycle);
ODKortrijkWebservice webs = new ODKortrijkWebservice(this.getActivity(), this);
webs.execute();
return view;
}
#Override
public void onSuccess(ArrayList<Winkel> winkels) {
Adaptor adaptor = new Adaptor(winkels, getContext());
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
mRecyclerView.addItemDecoration(new VerticalSpace(30));
mRecyclerView.setAdapter(adaptor);
adaptor.setItemCLickCallback(this);
}
#Override
public void onItemClick(int p) {
}
#Override
public void onSecItemClick(int p) {
}
}
Here,
You need to create one interface at RecycleView.Adapter<>
private static OnItemClickListener listener;
// Define the listener interface
public interface OnItemClickListener {
void onItemClick(View itemView, int position);
}
// Define the method that allows the parent activity or fragment to define the listener
public void setOnItemClickListener(OnItemClickListener listener) {
this.listener = listener;
}
send require details with interface method
public class ViewHolder extends RecyclerView.ViewHolder{
TextView header_title;
public ViewHolder(final View itemView) {
super(itemView);
txt_country_name = (TextView)itemView.findViewById(R.id.header_title);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Triggers click upwards to the adapter on click
if (listener != null)
listener.onItemClick(itemView, getLayoutPosition());
}
});
}
}
call adapter listener
ListAdapter listAdapter;
listAdapter.setOnItemClickListener(new listAdapter.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
Toast.makeText(getActivity(), position+ " was clicked!", Toast.LENGTH_SHORT).show();
}
});

viewpager with tab fragments with recyclerview just show first item from database

The title say it all but just in case my problem is that i have a viewpager with two tabs, one with a recyclerview that fetch the data from a sqlite database but just show the first entry but i have created more.
this is my recyclerview adapter
public class RecyclerViewMessagesAdapter extends RecyclerView.Adapter<RecyclerViewMessagesAdapter.TextMessagesViewHolder>{
private DatabaseHandler databaseHandler;
private Context context;
public RecyclerViewMessagesAdapter(Context context){
this.context = context;
databaseHandler = new DatabaseHandler(context);
}
#Override
public int getItemCount() {
return databaseHandler.getAllTextMessage().size();
}
#Override
public TextMessagesViewHolder onCreateViewHolder(ViewGroup parent,int viewType){
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_messages, parent, false);
TextMessagesViewHolder textMessagesViewHolder = new TextMessagesViewHolder(view);
return textMessagesViewHolder;
}
public static class TextMessagesViewHolder extends RecyclerView.ViewHolder {
TextView textviewPhoneNumber, textviewDate;
TextMessagesViewHolder(View itemView) {
super(itemView);
textviewPhoneNumber = (TextView)itemView.findViewById(R.id.textview_recyclerview_phone_number);
textviewDate = (TextView)itemView.findViewById(R.id.textview_recyclerview_date_to_send);
}
}
#Override
public void onBindViewHolder(TextMessagesViewHolder holder, int position) {
holder.textviewPhoneNumber.setText(databaseHandler.getMessage(position+1).getPhoneNumber());
holder.textviewDate.setText(String.valueOf(databaseHandler.getMessage(position+1).getDate()));
}
#Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
}
and this is the fragment class with the recyclerview.
public class FragmentHistoryTab extends Fragment{
private View rootView;
private DatabaseHandler databaseHandler;
private TextView textviewEmptySavings;
private RecyclerView messagesRecyclerView;
private OnFragmentInteractionListener mListener;
public FragmentHistoryTab() {
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_history_tab,container,false);
return rootView;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
databaseHandler = new DatabaseHandler(getContext());
textviewEmptySavings = (TextView)rootView.findViewById(R.id.textview_empty_recyclerview);
RecyclerViewMessagesAdapter adapter = new RecyclerViewMessagesAdapter(getContext());
messagesRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerview_saved_messages);
messagesRecyclerView.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
messagesRecyclerView.setLayoutManager(layoutManager);
messagesRecyclerView.setAdapter(adapter);
if (databaseHandler.getAllTextMessage().size() >= 1){
textviewEmptySavings.setVisibility(View.GONE);
messagesRecyclerView.setVisibility(View.VISIBLE);
}else {
textviewEmptySavings.setVisibility(View.VISIBLE);
messagesRecyclerView.setVisibility(View.GONE);
}
}
#Override
public void onStart() {
super.onStart();
}
#Override
public void onResume() {
super.onResume();
}
#Override
public void onPause() {
super.onPause();
}
#Override
public void onStop() {
super.onStop();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
}
#Override
public void onDetach() {
super.onDetach();
}
public interface OnFragmentInteractionListener {
}
}
thanks in advance!
i don't know what happened but it just fixed all alone.

Categories