RecyclerView with setOnClickListener - android

I'm using Firebase as a database and a preview to get information about the saved data, now I can bring both the image and the name of that image in my view, but now I would like to be able to click on the quick view and open a new fragment or activity where the same image or publication can be displayed that is clicked, that is, the photo, the name and the power to include other data within that new fragment or activity when clicking on the recyclerview post.
In a few words for example: a clothing store, you have a recycling view with your products and your name, click on that product opens but with all the other details and specifications you have.
I am currently using: Firebase navigation button with fragments
Fragment where the recyclerview is shown:
mRecyclerView = v.findViewById(R.id.recycler_view);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mUploads = new ArrayList<>();
mDatabaseRef = FirebaseDatabase.getInstance().getReference("Posts");
mDatabaseRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
Uploads uploads = postSnapshot.getValue(Uploads.class);
mUploads.add(uploads);
}
mAdapter = new ImageAdapter(getActivity(), mUploads);
mRecyclerView.setAdapter(mAdapter);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});return v;
//adapter code
public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ImageViewHolder> {
private Context mContext;
private List<Uploads> mUploads;
public ImageAdapter(Context context, List<Uploads> uploads) {
mContext = context;
mUploads = uploads;
}
#Override
public ImageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(mContext).inflate(R.layout.home_item, parent, false);
return new ImageViewHolder(v);
}
#Override
public void onBindViewHolder(ImageViewHolder holder, final int position) {
Uploads uploadCurrent = mUploads.get(position);
holder.textViewName.setText(uploadCurrent.getName());
Picasso.get()
.load(uploadCurrent.getImageUrl())
.placeholder(R.mipmap.ic_launcher)
.into(holder.imageView);
}
#Override
public int getItemCount() {
return mUploads.size();
}
public class ImageViewHolder extends RecyclerView.ViewHolder {
public TextView textViewName;
public ImageView imageView;
public ImageViewHolder(View itemView) {
super(itemView);
textViewName = itemView.findViewById(R.id.Descripcion);
imageView = itemView.findViewById(R.id.ImagePro);
}
}
}

You have two options.
You can create a callback interface and trigger the callback method from your Adapter's onClick. The activity or fragment that implemented the interface and passed the instance of it to the Adapter will get the callback and you can launch a quick view from there. I prefer this method.
Here you can find a detailed example to achieve this.
Since you already have Context in your class, you can directly reference a method in an Activity or Fragment and create a quick view Fragment from there.
public void onBindViewHolder(ImageViewHolder holder, final int position) {
((YourActivity) context).startQuickviewFragment();
}

Related

Issue on BillingClient.queryProductDetailsAsyn when call adapter.notifyDataSetChanged()

