I am showing random images in gridview using string array urls with picasso in first activity and when I'm clicking on any image in gridview then I want to show that exact random image in next activity. i am using put extra and sending that position like int r = random.nextInt(array.length); I'm using that r into gridview put extra as position. but when i m setting that r in imageview its showing another random image not exact.
This is my code
public class MainActivity extends Activity {
static Random random;
private GridView photoGrid;
private int mPhotoSize, mPhotoSpacing;
static int p;
// Some items to add to the GRID
static final String[] icons= {
"https://abhiandroid.com/ui/wp-content/uploads/2015/12/horizontalSpacing-in-Gridview.jpg",
"http://www.whatsappstatusmessages.com/wp-content/uploads/2017/01/whatsapp-dp-images-in-english.jpg",
"http://www.sarkarinaukrisearch.in/wp-content/uploads/2019/02/whatsapp-dp-status-in-english-1-77.jpg",
"https://www.trueshayari.in/wp-content/uploads/2018/07/Love-Status-DP-for-Couple.jpg",
"https://4.bp.blogspot.com/-2iawNx83Kpw/XL21pPj0aPI/AAAAAAAAKiE/VRR7pupbWDUj0TNNAKdGH8Baaz_c9IcSgCLcBGAs/s1600/ss.jpg",
"https://www.trueshayari.in/wp-content/uploads/2018/07/Love-Status-DP-for-Couple.jpg",
"https://3.bp.blogspot.com/-8us6YRiZEh0/XL21c6ibbXI/AAAAAAAAKh4/eNyjErq7q04YCeWxDPWojYfOoAC8BCodwCLcBGAs/s1600/s.jpg"
};
GridView gridView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gridView = findViewById(R.id.albumGrid);
CustomAdopter customAdopter=new CustomAdopter();
gridView.setAdapter(customAdopter);
gridView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(MainActivity.this, SwipeView.class);
intent.putExtra("id", p);
startActivity(intent);
}
});
}
private static class CustomAdopter extends BaseAdapter {
static int p;
#Override
public int getCount() {
return icons.length;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = getLayoutInflater().inflate(R.layout.phototem, null);
ImageView imageView = view.findViewById(R.id.cover);
random = new Random(); // or create a static random field...
p= random.nextInt(icons.length);
Picasso.get().load(icons[p]).placeholder(R.mipmap.ic_launcher).error(R.mipmap.ic_launcher).into(imageView);
return view;
}
}
Showing Image in this Activity
public class SwipeView extends Activity
{
int positions;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_swipe_view);
// get intent data
Intent i = getIntent();
// Selected image id
positions = i.getExtras().getInt("id");
ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager);
ImagePagerAdapter adapter = new ImagePagerAdapter();
viewPager.setAdapter(adapter);
viewPager.setCurrentItem(technoapps4.goodnightshayariworld.MainActivity.p);
}
private class ImagePagerAdapter extends PagerAdapter
{
String[] icons =MainActivity.icons ;
#Override
public int getCount()
{
return icons.length;
}
#Override
public boolean isViewFromObject(View view, Object object)
{
return view == ((ImageView) object);
}
#Override
public Object instantiateItem(ViewGroup container, int position)
{
Context context = SwipeView.this;
ImageView imageView = new ImageView(context);
Picasso.get().load(icons[position]).into(imageView);
container.addView(imageView, 0);
return imageView;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object)
{
container.removeView((ImageView) object);
}
}
}
For this purpose, you should create an Interface and pass the random position though that interface.
And the variable p isn't the clicked item position. The value of p is changing continuously while the gridView is populating items.
Edit:
Create an Interface like this:
public interface ItemClickListener {
void onItemClick(int position);
}
Now initialize the ItemClickListener instance inside your CustomAdopter class using the public setter.
public void setItemClickListener(ItemClickListener clickListener) {
onItemClickListener = clickListener;
}
and finally, add the following code inside the getview method to pass your adapter position to the listener.
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onItemClickListener.onItemClick(p);
}
});
Now instead of GridView's OnItemClickListener(), use this interface to get the correct position. like this-
gridView.setAdapter(customAdopter);
customAdopter.setItemClickListener(new ItemClickListener() {
#Override
public void onItemClick(int position) {
Intent intent = new Intent(MainActivity.this, SwipeView.class);
intent.putExtra("id", position);
startActivity(intent);
}
});
I was going to provide you an alternative to this issue which is to use a recyclerview with gridLayoutManager and create a Custom layout that implements RecyclerView.Adapter....All of this might seem confusing to you I guess, so I quickly create a Unit Test to simulate what your code wants to achieve and below is the result.
public class ExampleUnitTest {
private static String data = null;
#Test
public void setParentData(){
data = "I set You";
Subclass subclass = new Subclass();
subclass.getParentData();
}
private static class Subclass{
void getParentData(){
assertEquals("I set You", data);
}
}
}
//Tests passed
I will take a minute to explain this, since you have your custom adapter as a subclass of MainActivity, then I believe that the subclass should have access to some values of its parent class.
I am talking about this: static int p; so you don't need to create two of that like you created in the subclass also which is the CustomAdopter class.
So below is the modification to your code and I believe it should work as far as the test passed, else, pls let me know so I can take a look again.
This is not really an answer but it's the only way I can share code and explain some things in details.
public class MainActivity extends Activity {
static Random random;
private GridView photoGrid;
private int mPhotoSize, mPhotoSpacing;
static int p;
// Some items to add to the GRID
static final String[] icons= {
"https://abhiandroid.com/ui/wp-content/uploads/2015/12/horizontalSpacing-in-Gridview.jpg",
"http://www.whatsappstatusmessages.com/wp-content/uploads/2017/01/whatsapp-dp-images-in-english.jpg",
"http://www.sarkarinaukrisearch.in/wp-content/uploads/2019/02/whatsapp-dp-status-in-english-1-77.jpg",
"https://www.trueshayari.in/wp-content/uploads/2018/07/Love-Status-DP-for-Couple.jpg",
"https://4.bp.blogspot.com/-2iawNx83Kpw/XL21pPj0aPI/AAAAAAAAKiE/VRR7pupbWDUj0TNNAKdGH8Baaz_c9IcSgCLcBGAs/s1600/ss.jpg",
"https://www.trueshayari.in/wp-content/uploads/2018/07/Love-Status-DP-for-Couple.jpg",
"https://3.bp.blogspot.com/-8us6YRiZEh0/XL21c6ibbXI/AAAAAAAAKh4/eNyjErq7q04YCeWxDPWojYfOoAC8BCodwCLcBGAs/s1600/s.jpg"
};
GridView gridView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gridView = findViewById(R.id.albumGrid);
random = new Random(); // or create a static random field...
p= random.nextInt(icons.length);
CustomAdopter customAdopter=new CustomAdopter();
gridView.setAdapter(customAdopter);
gridView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(MainActivity.this, SwipeView.class);
intent.putExtra("id", p);
startActivity(intent);
}
});
}
private static class CustomAdopter extends BaseAdapter {
#Override
public int getCount() {
return icons.length;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = getLayoutInflater().inflate(R.layout.phototem, null);
ImageView imageView = view.findViewById(R.id.cover);
Picasso.get().load(icons[p]).placeholder(R.mipmap.ic_launcher).error(R.mipmap.ic_launcher).into(imageView);
return view;
}
}
Related
Due to the fact that the ListView is not optimized enough, I decided that I would switch to the Recycler View. The first problem that hit me was this one.
My RecyclerView adapter:
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {
private List<String> mData;
private LayoutInflater mInflater;
private ItemClickListener mClickListener;
// data is passed into the constructor
MyRecyclerViewAdapter(Context context, List<String> data) {
this.mInflater = LayoutInflater.from(context);
this.mData = data;
}
// inflates the row layout from xml when needed
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.adapter_box, parent, false);
return new ViewHolder(view);
}
// binds the data to the TextView in each row
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
String animal = mData.get(position);
holder.myTextView.setText(animal);
}
// total number of rows
#Override
public int getItemCount() {
return mData.size();
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView myTextView;
ViewHolder(View itemView) {
super(itemView);
myTextView = itemView.findViewById(R.id.text_adapter);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
}
}
// convenience method for getting data at click position
String getItem(int id) {
return mData.get(id);
}
// allows clicks events to be caught
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);
}
Using ListView I could do like this:
ListView listView = findViewById(R.id.testL);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (parent.getItemAtPosition(position).equals("hello")) {
TextView details = word_dialog.findViewById(R.id.word_edit_desc);
details.setText("hello");
}
}
});
How can I achieve the same result, but only with the Recycle view?:
#Override
public void onItemClick(View view, int position) {
}
I will be very grateful if you can help me!
I want to be able to click on the recycler view items in MainActivity.java, I already did it, now I need to be able to do my own actions on each line sorted using equals
ArrayList<String> animalNames = new ArrayList<>();
animalNames.add("Dog");
animalNames.add("Cow");
animalNames.add("Camel");
animalNames.add("Sheep");
animalNames.add("Goat");
// set up the RecyclerView
recyclerView = findViewById(R.id.myList);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new MyRecyclerViewAdapter(this, animalNames);
adapter.setClickListener(this);
recyclerView.setAdapter(adapter);
if (somecode.equals("Dog")){
soundPlay(MediaPlayer.create(getBaseContext(), R.raw.star));
}
if (somecode.equals("Camel")){
soundPlay(MediaPlayer.create(getBaseContext(), R.raw.tick));
}
You can define an interface in your adapter, like below
public interface ClickListener{
void onClick();
}
Implement in fragment or activity that your adapter at:
ClickListener listener = () ->{
TextView details = word_dialog.findViewById(R.id.word_edit_desc);
details.setText("hello");
}
then pass interface to adapter use constructor or setter, and you can use interface in your viewHolder when bind like below:
itemView.setOnClickListener(()->{
if (your_list.get(getAdapterPosition()).equals("hello")) {
interface_var_name.onClick()
}
});
This is Inbuild Click event of Recyclerview and another way to use Interface
holder.itemView.setOnClickListener(v ->
if (animal.equals("Your animal String"){
//Your code
}
);
if want to use interface then this is reference link
I need some help for a summer project
This is my Events fragment
This is my MyList fragment
I'm using a RecyclerView+Cardview to display the Events. The idea is that the user can click the big plus on the right side of each card, and the card would be displayed in the MyList fragment. I would like to ask if it's possible to transfer a card directly from one fragment to another? Also, both fragments are contained within the same activity, which makes it a little trickier(I haven't found any available solutions).
If that is not possible, another way is to transfer the reference type object contained in the CardView to the MyList fragment. However, this is even less straightforward. This is because the button is inflated in the adapter, but there is no reference type object created here. I have seen many tutorials on using the Parcelable interface, however, I don't know how to implement it here when I'm unable to even create the object in the adapter. The reference object is created in another activity and stored in Firebase before it is read and displayed.
I'm going to attach my EventsAdapter.java and EventsItem.java and EventsFragment.java code below, but please let me know if I should include more code to describe the problem.
Thanks for reading my very long post!!
public class EventsAdapter extends RecyclerView.Adapter<EventsAdapter.EventsViewHolder> implements Filterable {
private ArrayList<EventsItem> mEventsList;
private ArrayList<EventsItem> mEventsListFull;
private EventsAdapter.OnItemClickListener mListener;
private Context mContext;
private DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.UK);
public interface OnItemClickListener {
void onItemClick(int position);
}
//the ViewHolder holds the content of the card
public static class EventsViewHolder extends RecyclerView.ViewHolder {
public ImageView mImageView;
public ImageView mAddButton;
public TextView mTextView1;
public TextView mTextView2;
public TextView mTextView3;
public TextView mTextView4;
public TextView mTextView5;
public EventsViewHolder(Context context, View itemView, final EventsAdapter.OnItemClickListener listener) {
super(itemView);
final Context context1 = context;
mImageView = itemView.findViewById(R.id.imageView);
mAddButton = itemView.findViewById(R.id.image_add);
mTextView1 = itemView.findViewById(R.id.title);
mTextView2 = itemView.findViewById(R.id.event_description);
mTextView3 = itemView.findViewById(R.id.date);
mTextView4 = itemView.findViewById(R.id.location);
mTextView5 = itemView.findViewById(R.id.time);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(position);
}
}
}
});
mAddButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String str1 = mTextView1.getText().toString();
String str2 = mTextView2.getText().toString();
String str3 = mTextView3.getText().toString();
String str4 = mTextView4.getText().toString();
String str5 = mTextView5.getText().toString();
Bundle bundle = new Bundle();
bundle.putString("title", str1);
bundle.putString("event description", str2);
bundle.putString("date", str3);
bundle.putString("location", str4);
bundle.putString("time", str5);
MylistFragment mlf = new MylistFragment();
mlf.setArguments(bundle);
}
});
}
}
//Constructor for EventsAdapter class. This ArrayList contains the
//complete list of items that we want to add to the View.
public EventsAdapter(Context context, ArrayList<EventsItem> EventsList) {
mEventsList = EventsList;
mContext = context;
mEventsListFull = new ArrayList<>(EventsList); // copy of EventsList for SearchView
}
//inflate the items in a EventsViewHolder
#NonNull
#Override
public EventsAdapter.EventsViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.event_item, parent, false);
EventsAdapter.EventsViewHolder evh = new EventsAdapter.EventsViewHolder(mContext, v, mListener);
return evh;
}
#Override
public void onBindViewHolder(#NonNull EventsAdapter.EventsViewHolder holder, int position) {
EventsItem currentItem = mEventsList.get(position);
holder.mImageView.setImageResource(currentItem.getProfilePicture());
holder.mTextView1.setText(currentItem.getTitle());
holder.mTextView2.setText(currentItem.getDescription());
holder.mTextView3.setText(df.format(currentItem.getDateInfo()));
holder.mTextView4.setText(currentItem.getLocationInfo());
holder.mTextView5.setText(currentItem.getTimeInfo());
}
#Override
public int getItemCount() {
return mEventsList.size();
}
public class EventsItem implements Occasion, Parcelable {
//fields removed for brevity
//constructor removed for brevity
}
public EventsItem() {
}
public EventsItem(Parcel in) {
profilePicture = in.readInt();
timeInfo = in.readString();
hourOfDay = in.readInt();
minute = in.readInt();
locationInfo = in.readString();
title = in.readString();
description = in.readString();
}
public static final Creator<EventsItem> CREATOR = new Creator<EventsItem>() {
#Override
public EventsItem createFromParcel(Parcel in) {
return new EventsItem(in);
}
#Override
public EventsItem[] newArray(int size) {
return new EventsItem[size];
}
};
//getter methods have been removed for brevity
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(profilePicture);
dest.writeString(timeInfo);
dest.writeString(locationInfo);
dest.writeString(title);
dest.writeString(description);
dest.writeString(df.format(dateInfo));
dest.writeInt(hourOfDay);
dest.writeInt(minute);
}
}
public class EventsFragment extends Fragment {
ArrayList<EventsItem> EventsItemList;
FirebaseDatabase mDatabase;
DatabaseReference mDatabaseReference;
ValueEventListener mValueEventListener;
private RecyclerView mRecyclerView;
private RecyclerView.LayoutManager mLayoutManager;
private EventsAdapter mAdapter;
private View rootView;
public FloatingActionButton floatingActionButton;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_events, container, false);
mDatabase = FirebaseDatabase.getInstance();
mDatabaseReference = mDatabase.getReference().child("Events");
createEventsList();
buildRecyclerView();
floatingActionButton = rootView.findViewById(R.id.fab);
floatingActionButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), EventsAdder.class);
startActivity(intent);
}
});
mValueEventListener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
EventsItemList.add(snapshot.getValue(EventsItem.class));
}
EventsAdapter eventsAdapter = new EventsAdapter(getActivity(), EventsItemList);
mRecyclerView.setAdapter(eventsAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
mDatabaseReference.addValueEventListener(mValueEventListener);
setHasOptionsMenu(true);
Toolbar toolbar = rootView.findViewById(R.id.events_toolbar);
AppCompatActivity activity = (AppCompatActivity) getActivity();
activity.setSupportActionBar(toolbar);
return rootView;
}
public void createEventsList() {
EventsItemList = new ArrayList<>();
}
public void buildRecyclerView() {
mRecyclerView = rootView.findViewById(R.id.recyclerview);
mLayoutManager = new LinearLayoutManager(getContext());
mAdapter = new EventsAdapter(getActivity(), EventsItemList);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
}
}
If you would like to see the same CardView within the MyListFragment, you could have the MyListFragment contain a RecyclerView, and reuse the same EventsAdapter and EventsViewHolder. The only difference is that rather than populating the adapter with all the children of the "Events" from your database, you would only populate it with the single Event that you want.
Also, since you have made your Event class implement parcelable, you do not need to manually create the bundle when clicking the plus button.
I am assuming you have a single Activity, and you simply want to replace the EventsFragment with the MyListFragment. Checkout the docs for replacing one fragment with another.
Step 1:
Extend your onItemClickListener to look like:
public interface OnItemClickListener {
void onItemClick(int position);
void onPlusButtonClick(int position);
}
and adjust the code in your EventsViewHolder constructor to look like this when the plus button is clicked:
mAddButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
// no need to manually create the bundle here
// you already have all the information you need
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onPlusButtonClick(position);
}
}
}
});
Step 2:
Implement our new method onPlusButtonClick. As per our discussion in the comments, it seems you do not implement this interface anywhere. You can implement it inside the constructor to your EventsAdapter:
public EventsAdapter(Context context, ArrayList<EventsItem> EventsList) {
mEventsList = EventsList;
mContext = context;
mEventsListFull = new ArrayList<>(EventsList); // copy of EventsList for SearchView
mListener = new OnItemClickListener() {
#Override
public void onItemClick() {
// handle clicking the entire view holder
// NOTE: inside your EventsViewHolder, it looks like you call this method on the entire itemView. This could 'swallow' the click on the plus button. You may need to adjust your code to handle this.
}
#Override
public void onPlusButtonClick(int position) {
MyListFragment myListFragment = new MyListFragment();
Event event = mEventsList.get(position);
Bundle bundle = new Bundle();
bundle.putExtra("event", event); // this will work due to implementing parcelable
myListFragment.setArguments(bundle);
// use mContext since im assuming we areinside adapter
// if in an Activity, no need to use context to get the fragment manager
FragmentTransaction transaction = mContext.getSupportFragmentManager().beginTransaction();
// Replace the EventsFragment with the MyListFragment
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, myListFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
}
Step 3:
Inside your MyListFragments onCreateView() method:
#Override
public View onCreateView (
LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState
) {
Bundle bundle = getArguments();
Event event = bundle.getExtra("event"); // again, will work due to implementing parcelable
// from here you should bind to a recycler view, and you can even reuse your adapter like so:
List<EventsItem> singleEventList = new List<EventsItem>();
singleEventList.add(event);
EventsAdapter adapter = new EventsAdapter(getActivity(), singleEventList);
// be sure to inflate and return your view here...
}
and you should be good to go!
I have left out bits of code here and there for simplicity.. but I hope this is understandable.
As a side note.. in your firebase database listener, it is bad practice to create a new EventsAdapter every single time your data is updated. Instead, you should update the data in the adapter with the new values. Do this by creating a public method inside the adapter such as replaceEvents(List<EventsItem> newEvents), and inside, replace mEventsList with the new events, then call notifyDataSetChanged().
I have recycleview which is set to auto scroll. I am looking to implement onclicklistener such that new activity will open.
Here is my Recycleview
final int duration = 10;
final int pixelsToMove = 30;
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final Runnable SCROLLING_RUNNABLE = new Runnable() {
#Override
public void run() {
top.smoothScrollBy(pixelsToMove, 0);
mHandler.postDelayed(this, duration);
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_home, container, false);
top = (RecyclerView) view.findViewById(R.id.top);
final LinearLayoutManager llm = new LinearLayoutManager(getActivity(),LinearLayoutManager.HORIZONTAL,false);
top.setLayoutManager(llm);
top.setHasFixedSize(true);
staggeredBooksAdapter = new TopAdapter(this, bookslist);
top.setAdapter(staggeredBooksAdapter);
//Recycleview
top.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState); }
#Override public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int lastItem = llm.findLastCompletelyVisibleItemPosition();
if(lastItem == llm.getItemCount()-1){
mHandler.removeCallbacks(SCROLLING_RUNNABLE);
Handler postHandler = new Handler();
postHandler.postDelayed(new Runnable() {
#Override
public void run() {
top.setAdapter(null);
top.setAdapter(staggeredBooksAdapter);
mHandler.postDelayed(SCROLLING_RUNNABLE, 6000);
}}, 6000);
}
}
});
mHandler.postDelayed(SCROLLING_RUNNABLE, 6000);
and my adapter class is
public class TopAdapter extends RecyclerView.Adapter<TopAdapter.MyViewHolder> {
ArrayList<location> bookslist;
CardView cv;
location g;
private Home context;
public TopAdapter(Home context, ArrayList<location> bookslist){
this.bookslist = bookslist;
this.context = context; // add this as a field in your adapter class.
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_top,parent,false);
return new MyViewHolder(v);
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView teacher_name,teacher_location;
LinearLayout profile_details;
ImageView iv;
MyViewHolder(final View itemView) {
super(itemView);
cv = (CardView) itemView.findViewById(R.id.teacher_name);
teacher_location = (TextView)
}
}
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
database = FirebaseDatabase.getInstance();
g = bookslist.get(position);
holder.teacher_name.setText(g.getSellername());
holder.profile_details.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
g = bookslist.get(position);
Intent intent = new Intent(v.getContext(), gender_details.class);
intent.putExtra(KEY_NAME, g.getSellername());
v.getContext().startActivity(intent);
}
});
#Override
public int getItemCount() {
return bookslist.size();
}
}
When I repetitively click, I am able to opens new activity with details based on position but I have no idea how It is happening and I can only reproduce same effect only after repeatedly clicking some item. But it doesn't happen often. I'm looking for permanent solution to opens new activity when I click any item from list of recycleview in one click.
Thanks in advance.
Your onClickListener setted for view with name profile_details and it is triggered only when you tap on (exactly) this view. Some of your elements may overlap this view, so your tap not work. It's explain what your startActivity triggered after some random number of taps in different parts of item.
Try to debug clicks on view and set this onItemClickListener to appropriate View/ViewGroup
P.S:
Also my advice is to not store any database related objects inside adapter (it's violation of single responsibility).
Also is bad practice to store activity start logic in adapter. See this answer: Can't resolve the Context or Application while navigating from Adapter of a fragment(A) to another Fragment (B)
Hope it will help :)
I have 3 RecyclerView to display most visited market, close by markets and favorite markets.
I have created 3 difference instance of MarketAdapter class for the three RecyclerView
Everything works fine, but my Activity implements one OnClickListener and I cant figure out which adapter was clicked. Is it possible to programmatically determine the Adapter that was clicked from the OnClickListener?
Here is my MarketAdapter Class
public class MarketAdapter extends RecyclerView.Adapter<MarketAdapter.ViewHolder> {
ArrayList<Markets> mMarket = new ArrayList<>();
Context mContext;
private final MarketsItemsClickListener mItemsClickListener;
private final MarketLongClickListener mLongClickListener;
private final MarketClickListener mClickListener;
public MarketAdapter(Context context, MarketsItemsClickListener itemsClickListener, MarketClickListener clickListener, MarketLongClickListener longClickListener){
mContext = context;
mItemsClickListener = itemsClickListener;
mLongClickListener = longClickListener;
mClickListener = clickListener;
}
public interface MarketLongClickListener{
void onLongClick(int position);
}
public interface MarketClickListener{
void onClick(int position);
}
public interface MarketsItemsClickListener{
void imageViewOnClickListener(View view, int position);
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
Context context = viewGroup.getContext();
int layoutForListItem = R.layout.list_market;
LayoutInflater inflater = LayoutInflater.from(context);
boolean shouldAttachToParentImmediately = false;
View view = inflater.inflate(layoutForListItem, viewGroup, shouldAttachToParentImmediately);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, int i) {
viewHolder.bindView(i);
}
#Override
public int getItemCount() {
if(mMarket != null) return mMarket.size();
return 0;
}
public void setData(ArrayList<Markets> markets){
mMarket = markets;
notifyDataSetChanged();
}
public void addData(Markets market, int position){
mMarket.add(0, market);
notifyDataSetChanged();
}
public Markets getItem(int position){return mMarket.get(position);}
class ViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener, View.OnClickListener{
ImageView mImageView;
TextView mNameTextView, mCityTextView;
public ViewHolder(#NonNull View itemView) {
super(itemView);
mImageView = itemView.findViewById(R.id.image_view);
mNameTextView = itemView.findViewById(R.id.name_text_view);
mCityTextView = itemView.findViewById(R.id.city_text_view);
itemView.setOnLongClickListener(this);
itemView.setOnClickListener(this);
}
void bindView(int position){
Markets market = getItem(position);
mCityTextView.setText(market.getCity());
mNameTextView.setText(market.getName());
}
#Override
public void onClick(View v) {
//Get position of Adapter
int position = getAdapterPosition();
//Handle the click
mClickListener.onClick(position);
}
#Override
public boolean onLongClick(View v) {
return false;
}
}
}
and OnClickListener from Activity
#Override
public void onClick(int position) {}
You can pass a tag in the constructor and get that tag back via a click listener to identify the click as
private final MarketsItemsClickListener mItemsClickListener;
private final MarketLongClickListener mLongClickListener;
private final MarketClickListener mClickListener;
private final String mTag;
public MarketAdapter(Context context, MarketsItemsClickListener itemsClickListener, MarketClickListener clickListener, MarketLongClickListener longClickListener, String tag){
mTag = tag
mContext = context;
mItemsClickListener = itemsClickListener;
mLongClickListener = longClickListener;
mClickListener = clickListener;
}
Modify the listener as
public interface MarketClickListener{
void onClick(int position, String tag);
}
and the listener code in activity as
#Override
public void onClick(int position, String tag) {
switch(tag){
case "adapter1":
break;
case "adapter2":
break;
case "adapter3":
break;
}
}
and create adapter object as
MarketAdapter adapter = new MarketAdapter("adapter1"....);
MarketAdapter adapter1 = new MarketAdapter("adapter2"....);
MarketAdapter adapter2 = new MarketAdapter("adapter3"....);
and use
mClickListener.onClick(position, mTag);
Note: You can use enums as well
You can add a attribute inside MarketAdapter so that you can tell what instance is that adapter.
Change your custom click listener to receive the adapter type:
public interface MarketClickListener {
//You can change this to receive any data you want from the adapter
void onClick(int position, int adapterType);
}
Add the constants, the identifier attribute and change the listener in your adatper:
public class MarketAdapter extends RecyclerView.Adapter<MarketAdapter.ViewHolder> {
//The constants types
public static int MOST_VISITED_MARKETS = 1;
public static int CLOSE_BY_MARKETS = 2;
public static int FAVORITE_MARKETS = 3;
//New attribute
private int adapterType;
...
//Keep the listener
private final MarketClickListener mClickListener;
public MarketAdapter(Context context, MarketsItemsClickListener itemsClickListener, MarketClickListener clickListener, MarketLongClickListener longClickListener, int adapterType){
...
//Set the type
adapterType = adapterType;
}
...
}
In your activity:
mostVisitedRecyclerView.setAdapter(new MarketAdapter(this,itemsClickListener,clickListener,longClickListener,MarketAdapter.MOST_VISITED_MARKETS ));
closeByRecyclerView.setAdapter(new MarketAdapter(this,itemsClickListener,clickListener,longClickListener,MarketAdapter.CLOSE_BY_MARKETS));
favoritesRecyclerView.setAdapter(new MarketAdapter(this,itemsClickListener,clickListener,longClickListener,MarketAdapter.FAVORITE_MARKETS));
In your view holder, change the onClick:
#Override
public void onClick(View v) {
//Get position of Adapter
int position = getAdapterPosition();
//Handle the click
mClickListener.onClick(position,adapterType);
}
I didn't test this but I think it will do the trick. Try it out.
If you want to do it this way, I would add a new variable to the adapters constructor, and then use a case/if statement to determine what you want to do in your onbindviewholder.
So I have created a generic PageAdapter to be used in various parts on the app, which looks like this:
public class ImagePagerAdapter extends PagerAdapter {
private final LayoutInflater layoutInflater;
private final Picasso picasso;
private final int layoutResId;
private final List<AssociatedMedia> images;
public ImagePagerAdapter(Context context, int layoutResId) {
layoutInflater = LayoutInflater.from(context);
picasso = Injector.getInstance().getPicasso();
this.layoutResId = layoutResId;
this.images = new ArrayList<>();
}
public void setMedia(List<AssociatedMedia> media) {
images.clear();
for (AssociatedMedia productMedia : media) {
if (productMedia.type == AssociatedMediaType.IMAGE) {
images.add(productMedia);
}
else {
// non-images all at the end
break;
}
}
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
AssociatedMedia image = images.get(position);
ImageView imageView = (ImageView) layoutInflater.inflate(layoutResId, container, false);
container.addView(imageView);
picasso.load(Uri.parse(image.urls[0])).into(imageView);
return imageView;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
ImageView imageView = (ImageView) object;
container.removeView(imageView);
picasso.cancelRequest(imageView);
}
#Override
public int getCount() {
return images.size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
I then call this adapter in a fragment, like this:
ImagePagerAdapter productImageAdapter = new ImagePagerAdapter(getActivity(), R.layout.photo_container_small);
productImageAdapter.setMedia(medias);
productImage.setAdapter(productImageAdapter);
My question is, how can I invoke a onClickListener in the fragment. So my scenario is that, we have a carousel of images, and once the user click on an image, it will open a large view on that image, so sort of need an onItemClickListener, but this can only be invoked in the pagerAdapter.
So is there a way to either call a onClickListener in the fragment, or notify the fragment from the adapter when an item has been clicked?
This is a response to your comment. For formating and size reasons I use an answer for it. It is a general example on how to use an interface to de-couple a fragment from an adapter class which makes the adapter re-usable in several fragments (and even other projects).
public class MyAdapter {
MyAdapterListener listener;
private MyAdapter() {}
public MyAdapter(MyAdapterListener listeningActivityOrFragment) {
listener = listeningActivityOrFragment;
}
}
public interface MyAdapterListener {
void somethingTheFragmentNeedsToKnow(Object someData);
}
public class SomeFragment extends Fragment implements MyAdapterListener {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.my_view, container, false);
// Do everyhting here to init your view.
// Create an Adapter and bind it to this fragment
MyAdapter myAdapter = new MyAdapter(this);
return view;
}
// Implement the listener interface
#Override
public void somethingTheFragmentNeedsToKnow(Object someData) {
// Get the data and process it.
}
}
So in your case the method within the interface may well be onClick(int position); If you need more than one method, then just add them.