I am trying to run some code I got from some online tutorial of writing a fragment with a recyclerview in it but I am experiencing some difficulty in opening an activity from the onclick event. My adapter is below
public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.MyViewHolder> {
private final ArrayList<ItemModel> mArrayList;
private Context mcontext;
ItemAdapter(ArrayList<ItemModel> mArrayList) {
this.mArrayList = mArrayList;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
mcontext = parent.getContext();
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listing_item, parent, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
//Glide.with(mcontext).load(mArrayList.get(position).getImage()).into(holder.item_image);
holder.item_name.setText(mArrayList.get(position).getTitle());
holder.item_description.setText(mArrayList.get(position).getDescription());
holder.item_tags.setText(mArrayList.get(position).getTags());
Log.d("MyAdapter", "position: " + position);
}
#Override
public int getItemCount() {
return mArrayList.size();
}
class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private final ImageView item_image;
private final TextView item_name;
private final TextView item_description;
private final TextView item_tags;
private final LinearLayout cardViewLayout;
MyViewHolder(View view) {
super(view);
item_image = view.findViewById(R.id.item_image);
item_name = view.findViewById(R.id.item_name);
item_description = view.findViewById(R.id.item_description);
item_tags = view.findViewById(R.id.item_tags);
cardViewLayout = view.findViewById(R.id.cardViewLayout);
cardViewLayout.setOnClickListener(this);
}
#Override
public void onClick(View view) {
Intent intent = new Intent(mcontext, ItemView.class);
mcontext.startActivity(intent);
}
}
}
When I run the code nothing happens when i click on a item and neither do I see any error in the logcat
Instead, try like this,
ItemAdapter(Context context, ArrayList<ItemModel> mArrayList) {
this.mArrayList = mArrayList;
this.mContext = context;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listing_item, parent, false);
return new MyViewHolder(view);
}
In your fragment, while setting adapter
ItemAdapter itemAdapter=new ItemAdapter(getActivity(),itemList);
You can have a listener sent from the fragment to adapter. Instead of trying to start an activity from the adapter, you can send it back to the fragment to open the activity.
1. Define an interface
public interface MyAdapterListener {
void openActivity(/*any values to be sent*/);
}
2. The fragment should implement MyAdapterListener
3. send the listener object to an adapter in a constructor
ItemAdapter(ArrayList<ItemModel> mArrayList, MyAdapterListener listener) {..
mListener = listener;
}
4. On Adapter - View Holder: in onClick() return to fragment
public void onClick(View view) {
mListener.openActivity(/*any values to be sent*/);
}
I was of the idea that on your application of the adapter in some activity you simply call the activity on the setOnItemClickListener of the adapter
private void loadItemsData() {
RecyclerView itemsRecyclerView = view.findViewById(R.id.posts_recycler_view);
itemsRecyclerView.setHasFixedSize(true);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
itemsRecyclerView.setLayoutManager(layoutManager);
ItemAdapter myadapter = new ItemAdapter(new ArrayList<MyItem>(), getContext());
myadapter.setOnItemClickListener(new ItemAdapter.OnItemClickListener() {
#Override
public void onItemClick(View view, PostItems items) {
ViewItem.passingIntent(getActivity(), items.postid);
}
});
itemsRecyclerView.setAdapter(ListAdapter );
}
then once done that you come to the receiver activity and make way to get the variables being passed on to it
public static void passingIntent(Activity activity, Integer postid){
Intent intent = new Intent(activity, ViewItem.class);
intent.putExtra(MY_ITEM, postid);
activity.startActivity(intent);
}
I have used this approach in one of my apps lately
Try setting your click listener in onBindViewHolder like below
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
//Glide.with(mcontext).load(mArrayList.get(position).getImage()).into(holder.item_image);
holder.item_name.setText(mArrayList.get(position).getTitle());
holder.item_description.setText(mArrayList.get(position).getDescription());
holder.item_tags.setText(mArrayList.get(position).getTags());
holder.setOnClickListener(this) // put this line
Log.d("MyAdapter", "position: " + position);
}
Then of course you will override onClick in adapter rather than viewholder
Related
I am working on this diary app on Android studio and I want people to be able to delete their entries, but I have no idea how.
This is the TextListAdapter (recyclerview):
public class TextListAdapter extends RecyclerView.Adapter<TextListAdapter.TextViewHolder>{
private File[] allTextFiles;
private TimeAgo timeAgo;
private onTextItemListClick onTextItemListClick;
public TextListAdapter(File[] allTextFiles, onTextItemListClick onTextItemListClick) {
this.allTextFiles = allTextFiles;
this.onTextItemListClick = onTextItemListClick;
}
#NonNull
#Override
public TextViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_text_item, parent, false);
timeAgo = new TimeAgo();
return new TextViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull TextListAdapter.TextViewHolder holder, int position) {
holder.cardText.setText(allTextFiles[position].getName());
holder.textCardTitle.setText(timeAgo.getTimeAgo(allTextFiles[position].lastModified()));
}
#Override
public int getItemCount() {
return allTextFiles.length;
}
//Inner Class
public class TextViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private final Context context;
//Adding components
private TextView textCardTitle;
private Button cardText;
private MaterialButton textCardBtn;
private String recordFile;
private ImageButton deleteText;
public TextViewHolder(#NonNull View itemView) {
super(itemView);
textCardTitle = itemView.findViewById(R.id.text_card_title);
cardText = itemView.findViewById(R.id.card_text);
textCardBtn = itemView.findViewById(R.id.text_card_btn);
context = itemView.getContext();
deleteText = itemView.findViewById(R.id.delete_menu_btn);
textCardBtn.setOnClickListener(this);
}
#Override
public void onClick(View v) {
onTextItemListClick.onClickListener(allTextFiles[getAdapterPosition()], getAdapterPosition());
final Intent intent;
intent = new Intent(context, DiaryEntry.class);
intent.putExtra(Intent.EXTRA_TEXT, cardText.getText());
context.startActivity(intent);
}
}
//Interface
public interface onTextItemListClick{
void onClickListener(File file, int position);
}
}
And this is the fragment it comes from:
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
textList = view.findViewById(R.id.text_list_view);
//Reversing audioList
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
linearLayoutManager.setReverseLayout(true);
linearLayoutManager.setStackFromEnd(true);
textList.setLayoutManager(linearLayoutManager);
String path = getActivity().getFilesDir().getAbsolutePath();
File directory = new File(path);
allTextFiles = directory.listFiles();
textListAdapter = new TextListAdapter(allTextFiles, this);
textList.setHasFixedSize(true);
textList.setAdapter(textListAdapter);
}
What can I try next?
First of all you need set the clickListener inside TextViewHolder for deleteText
like this.
deleteText.setOnClickListener(this);
Then inside onClick of your function of the Adaptor
int position = getAdaptorPosition;
allTextFiles.remove(position);
notifyItemRemoved(position);
Hopefully, it will work inform me if found any error i would love to help you.
I tried to make a setListener on adapter to make something Action on the app. But the problem was when using this line of code to call setClickListener
adapter.setClickListener(this);
it gives me this error when using (this)
Required type: ItemClickListener
Provided: HomeImagesFragment
Here are my codes
Picassotest "Adapter for RecyclerView"
public class Picassotest extends RecyclerView.Adapter<Picassotest.ViewHolder> {
private String[] mData;
private Context context;
private LayoutInflater mInflater;
private ItemClickListener mClickListener;
// data is passed into the constructor
public Picassotest(Context context, String[] data) {
this.mInflater = LayoutInflater.from(context);
this.mData = data;
this.context = context;
}
// inflates the cell layout from xml when needed
#Override
#NonNull
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.images_list, parent, false);
return new ViewHolder(view);
}
// binds the data to the TextView in each cell
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
Picasso
.with(context)
.load(mData[position])
.fit() // to resize the image to imageView
.placeholder(R.drawable.loading_image) // load image
.transform(new PicassoRoundedTransformation(20, 0)) // Add radius to the images
.noFade()
.into(holder.mimageView);
}
// total number of cells
#Override
public int getItemCount() {
return mData.length;
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ImageView mimageView;
ViewHolder(View itemView) {
super(itemView);
mimageView = itemView.findViewById(R.id.list_image);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
}
}
// convenience method for getting data at click position
public String getItem(int id) {
return mData[id];
}
// allows clicks events to be caught
public void setClickListener(ItemClickListener itemClickListener) {
this.mClickListener = itemClickListener;
}
// parent activity will implement this method to respond to click events
public interface ItemClickListener {
void onItemClick(View view, int position);
}
}
HomeImagesFragment "Fragment"
public class HomeImagesFragment extends Fragment {
private Picassotest adapter;
String[] chooseImages;
public HomeImagesFragment(String[] chooseImages) {
this.chooseImages = chooseImages;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.images_fragment_home, container, false);
/* ArrayList for chooseImages */
chooseImages = new String[]{
"https://quotess.cc/wp-content/uploads/2020/01/4688.jpg",
"https://whatt.cc/wp-content/uploads/2018/07/4443.jpg",
"https://quotess.cc/wp-content/uploads/2020/01/4688.jpg",
};
/* make new object and find the view "GridView" */
RecyclerView recyclerView = rootView.findViewById(R.id.recyclerview_image_choose);
// Calculate the items and auto-fit it on the screen
int mNoOfColumns = Utility.calculateNoOfColumns(getActivity(), 140);
recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), mNoOfColumns));
adapter = new Picassotest(getActivity(), chooseImages);
adapter.setClickListener(this);
recyclerView.setAdapter(adapter);
return rootView;
}
public void onItemClick(int position) {
// get the image
String image = chooseImages[position];
Intent intent = new Intent(getActivity(), PicassoImageDisplayWallpaperAdapter.class);
intent.putExtra("imageUrl", image);
getActivity().startActivity(intent);
}
You need to create an interface like below code
interface ItemClickListener{
public void onItemClick(int position);
}
You need to implements ItemClickListener in your HomeImagesFragment
SAMPLE CODE
public class HomeImagesFragment extends Fragment implements ItemClickListener{
private Picassotest adapter;
String[] chooseImages;
public HomeImagesFragment(String[] chooseImages) {
this.chooseImages = chooseImages;
}
#Override
public void onItemClick(int position) {
// you will clikcked item position here
String image = chooseImages[position];
Intent intent = new Intent(getActivity(), PicassoImageDisplayWallpaperAdapter.class);
intent.putExtra("imageUrl", image);
getActivity().startActivity(intent);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.images_fragment_home, container, false);
/* ArrayList for chooseImages */
chooseImages = new String[]{
"https://quotess.cc/wp-content/uploads/2020/01/4688.jpg",
"https://whatt.cc/wp-content/uploads/2018/07/4443.jpg",
"https://quotess.cc/wp-content/uploads/2020/01/4688.jpg",
};
/* make new object and find the view "GridView" */
RecyclerView recyclerView = rootView.findViewById(R.id.recyclerview_image_choose);
// Calculate the items and auto-fit it on the screen
int mNoOfColumns = Utility.calculateNoOfColumns(getActivity(), 140);
recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), mNoOfColumns));
adapter = new Picassotest(getActivity(), chooseImages);
adapter.setClickListener(this);
recyclerView.setAdapter(adapter);
return rootView;
}
public void onItemClick(int position) {
// get the image
String image = chooseImages[position];
Intent intent = new Intent(getActivity(), PicassoImageDisplayWallpaperAdapter.class);
intent.putExtra("imageUrl", image);
getActivity().startActivity(intent);
}
(Additional) Another way if you use Kotlin:
Sample Code
In Adapter class (Picassotest):
class Picassotest : RecyclerView.Adapter<Picassotest.ViewHolder>{
internal var itemClickListener: (Int) -> Unit = {}
inner class ViewHolder(itemView:View):RecyclerView.ViewHolder(itemView){
init{
itemView.setOnClickListener{
itemClickListener.invoke(adapterPosition)
}
}
}
}
In HomeImagesFragment:
class HomeImagesFragment{
adapter = new Picassotest(getActivity(), chooseImages)
adapter.itemClickListener = { position->
//TODO handle item on click here
}
}
I have RecyclerView in my Main Activity. I want to change different fragments after clicking on different recyclerview Items. I try this by using position from onbindviewholder() but i am not able to change the fragment when i click on recyclerview items. I am not getting any error but at the same time nothing is happening onclick of recyclerview. Please check my code and tell me where i am wrong or which line of code i am missing.
RecyclerAdapter Code:
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
ArrayList<NewModel> newModels;
Context context;
public RecyclerAdapter(ArrayList<NewModel>newModels, Context context){
this.newModels = newModels;
this.context = context;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recy_layout, parent,false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, final int position) {
holder.imageView.setImageResource(newModels.get(position).getImg());
holder.textView.setText(newModels.get(position).getText());
holder.imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(position ==1){
((FragmentActivity)context).getSupportFragmentManager().beginTransaction()
.replace(R.id.framelayout, new FirstFragment());
}
else if(position ==2){
((FragmentActivity)context).getSupportFragmentManager().beginTransaction()
.replace(R.id.framelayout, new SecondFragment());
}
}
});
}
#Override
public int getItemCount() {
return newModels.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
TextView textView;
public ViewHolder(#NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.cirlceimg);
textView = itemView.findViewById(R.id.text1);
}
}
}
you forgot to call commit()
do this:
(((FragmentActivity)context).getSupportFragmentManager().beginTransaction()
.replace(R.id.framelayout, new SecondFragment()).commit();
Fragment is not rendered until you call commit() on the transaction , because transaction use builder pattern and in builder pattern there is a method to say that i don't want to do anything else just create the object, normally these method are name create() , build(), and commit() in this case
You can handle the onClickListener from your activity using callback implementation with an interface.
Interface:
public interface OnItemClickListener {
void onItemClick(int position);
}
Add the listener to your adapter's constructor
ArrayList<NewModel> newModels;
Context context;
private final OnItemClickListener listener;
public RecyclerAdapter(ArrayList<NewModel>newModels, Context context, OnItemClickListener listener){
this.newModels = newModels;
this.context = context;
this.listener = listener;
}
In your onBindViewHolder set the clicklistener
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, final int position) {
holder.imageView.setImageResource(newModels.get(position).getImg());
holder.textView.setText(newModels.get(position).getText());
holder.imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
listener.onItemClick(position);
}
});
}
In your activity:
RecyclerAdapter rvAdapter = new RecyclerAdapter(newModels, this, new RecyclerAdapter.OnItemClickListener() {
#Override public void onItemClick(int item) {
if(position ==1){
getSupportFragmentManager().beginTransaction().replace(R.id.framelayout, new FirstFragment()).commit();;}
else if(position ==2){
getSupportFragmentManager().beginTransaction().replace(R.id.framelayout, new SecondFragment()).commit();;
}
}});
recycler.setAdapter(rvAdapter);
Inside onBindViewHolder
holder.imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(position ==1){
((FragmentActivity)context).getSupportFragmentManager().beginTransaction()
.replace(R.id.framelayout, new FirstFragment()).addToBackStack(null).commit();
}
else if(position ==2){
((FragmentActivity)context).getSupportFragmentManager().beginTransaction()
.replace(R.id.framelayout, new SecondFragment()).addToBackStack(null).commit();
}
}
});
}
Hope this helps you.
I have a recyclerview in ShoppingCartActivity and a button in ProductDetailActivity. I want to send some data to ShoppingCartActivity when a button clicked in ProductDetailActivity and display them in recyclerview item that creates dynamically in ShoppingCartActivity.
I added addData method to recyclerview Adapter but it doesn't work and app crashes.
shop_btn = findViewById(R.id.add_to_shopping_cart);
shop_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent addToCart = new Intent(ProductDetailActivity.this, ShoppingCartActivity.class);
startActivity(addToCart);
}
});
//HERE IS MY RECYCLERVIEW ADAPTER
public class RecyclerViewAdapter_ShoppingCart extends RecyclerView.Adapter<RecyclerViewAdapter_ShoppingCart.MyViewHolder> {
private Context context;
List<CartItems> cartItemsList;
public RecyclerViewAdapter_ShoppingCart(Context context, List<CartItems> cartItemsList) {
this.context = context;
this.cartItemsList = cartItemsList;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view;
LayoutInflater layoutInflater = LayoutInflater.from(context);
view = layoutInflater.inflate(R.layout.card_cart, parent, false);
return new MyViewHolder(view);
}
#NonNull
#Override
public void onBindViewHolder(#NonNull final MyViewHolder holder, final int position) {
holder.cart_title.setText(cartItemsList.get(position).getTitle());
holder.cart_price.setText(cartItemsList.get(position).getPrice());
Picasso.get().load(cartItemsList.get(position).getImageUrl()).into(holder.cart_img);
}
#Override
public int getItemCount() {
return cartItemsList.size();
}
public static class MyViewHolder extends RecyclerView.ViewHolder {
TextView cart_title, cart_price;
ImageView cart_img;
public MyViewHolder(View itemView) {
super(itemView);
cart_title = itemView.findViewById(R.id.cart_title);
cart_price = itemView.findViewById(R.id.cart_price);
//cart_delete = itemView.findViewById(R.id.cart_delete);
cart_img = itemView.findViewById(R.id.cart_image);
}
}
public void addItem(List<CartItems> cartItems) {
CartItems newValue = new CartItems();
newValue.setTitle("123");
newValue.setPrice("123");
newValue.setImageUrl("");
cartItems.add(newValue);
notifyDataSetChanged();
}
}
My goal is adding recyclerview items dynamically to ShoppingCartActivity when a button clicked in ProductDetailActivity but app crashes.
I'm trying to delete an item from my RecyclerView when the user clicks on it. However, even though the delete method in the Adapter is public I get the error 'Cannot resolve method delete(int)' when trying to call 'delete' method from the onClick in MyViewHolder.
What gives? It's public so why can't I call it?
GroceryItemAdapter
public class GroceryItemAdapter extends RecyclerView.Adapter<MyViewHolder> {
private LayoutInflater inflater;
private Context context;
List<MetaData> data = Collections.emptyList();
public GroceryItemAdapter(Context context, List<MetaData> data) {
this.context = context;
inflater = LayoutInflater.from(context);
this.data = data;
}
public void delete(int position) {
data.remove(position);
notifyItemRemoved(position);
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.grocery_item_row, parent, false);
MyViewHolder holder = new MyViewHolder(view);
Log.i("GroceryHero", "onCreateViewHolder called");
return holder;
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
MetaData current = data.get(position);
holder.title.setText(current.title);
holder.icon.setImageResource(current.iconid);
Log.i("GroceryHero","onBindViewHolder called " + position);
}
#Override
public int getItemCount() {
return data.size();
}
}
MyViewHolder:
class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView title;
ImageView icon;
public MyViewHolder(View itemView) {
super(itemView);
Log.i("GroceryHero", "MyViewHolder called");
title = (TextView) itemView.findViewById(R.id.grocery_text);
icon = (ImageView) itemView.findViewById(R.id.grocery_icon);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Toast.makeText(v.getContext(), "Item clicked at " + getAdapterPosition(), Toast.LENGTH_SHORT).show();
delete(getAdapterPosition()); // ERROR: Cannot resolve method
}
}
You're trying to call delete from the view holder class. But delete is a method of the adapter class. You can may be pass an instance of adapter to the view holder in onCreateViewHolder and store it as a private field.
GroceryItemAdapter mAdapter;
public MyViewHolder(View itemView, GroceryItemAdapter adapter) {
mAdapter = adapter;
...
}
// now you can call
mAdapter.delete(getAdapterPosition());