When I do adapter.notifyDataSetChanged() into
onProductDetailsResponse it seems that the callback stays pending and the Recycleview doesn't show anything
I'm upgrading the Google Play Billing Library on my app, form 3 highter, I've the same issue on 4.1 and 5.
I retrieve my Subscriptions as Google require:
Define my productId
List<String> skuList = Application.getSubscritionsSkuList();
for (String sku : skuList) {
List<Product> productList.add(Product.newBuilder()
.setProductId(sku)
.setProductType(BillingClient.ProductType.SUBS)
.build());
Define my RecycleView and set My adapter
RecyclerView recyclerView = getActivity().findViewById(R.id.SubscritionsList);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
SubscriptionAdapter subscriptionAdapter = new SubscriptionAdapter(
context.getApplicationContext(), getActivity(), inventoryAsyncSub);
recyclerView.setAdapter(subscriptionAdapter);
Then retrieve the Subscriptions form the Store
QueryProductDetailsParams params = QueryProductDetailsParams.newBuilder()
.setProductList(productList)
.build();
billingClient.queryProductDetailsAsync(
params,
new ProductDetailsResponseListener() {
public void onProductDetailsResponse(BillingResult billingResult, List<ProductDetails> productDetailsList) {
inventoryAsyncSub.addAll(productDetailsList);
subscriptionAdapter.notifyDataSetChanged();
}
}
);
The issue is: when I do subscriptionAdapter.notifyDataSetChanged() it seems that the callback from queryProductDetailsAsync stays pending and the Recycleview doesn't show anything till I scroll it and navigating out from this Fragment the app stays waiting something: no other callback works
First I thought that it depend form deprecated method querySkuDetailsAsync() so following the Google guide I migrated to queryProductDetailsAsync method, but the issue still persist.
My Adapter has got any of characteristic:
public class SubscriptionAdapter extends RecyclerView.Adapter<SubscriptionAdapter.Viewholder>{
public Object setOnItemClickListener;
private Context context;
private Activity activity;
private List<ProductDetails> InventoryAsyncSub;
private static ClickListener clickListener;
public SubscriptionAdapter(
Context context,
Activity activity,
List<ProductDetails> InventoryAsyncSub
) {
this.context = context;
this.activity = activity;
this.InventoryAsyncSub = InventoryAsyncSub;
}
#NonNull
#Override
public SubscriptionAdapter.Viewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.subscrition_card, parent, false);
return new Viewholder(view);
}
#Override
public void onBindViewHolder(#NonNull SubscriptionAdapter.Viewholder holder, int position) {
ProductDetails subScr = InventoryAsyncSub.get( position );
PurchaseHandlerTools.setItemTitle( activity, holder.name, subScr.getTitle() );
holder.description.setText( subScr.getDescription() );
holder.pricesBox.findViewById( R.id.item_price);
TextView price = holder.pricesBox.findViewById( R.id.item_price);
price.setText( subScr.getSubscriptionOfferDetails().get(0).getPricingPhases().getPricingPhaseList().get(0).getFormattedPrice() );
}
#Override
public int getItemCount() {
return InventoryAsyncSub.size();
}
// stores and recycles views as they are scrolled off screen
public class Viewholder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView name;
private TextView description;
private LinearLayout pricesBox;
public Viewholder(#NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.submition_name);
description = itemView.findViewById(R.id.submition_description);
pricesBox = itemView.findViewById(R.id.purchase_btn);
itemView.setOnClickListener( this::onClick );
}
#Override
public void onClick(View v) {
clickListener.onItemClick( getAdapterPosition(), v );
}
}
public void setOnItemClickListener(ClickListener clickListener) {
SubscriptionAdapter.clickListener = clickListener;
}
public interface ClickListener{
void onItemClick( int position, View view );
}
}

why png files are not loading into recyclerview

I am currently working at a Android project, where I have to upload png files into Firebase Realtime-database. My app is retrieving images but when I used png files it's loading only five png files, I don't know what happened to the other png files.
When I make an edit with the image url one of the another image turn not working and the one I edited started to work.
I am using Picasso library to view the images...
Does anybody else encountered the same error...
I should complete the project as soon as possible
Should this problem solves if I use glide instead of picasso???
myadapter.java
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private DatabaseReference reference;
static Context context;
static ArrayList<Profile> profiles;
public MyAdapter(Context c, ArrayList<Profile> p) {
context = c;
profiles = p;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.recyclerview_item, parent, false));
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
holder.title.setText(profiles.get(position).getTitle());
holder.desc.setText(profiles.get(position).getDesc());
Picasso.get().load(profiles.get(position).getImage()).into(holder.image);
}
#Override
public int getItemCount() {
return profiles.size();
}
static class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView title, desc;
ImageView image;
Button btn;
public MyViewHolder(View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.title);
desc = (TextView) itemView.findViewById(R.id.desc);
image = (ImageView) itemView.findViewById(R.id.image);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
Intent intent = new Intent(context, Main2Activity.class);
intent.putExtra("URL", profiles.get(getAdapterPosition()).getImage());
context.startActivity(intent);
}
}
}
mainactivity.java
public class helmet extends AppCompatActivity {
DatabaseReference reference;
RecyclerView recyclerView;
ArrayList<Profile> list;
public MyAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_helmet);
recyclerView = (RecyclerView) findViewById(R.id.recyclle);
int numberOfColumns = 3;
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.HORIZONTAL));
recyclerView.setLayoutManager(new GridLayoutManager(this, numberOfColumns));
reference = FirebaseDatabase.getInstance().getReference().child("helmet");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
list = new ArrayList<Profile>();
for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
Profile p = dataSnapshot1.getValue(Profile.class);
list.add(p);
}
adapter = new MyAdapter(helmet.this, list);
recyclerView.setAdapter(adapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(helmet.this, "Opsss.... Something is wrong", Toast.LENGTH_SHORT).show();
}
});
}
....

Loading images in recycler view with Glide

