How to start fragment from PagerAdapter - java

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;
}

Related

How to solve position problem in adapter? Using firebase as the backend

I'm creating an app with firebase as a backend. I'm using same adapter for different activity, now it is working good but positions were mismatched for example: The output of position 0 shows in position 1 and for position 1 shows in position 2 and so on.. How to solve this problem, The problem with the positions of the output.
Adapter:
public class FrontlistAdapter extends FirebaseRecyclerAdapter<Gamedata, FrontlistAdapter.ViewHolder> {
private static final String TAG = "GameAdapter";
Context mContext;
int positions;
public FrontlistAdapter(#NonNull FirebaseRecyclerOptions<Gamedata> options, Context context) {
super(options);
mContext = context;
}
#Override
protected void onBindViewHolder(#NonNull ViewHolder holder, int position, #NonNull Gamedata model) {
holder.name.setText(model.getName());
holder.address.setText(model.getAddress());
//Picasso.get().load(model.getFrontcover()).into(holder.Frontcover);
Glide.with(mContext).load(model.getFrontcover()).into(holder.Frontcover);
positions = position; //<-- here I'm having positions but output shows different for each positions
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View v = layoutInflater.inflate(R.layout.gamerow,parent,false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ImageView Frontcover;
TextView name;
TextView address;
View v;
public ViewHolder(#NonNull View itemView) {
super(itemView);
Frontcover = (ImageView)itemView.findViewById(R.id.frontcover);
name = (TextView)itemView.findViewById(R.id.frontname);
address=(TextView)itemView.findViewById(R.id.frontaddress);
v = itemView;
itemView.setClickable(true);
itemView.setOnClickListener((View.OnClickListener) this);
}
#Override
public void onClick(View v) {
String className = mContext.getClass().getSimpleName();
Intent intent = null;
switch (className) {
case "GameActivity":
intent = new Intent(mContext, Center_details.class);
intent.putExtra("User", getRef(positions).getKey());
break;
case "KidsActivity":
intent = new Intent(mContext,AllCenterDetails.class);
intent.putExtra("Kids",getRef(positions).getKey());
break;
}
mContext.startActivity(intent);
}
}
}
first what you have to do is create the interface like this
public interface ClickListner {
void onClick(View view, int position);
}
then in your activity create object of the interface like this and pass to the adapter along with your other data
ClickListner listener = ClickListner();
FrontlistAdapter customAdapter = new
FrontlistAdapter(AcceptedOrdersActivity.this,listener);
riderView.setAdapter(customAdapter);
copy this outside onCreate and intent in this
private ClickListner ClickListner() {
ClickListner listener = new ClickListner() {
#Override
public void onClick(View view, int position) {
int tag = (int) view.getTag();
if(tag == 0)
{
//Intent here
}
}
};
return listener;
}
now your adapter should be this one
public class FrontlistAdapter extends
RecyclerView.Adapter<FrontlistAdapter .DataObjectHolder>{
ClickListner listenr;
Context context;
public FrontlistAdapter (Context context,ClickListner listenr) {
this.context = context;
this.listenr = listenr;
}
public static class DataObjectHolder extends RecyclerView.ViewHolder {
Context context;
public DataObjectHolder(View itemView,ClickListner listenr) {
super(itemView);
this.listenr = listenr;
Frontcover = (ImageView)itemView.findViewById(R.id.frontcover);
name = (TextView)itemView.findViewById(R.id.frontname);
address=(TextView)itemView.findViewById(R.id.frontaddress);
v = itemView;
setOnClickListeners();
}
private void setOnClickListeners() {
`v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
v.setTag(0);
listenr.onClick(v, getAdapterPosition());
}
});
}
}
#NonNull
#Override
public FrontlistAdapter.DataObjectHolder onCreateViewHolder(#NonNull ViewGroup parent,
int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.cell_orderdetail_list, parent, false);
FrontlistAdapter.DataObjectHolder dataObjectHolder = new
FrontlistAdapter.DataObjectHolder(view,listenr);
return dataObjectHolder;
}
#Override
public void onBindViewHolder(#NonNull FrontlistAdapter.DataObjectHolder holder, int
position) {
}
#Override
public int getItemCount() {
return options.size;
}
}
positions = position;
This is your problem. You're setting one global position for everything in the adapter.
Everywhere you are currently using position, you should instead be calling getBindingAdapterPosition() on the ViewHolder.

I'd like to implement a recycler view click event

I want to implement a recycler view click event. I intended to have an event when I clicked tvRoomNum. But error 'TextView.setOnClickListener(android.view.View$OnClickListener)' on a null object reference' occurs. So I notice that tvRoomNum is null object and attempt to use 'findViewById'. But the function is not recognized. How can I solve the problem?
public class RoomAdapter extends RecyclerView.Adapter<RoomAdapter.CustomViewHolder> {
private Context context;
private ArrayList<RoomData> rooms;
public ArrayList<StudnetInRoomData> students;
private LayoutInflater inflater;
private RoomData room;
View view;
public RoomAdapter(Context context, ArrayList<RoomData> rooms) {
this.context = context;
this.rooms = rooms;
this.inflater = LayoutInflater.from(context);
students = new ArrayList<>();
}
#Override
public CustomViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
view = inflater.inflate(R.layout.single_room, parent, false);
return new CustomViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull CustomViewHolder holder, int position) {
room = rooms.get(position);
holder.tvRoomNum.setText(String.valueOf(room.roomNum));
}
#Override
public int getItemCount() {
return rooms.size();
}
public class CustomViewHolder extends RecyclerView.ViewHolder {
public TextView tvRoomNum;
public CustomViewHolder(View itemView) {
super(itemView);
tvRoomNum.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
Intent intent = new Intent(view.getContext(), PlusStudentActivity.class);
intent.putExtra("studentList", room.students);
context.startActivity(intent);
}
});
}
}
}
The code below is the adapter of the recycler view that implements the recycler view. This is a dual recircular view structure.
public class FloorAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements OnFloorItemClickListener {
OnFloorItemClickListener listener;
static public ArrayList<FloorData> floors;
private Context context;
private LayoutInflater layoutInflater;
private OnItemClickListener mListener = null;
public FloorAdapter(ArrayList<FloorData> floors, Context context) {
this.floors = floors;
this.context = context;
this.layoutInflater = LayoutInflater.from(context);
}
public interface OnItemClickListener{
void onItemClick(View v, int pos);
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.mListener = listener ;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.signle_floor, parent, false);
return new GridViewHolder(view);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
((GridViewHolder)holder).recyclerView.setAdapter(new RoomAdapter(context, floors.get(position).rooms));
((GridViewHolder)holder).recyclerView.setLayoutManager(new GridLayoutManager(context, 5));
((GridViewHolder)holder).recyclerView.setHasFixedSize(true);
((GridViewHolder)holder).tvFloorNum.setText(String.valueOf(floors.get(position).floorNum));
}
#Override
public int getItemCount() {
return floors.size();
}
#Override public void onItemClick(RecyclerView.ViewHolder holder, View view, int position) {
if(listener != null){
listener.onItemClick(holder,view,position);
}
}
#Override
public int getItemViewType(int position) {
return floors.get(position).id;
}
public class GridViewHolder extends RecyclerView.ViewHolder {
RecyclerView recyclerView;
TextView tvFloorNum;
Button btnPlusRoom;
public GridViewHolder(View itemView) {
super(itemView);
recyclerView = itemView.findViewById(R.id.rvRooms);
tvFloorNum = itemView.findViewById(R.id.tvFloorNum);
btnPlusRoom = (Button)itemView.findViewById(R.id.btnPlusRoom);
btnPlusRoom.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v)
{
int pos = getAdapterPosition();
if (pos != RecyclerView.NO_POSITION)
{
if(mListener != null){
mListener.onItemClick(v, pos);
}
}
}
});
}
}
}
Your TextView is null, because you are missing the findViewById():
You find the Id on a View, in this case, it is the itemView
The function was not recognised because you would've just called findViewById() & ViewHolder does not have that method,
You should've called itemView.findViewById() instead.
Try this:
public class CustomViewHolder extends RecyclerView.ViewHolder {
public TextView tvRoomNum;
public CustomViewHolder(View itemView) {
super(itemView);
tvRoomNum = itemView.findViewById(R.id.your_textview_id) // THIS
tvRoomNum.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
Intent intent = new Intent(view.getContext(), PlusStudentActivity.class);
intent.putExtra("studentList", room.students);
context.startActivity(intent);
}
});
}
}

How to Implemet onClick listener insidie Recycleview to open different activities

I'm using Horizontal Recycleview to show the icon in my app. It cotains one Recycle view and one Mainactivity Class.
I'm trying to use the onClick listener method inside the adapter class but to my surprise it is not working yet all and also don't recognize intent and give cannot resolve intent symbol. so I used toast message instead but also app compile sucessfully but nothing happens.
Here is my Recycle view class
public class SnapRecyclerAdapter extends RecyclerView.Adapter<SnapRecyclerAdapter.ReyclerViewHolder> {
private LayoutInflater layoutInflater;
private Context context;
private ArrayList<Item> items;
public SnapRecyclerAdapter(Context context, ArrayList<Item> items) {
this.layoutInflater = LayoutInflater.from(context);
this.context = context;
this.items = items;
}
#Override
public ReyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View item = layoutInflater.inflate(R.layout.item_recycler_view, parent, false);
return new ReyclerViewHolder(item);
}
#Override
public void onBindViewHolder(final ReyclerViewHolder holder, int position) {
Item item = items.get(position);
holder.image.setImageResource(item.getDrawable());
holder.appName.setText(item.getName());
}
#Override
public int getItemCount() {
return items.size();
}
class ReyclerViewHolder extends RecyclerView.ViewHolder {
private ImageView image;
private TextView appName;
private ReyclerViewHolder(final View v) {
super(v);
image = (ImageView) v.findViewById(R.id.image);
appName = (TextView) v.findViewById(R.id.app_name);
context = v.getContext();
}
private View.OnClickListener Click=new View.OnClickListener(){
#Override
public void onClick(View v) {
switch(getAdapterPosition())
{
case 1:
Toast.makeText(context, "No data available", Toast.LENGTH_SHORT).show();
}
}
};
}
}
and my Mainactivity class is
public class MainActivity extends AppCompatActivity {
private ArrayList<Item> items;
private RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
createApps();
SnapHelper snapHelper = new GravitySnapHelper(Gravity.BOTTOM);
snapHelper.attachToRecyclerView(recyclerView);
// HORIZONTAL for Gravity START/END and VERTICAL for TOP/BOTTOM
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
recyclerView.setHasFixedSize(true);
SnapRecyclerAdapter adapter = new SnapRecyclerAdapter(this, items);
recyclerView.setAdapter(adapter);
}
private void createApps() {
items = new ArrayList<>();
items.add(new Item("Google+", R.drawable.google_plus));
items.add(new Item("Facebook", R.drawable.facebook));
items.add(new Item("LinkedIn", R.drawable.linkedin));
items.add(new Item("Youtube", R.drawable.youtube));
items.add(new Item("Instagram", R.drawable.instagram));
items.add(new Item("Skype", R.drawable.skype));
items.add(new Item("Twitter", R.drawable.twitter));
items.add(new Item("Wikipedia", R.drawable.wikipedia));
items.add(new Item("Whats app", R.drawable.what_apps));
items.add(new Item("Pokemon Go", R.drawable.pokemon_go));
}
}
Your implementation setOnClickListener is not correct. You should set it for each view in RecylerView and inside that you can write your code to start an activity or show a toast, etc.
public class SnapRecyclerAdapter extends RecyclerView.Adapter<SnapRecyclerAdapter.ReyclerViewHolder> {
private LayoutInflater layoutInflater;
private Context context;
private ArrayList<Item> items;
public SnapRecyclerAdapter(Context context, ArrayList<Item> items) {
this.layoutInflater = LayoutInflater.from(context);
this.context = context;
this.items = items;
}
#Override
public ReyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View item = layoutInflater.inflate(R.layout.item_recycler_view, parent, false);
ReyclerViewHolder holder = new ReyclerViewHolder(item)
item.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, items.get(holder.getAdapterPosition()).getName(), Toast.LENGTH_SHORT).show();
// TODO: You can start an activity by using Intent as well.
}
});
return holder;
}
#Override
public void onBindViewHolder(final ReyclerViewHolder holder, int position) {
Item item = items.get(position);
holder.image.setImageResource(item.getDrawable());
holder.appName.setText(item.getName());
}
#Override
public int getItemCount() {
return items.size();
}
class ReyclerViewHolder extends RecyclerView.ViewHolder {
private ImageView image;
private TextView appName;
private ReyclerViewHolder(final View v) {
super(v);
image = (ImageView) v.findViewById(R.id.image);
appName = (TextView) v.findViewById(R.id.app_name);
context = v.getContext();
}
}
}
You want the click listener on the whole itemView? Here is an example:
//Implement View.OnClickListener
class ReyclerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private ImageView image;
private TextView appName;
private ReyclerViewHolder(final View v) {
super(v);
image = (ImageView) v.findViewById(R.id.image);
appName = (TextView) v.findViewById(R.id.app_name);
// Set the onClickListener
v.setOnClickListener(this)
}
#Override
public void onClick(View v) {
// if (getAdapterPosition() != RecyclerView.NO_POSITION) {
Context context = v.getContext();
Intent intent = new Intent(context, aActivityClass.class);
intent.putExtra(extraKey, extraValue);
context.startActivity(intent)
// }
};
}
Do you set the click listener on a View ? Something like image.setOnClickListener(Click) ? By the way, variables should start with lowercase
you need to pass the view from adapter by using onclickListner and make and internface in adapter
this is where we are passing the view in adapter :
#Override
public void onBindViewHolder(myholder holder, final int position) {
holder.parent.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onItemClick.click(position,view);
}
});
Interface for adapter onclick and activity:
public void clickItem(PartnerBankAdapter.OnItemClick onItemClick){
this.onItemClick=onItemClick;
}
public interface OnItemClick{
public void click(int postion,View view);
}
Define Interface as glocbal object in adapter:
private OnItemClick onItemClick;
Consider this example for adapter:
public class PartnerBankAdapter extends RecyclerView.Adapter<PartnerBankAdapter.myholder> {
public Context mContext;
ArrayList<String> bankname;
ArrayList<Integer> iconlist;
private OnItemClick onItemClick;
public PartnerBankAdapter(Context mContext, ArrayList<String> banklist,ArrayList<Integer> iconlist)
{
this.mContext = mContext;
this.bankname=banklist;
this.iconlist=iconlist;
}
#Override
public myholder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.bank_list_adpater,parent,false);
return new myholder(view);
}
#Override
public void onBindViewHolder(myholder holder, final int position) {
holder.parent.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onItemClick.click(position,view);
}
});
holder.txt.setText(bankname.get(position));
holder.image.setImageResource(iconlist.get(position));
holder.txtacc.setText(bankname.get(position));
}
#Override
public int getItemCount() {
return bankname.size();
}
public static class myholder extends RecyclerView.ViewHolder {
TextView txt,txtacc;
ImageView image;
LinearLayout parent;
public myholder(View itemView) {
super(itemView);
txt= (TextView) itemView.findViewById(R.id.txbank);
image=(ImageView) itemView.findViewById(R.id.imagebank);
parent=(LinearLayout) itemView.findViewById(R.id.parent);
txtacc=(TextView) itemView.findViewById(R.id.txbankacc);
}
}
public void clickItem(PartnerBankAdapter.OnItemClick onItemClick){
this.onItemClick=onItemClick;
}
public interface OnItemClick{
public void click(int postion,View view);
}
}
and then just use onclick in your activity on recyclerview
consider code below for onclick in activity :
partnerBankAdapter.clickItem(new PartnerBankAdapter.OnItemClick() {
#Override
public void click(int postion, View view) {
}
});

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();
}
});

RecylerView Adapter causing memory leak when using on Click interface

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.

Categories