I am attempting to load images from firebase into a recycler adapter and display them
I have attempted two methods to try and solve this problem the first block of code resulted in the error"You cannot start a load on a not yet attached View or a Fragment where getActivity() returns null (which usually occurs when getActivity() is called before the Fragment is attached or after the Fragment is destroyed)"
The second method the application ran but no images were loaded from reading other similar issues I have seen the isAdded() check but I couldn't seem to get that to work the images are being uploaded into a folder in firebase called post_images and the rest of the data associated with the post (Instagram like app with posting) are in firestore
public BlogRecyclerAdapter(List<BlogPost> blog_list) {
this.blog_list = blog_list;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.blog_list_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
String desc_data = blog_list.get(position).getDesc();
holder.setDescText(desc_data);
String image_url = blog_list.get(position).getImage_url();
holder.setBlogImage(image_url);
}
#Override
public int getItemCount() {
return blog_list.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private View mView;
private TextView descView;
private ImageView blogImageView;
public Context mContext;
public ViewHolder(View itemView) {
super(itemView);
mView = itemView;
}
public void setDescText(String descText) {
descView = mView.findViewById(R.id.blog_desc);
descView.setText(descText);
}
public void setBlogImage(final String downloadUri) {
blogImageView = mView.findViewById(R.id.Post_image_view);
Glide.with(mContext).load(downloadUri).into(blogImageView);
}}}
Other method attempted
mCurrentUser = FirebaseAuth.getInstance().getCurrentUser();
mImageStorage = FirebaseStorage.getInstance().getReference();
final String current_uid = mCurrentUser.getUid();
mUserDatabase = FirebaseDatabase.getInstance().getReference().child("Users").child(current_uid);
mUserDatabase.keepSynced(true);
mUserDatabase.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
StorageReference filepath = mImageStorage.child("profile_images").child(current_uid + (".jpeg"));
Log.d("heere", "S");
// This gets the download url async
filepath.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
//The download url
final String downloadUrl = uri.toString();
Log.d("tag", downloadUrl);
if (!downloadUrl.equals("default")) {
Glide.with(mContext).load(downloadUrl).into(blogImageView);
// Glide.with(getApplicationContext()).load(downloadUrl).into(mDisplayImage);
}
}});}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});}}}
I would like the image to be displayed in the recycler view
Change this line
Glide.with(mContext).load(downloadUri).into(blogImageView);
to this instead:
Glide.with(itemView.getContext()).load(downloadUri).into(blogImageView);
All ViewHolder instances have a field itemView that is guaranteed to be non-null, and you can get the context from that.
Your mContext is not initialized
mContext must be a RecyclerView.Adapter global variable and not a ViewHolder variable
mContext must initialize in onCreateViewHolder function this way
this.mContext = parent.getContext();

Listener only adds last image in list to the RecyclerView

I get a Data snapshot of the user's ids. These ids are also the same as the image ids of the matching profile pictures of the users.
I want to populate the RecyclerView with each image that matches the RecyclerView, but what happens is, that it populate the correct user id, but it only populates the last image in the list of the data snapshot instead of all. So I end up with a list of user ids and a single image at the bottom:
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
imageName = ds.getKey();
user = new User(imageName);
myDataset.add(user);
storageReference.child("profileImages").child(imageName).getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
user.setImageUri(uri);
// Got the download URL
mAdapter.notifyDataSetChanged();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
// Handle any errors
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
imagesRef.addListenerForSingleValueEvent(eventListener);
This is how it looks:
This is the adapter:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private ArrayList<User> mDataset;
private MyViewHolder myHolder;
private User user;
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class MyViewHolder extends RecyclerView.ViewHolder {
public TextView userIdTextView;
public ImageView userProfileImageView;
public View layout;
public MyViewHolder(View v) {
super(v);
layout = v;
userProfileImageView = (ImageView) v.findViewById(R.id.profile_image);
public TextView userIdTextView = (TextView) v.findViewById(R.id.user_id_text_view);
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(ArrayList<User> myDataset) {
mDataset = myDataset;
}
// Create new views (invoked by the layout manager)
#Override
public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler_view, parent, false);
MyViewHolder vh = new MyViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
myHolder = holder;
user = mDataset.get(position);
Uri userImage = user.getImageUri();
myHolder.userIdTextView.setText(user.getUsername());
Glide.with(myHolder.itemView.getContext() /* context */)
.load(userImage)
.apply(new RequestOptions().override(300, 300))
.into(myHolder.userProfileImageView);
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return mDataset.size();
}
}
database structure:
database
|_____users
|___uid1
|___uid2
|___uid3
Your "user" variable cannot be used in that way inside "onSuccess()" callback method. That variable refers always to the LAST "new User()", so when the "download" procedure reach the "onSuccess()" the value of "user" value is THE LATEST executed "new User()". You need to pass something like an "userID" to the download method and when the "onSuccess()" is executed you have to find the right User using that ID, and then set its image.
As getDownloadUrl is async method other user objects are changed and only last object is referenced when onSuccess() is called so last objects uri is set.
Use HashMap<String,User> userMap = new HashMap<String,User>();
Before getDownloadUrl
userMap.put(imageName,user);
in onSuccess()
User user = userMap.get(imageName);
user.setImageUri(uri);
Make imageName final.

nested recyclerview inside adapter

I am developing an android app where I have used nested RecyclerView but I am not achieving what I want.I want to achieve on this list it should show Title and below multiple images like json below how can I achieve that I am using two viewholder and it should scrool as well.
json structure
below Adapter class
public class UranAdapter extends RecyclerView.Adapter {
public List<Exhibit> exhibitList;
public Context context;
public UranAdapter(List<Exhibit> uranList, Context context) {
this.exhibitList = uranList;
this.context = context;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView;
switch (viewType) {
case Exhibit.TEXT_TYPE:
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.exhibit_list, parent, false);
return new ViewHolder(itemView);
case Exhibit.IMAGE_TYPE:
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.exhibit_list2, parent, false);
return new ImageViewHolder(itemView);
}
return null;
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder viewHolder, int i) {
}
#Override
public int getItemViewType(int position) {
return exhibitList.get(position).type;
}
public int getItemCount() {
return exhibitList.size();
}
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
Exhibit exhibit = exhibitList.get(position);
switch (exhibit.type) {
case Exhibit.TEXT_TYPE:
((ViewHolder) holder).exhibition_textView.setText(exhibit.getTitle());
break;
case Exhibit.IMAGE_TYPE:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
((ViewHolder) holder).exhibition_imageView.setImageResource(exhibit.image);
}
break;
}
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public ImageView exhibition_imageView;
TextView exhibition_textView;
public ViewHolder(View view) {
super(view);
exhibition_textView = (TextView) view.findViewById(R.id.exhibition_textview);
}
}
public static class ImageViewHolder extends RecyclerView.ViewHolder {
public ImageView exhibition_imageView;
TextView exhibition_textView;
public ImageViewHolder(View view) {
super(view);
exhibition_imageView = (ImageView) view.findViewById(R.id.exhibition_imageview);
}
}
}
below MainActivity
public class MainActivity extends AppCompatActivity {
public List<Exhibit> exhibitList = new ArrayList<>();
Context context;
RecyclerView recyclerView;
public UranAdapter uranAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ApiInterface apiInterface = ApiClient.getApiService();
Call<ExhibitsLoader> call = apiInterface.getExhibitList();
call.enqueue(new Callback<ExhibitsLoader>() {
#Override
public void onResponse(Call<ExhibitsLoader> call, Response<ExhibitsLoader> response) {
exhibitList = response.body().getExhibitList();
exhibitList.add(new Exhibit(Exhibit.IMAGE_TYPE));
RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
uranAdapter = new UranAdapter(exhibitList, context); // changes
recyclerView.setAdapter(uranAdapter);
}
#Override
public void onFailure(Call<ExhibitsLoader> call, Throwable t) {
}
});
}
}
below image what I want
I think what you need here is flatMap the embedded image list into one-level list and you're going correctly to have two ViewHolder of different types, one for title, and one for image. Don't understand why your ViewHolders are static.
You forget to call notifyDatasetChanged() after setting the adapter.
uranAdapter = new UranAdapter(exhibitList, context); // changes
recyclerView.setAdapter(uranAdapter);
uranAdapter.notifyDatasetChanged();
Use Expandable CardView for this ..
Like : https://www.youtube.com/watch?v=z9qScBaKfnM&t=727s
Why don't you use two RecyclerViews, one inside the other?
One RecyclerView will have the title and a children RecyclerView. The second RecyclerView(the children RecyclerView) will have just the images.
Check this post: Recyclerview inside Recyclerview , get click position of child row inside parent Adapter

Categories

Resources