Loading Array of images horizontally in recyclerview using Glide - android

I have a recyclerview.I am trying to load images horizontally int o it but i keeping getting the foll error
You must provide a Model of a type for which there is a registered ModelLoader, if you are using a custom model, you must first call Glide#register with a ModelLoaderFactory for your custom model class
I tried searching a lot but couldn't get an answer that would help me.Following is my code
public class Images {
public String[] imageUrl;
public String[] getImageUrl() {
return imageUrl;
}
public void setImageUrl(String[] imageUrl) {
this.imageUrl = imageUrl;
}
public Images(String[] imageUrl) {
this.imageUrl = imageUrl;
}
}
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {
private Context context;
private List<Images> imagesList;
public class MyViewHolder extends RecyclerView.ViewHolder {
public ImageView recyclerimageView;
public MyViewHolder(View view) {
super(view);
recyclerimageView=(ImageView)view.findViewById(R.id.recyclerlistitemimageview);
}
}
public RecyclerAdapter(Context context,List<Images> imagesList){
this.context=context;
this.imagesList=imagesList;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recyclerlistitem, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
// Glide.with(context).load(myarr).into(holder.recyclerimageView);
Images images=imagesList.get(position);
Glide.with(context).load(images.getImageUrl()).into(holder.recyclerimageView);
}
#Override
public int getItemCount() {
return imagesList.size();
// return myarr.length;
}
}
public class Arrayclass {
public static String activa3gimage3[]={"https://firebasestorage.googleapis.com/v0/b/venetian-honda-179411.appspot.....",
"https://firebasestorage.googleapis.......",
"https://firebasestorage.googleapis....",
"https://firebasestorage.googleapis......"};
}
I have uploaded my image to server and taking the uri of images in activa3gimage3 array
public class ModelLineUpInnerActivity extends AppCompatActivity {
private List<Images> imagesList = new ArrayList<>();
private RecyclerView recyclerView;
private RecyclerAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_model_line_up_inner);
recyclerView=(RecyclerView)findViewById(R.id.recyclerview);
Images images=new Images(Arrayclass.activa3gimage3);
imagesList.add(images);
mAdapter = new RecyclerAdapter(ModelLineUpInnerActivity.this,imagesList);
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, true));
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(mAdapter);
}
}
I know that the error is beacause of Glide and i am trying to load array of images into it,but don't know how to resolve it.Any help will be appreciated.

You need to use single url to download and load image into single image using array with index so use
Glide.with(context).load(images.getImageUrl()[position]).into(holder.recyclerimageView);
// ^^^^^^^^^^
Update :
Your list is containing only single item so you need to modify list with all the items in it
Images images=new Images(Arrayclass.activa3gimage3);
imagesList.add(images); // single item so single view
Use List<String> and eliminate use of Images because your adapter only needs String url to load images.
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {
private Context context;
private List<String> imagesList;
// use String list
public RecyclerAdapter(Context context,List<String> imagesList){
this.context=context;
this.imagesList=imagesList;
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Glide.with(context).load(imagesList.get(position)).into(holder.recyclerimageView);
}
#Override
public int getItemCount() {
return imagesList.size();
}
// ... code
and setup adapter like
private List<String> imagesList = new ArrayList<>();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_model_line_up_inner);
recyclerView=(RecyclerView)findViewById(R.id.recyclerview);
imagesList.addAll(new ArrayList<>(Arrays.asList(Arrayclass.activa3gimage3)));
mAdapter = new RecyclerAdapter(ModelLineUpInnerActivity.this,imagesList);
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, true));
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(mAdapter);
}

images.getImageUrl() is array, and you need a String with url of your image
Use List<String> instead of List<Images> (also update it in your RecyclerAdapter & ModelLineUpInnerActivity)
private List<String> imagesList = new ArrayList<>();
Add your urls in this list, like this:
imagesList.addAll(Arrays.asList(Arrayclass.activa3gimage3));
After that you can load your image:
String image = imagesList.get(position);
Glide.with(context).load(image).into(holder.recyclerimageView);

Related

Get item fully visible or not in Recyclerview adapter

I am making an android app in which RecyclerView consist list of GIFs, Now I want to develop such functionality like when GIF item is completely visible to the user then and then it starts loading, once it slightly looses the focus of user it should stop loading.
I have displayed GIF in recyclerview now the only part remain is how to get that such GIF is fully visible or looses focus. I want such code inside adapter which indicated that this item is fully visible and this item looses focus.
MY Adapter class
public class FeedAdapter extends RecyclerView.Adapter<FeedAdapter.MyViewHolder> {
private List<FeedModel> feedList;
Context context;
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.single_item, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
holder.setData(feedList.get(position));
new GifDataDownloader() {
#Override
protected void onPostExecute(final byte[] bytes) {
holder.gifImageView.setBytes(bytes);
holder.gifImageView.startAnimation();
}
}.execute(feedList.get(position).getUrl());
}
public FeedAdapter(Context context, List<FeedModel> feedList) {
this.feedList = feedList;
this.context = context;
}
#Override
public int getItemCount() {
return feedList.size();
}
public void setGridData(ArrayList<FeedModel> feedList) {
this.feedList = feedList;
notifyDataSetChanged();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
FeedModel item;
GifImageView gifImageView;
public MyViewHolder(View itemView) {
super(itemView);
gifImageView = itemView.findViewById(R.id.gifImageView);
}
public void setData(FeedModel item) {
this.item = item;
}
}
My activity
public class MainActivity extends AppCompatActivity {
ImageView imageView;
ImageView imageView1;
private PendingIntent pendingIntent;
RecyclerView recyclerView;
FeedAdapter mAdapter;
ProgressBar progressBar;
GridLayoutManager manager;
Spinner countrySpinner;
ArrayList<FeedModel> feedList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
feedList = new ArrayList<>(10);
for (int i = 0; i < 10; i++) {
FeedModel feedModel = new FeedModel();
feedModel.setUrl("https://media.tenor.com/images/925bfbaad2f947987bcf18b9167b3326/tenor.gif");
feedList.add(feedModel);
}
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mAdapter = new FeedAdapter(getApplicationContext(), feedList);
manager = new GridLayoutManager(getApplicationContext(), 1, GridLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(manager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setVisibility(View.VISIBLE);
recyclerView.setAdapter(mAdapter);
}
Better way to used glide to show image and gif etc. it is take all senior that you define .
Add below dependency into app level gradle file
implementation 'com.github.bumptech.glide:glide:4.7.1'
then after used in adapter like this way..
private Context context;
// define context into constructor
public RecyclerviewAdapter(List<StepsItem> stepsItems, Context context) {
this.stepsItems = stepsItems;
this.context = context;
}
Glide.with(context).load(yoururl).into(holder.mIvIcon);
Start gif after your view is created like in onstart() method
And when you want to stop the gif when user is no more interact with app , stop the gif in onpause() method.

RecyclerView not populating with data

I am trying to load recyclerview with data from SQLite database contents. But it is not working
This is what i have done
Activity class
public class ViewMembership extends AppCompatActivity {
private RecyclerView recyclerView;
private membership_view_recycler_adapter m;
private DBHelper dbHelper;
public List<membership_recycler_model> membershipList=new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_membership);
dbHelper=new DBHelper(this);
////////////////////////////////////////////////////////////////////////////
recyclerView=(RecyclerView) findViewById(R.id.View_Membership_Recycler);
m=new membership_view_recycler_adapter(membershipList);
RecyclerView.LayoutManager layoutManager=new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));
recyclerView.setAdapter(m);
prepare_membership();
//////////////////////////////////////////////////////////////////////////
}
public void prepare_membership()
{
System.out.println("#######################Prepare_membership called");
membershipList=dbHelper.membership_for_recycler_view();
m.notifyDataSetChanged();
}}
Adapter class
public class membership_view_recycler_adapter extends RecyclerView.Adapter<membership_view_recycler_adapter.MyViewHolder> {
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView name,region;
public MyViewHolder(View itemView) {
super(itemView);
name=(TextView) itemView.findViewById(R.id.membership_name_textview);
region=(TextView) itemView.findViewById(R.id.membership_region_textview);
}
}
public membership_view_recycler_adapter(List<membership_recycler_model> membership_list) {
this.membership_list = membership_list;
}
private List<membership_recycler_model> membership_list;
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.membership_view_row,parent,false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
membership_recycler_model membership=membership_list.get(position);
holder.name.setText(membership.getMembership_name());
holder.region.setText(membership.getRegion());
}
#Override
public int getItemCount() {
return membership_list.size();
}}
I've got no compilation errors, application is not throwing any exceptions. dbHelper.membership_for_recycler_view() is returning appropriate values. I am kinda new in Android. I did this with the help of a tutorial. What have I done wrong?
I think the problem here is you are calling prepare_membership()
function later and passing data to your adapter before with an empty list. Try to make following changes :
Add a new method in your adapter -
public void refreshData(List<membership_recycler_model> membership_list){
this.membership_list = membership_list;
notifyDataSetChanged();
}
Inside your prepare_membership() function call this method after fetching the list from db i.e m.refreshData(membershipList)
`

RecycleView displays data only first time

I have a RecycleView to which I give an Array of Post objects. When it's loaded first time, everything works fine but trying to replace the data or just entering in the Fragment again then the RecycleView does not show anything. Also I have checked the size of the new data and it's different from zero. Here is my code:
// Init the list
list = (RecyclerView) view.findViewById(R.id.list);
list.setLayoutManager(new LinearLayoutManager(mContext));
...
if (adapter != null) {
adapter.replaceCurrentPosts(new ArrayList<>(postList));
}
else {
adapter = new PostAdapter(mContext, new ArrayList<>(postList), this);
list.setAdapter(adapter);
}
...
public PostAdapter(Context context, List<Post> posts, onPostElementClickListener listener) {
this.context = context;
this.posts = posts;
this.mListener = listener;
}
public void replaceCurrentPosts(List<Post> newPosts) {
this.posts.clear();
this.posts.addAll(newPosts);
this.notifyDataSetChanged();
}
#Override
public int getItemCount() {
return posts.size();
}
package com.example.jiteshmohite.myapplication;
public class PostAdapter extends RecyclerView.Adapter {
private Context context;
private List<Post> posts;
private onPostElementClickListener mListener;
// 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 ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView mTextView;
public ViewHolder(View v) {
super(v);
mTextView = (TextView) v.findViewById(R.id.info_text);
}
}
public PostAdapter(Context context, List<Post> posts, onPostElementClickListener listener) {
this.context = context;
this.posts = posts;
this.mListener = listener;
}
public void replaceCurrentPosts(List<Post> newPosts) {
posts.clear();
posts = newPosts;
this.notifyDataSetChanged();
}
#Override
public PostAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.my_text_view, parent, false);
// set the view's size, margins, paddings and layout parameters
ViewHolder vh = new ViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(PostAdapter.ViewHolder holder, final int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
holder.mTextView.setText(posts.get(position).getName());
holder.mTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mListener.onClick(position);
}
});
}
#Override
public int getItemCount() {
return posts.size();
}
interface onPostElementClickListener {
public void onClick(int pos);
}
}
private RecyclerView list;
private PostAdapter postAdapter;
private RecyclerView.LayoutManager layoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler_example);
list = (RecyclerView) findViewById(R.id.list);
layoutManager = new LinearLayoutManager(getApplicationContext());
list.setLayoutManager(layoutManager);
postAdapter = new PostAdapter(getApplicationContext(), getPostData(), listener);
list.setAdapter(postAdapter);
}
private PostAdapter.onPostElementClickListener listener = new PostAdapter.onPostElementClickListener() {
#Override
public void onClick(int pos) {
Toast.makeText(getApplicationContext(), pos + "" , Toast.LENGTH_SHORT).show();
List<Post> posts = getPostData();
posts.get(pos).setName("abc");
postAdapter.replaceCurrentPosts(posts);
}
};
// get post list which contains name
public List<Post> getPostData() {
Post post = new Post();
post.setName("xyz");
List<Post> posts = new ArrayList<Post>();
posts.add(post);
posts.add(post);
posts.add(post);
posts.add(post);
posts.add(post);
return posts;
}
}
I suggesting rather then notifyDataSetChanged() you should refer notifyItemChange which modify specific positions.
please let me know if it is not work for you.
why don't you try to add one element (or maybe more) instead of remove all and re-add all items?

Custom methods in adapter are not resolving in android

I have 2 methods inside of adapter class.
addValues(brandMap);
setBrandMap(brandMap);
that I'm trying to call after async call. However, the compiler is complaining that it cannot resolve these methods. What is the issue?
This is complete class.
public class FragmentBrandList extends ListFragment {
private String TAG = getClass().getSimpleName();
private Map<String, Brand> brandMap = new ConcurrentHashMap<>();
private RecyclerView.Adapter adapter;
private FirebaseDatabase database = FirebaseDatabase.getInstance();
private RecyclerView recyclerView;
private Query query = database.getReference("brands").orderByChild("name");
public FragmentBrandList() {
}
public static FragmentBrandList newInstance(int num) {
FragmentBrandList f = new FragmentBrandList();
// Supply num input as an argument.
Bundle args = new Bundle();
args.putInt("num", num);
f.setArguments(args);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.recycler_list, container, false);
recyclerView = (RecyclerView) v.findViewById(R.id.recycler_view);
RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(getActivity(), 3);
RecyclerView.setLayoutManager(mLayoutManager);
adapter = new FragmentBrandList.MyAdapter(Utility.getBrandMap(), getActivity());
recyclerView.setAdapter(adapter);
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), recyclerView, new ClickListener() {
#Override
public void onClick(View view, int position) {
Brand brand = Utility.getBrands().get(position);
Intent intent = new Intent(getActivity(), ActivityProductList.class);
intent.putExtra("BrandId", brand.getId());
startActivity(intent);
}
#Override
public void onLongClick(View view, int position) {
}
}));
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
Brand brand = dataSnapshot1.getValue(Brand.class);
brandMap.put(brand.getId(), brand);
}
Utility.setBrandMap(brandMap);
adapter.addValues(brandMap);
adapter.setBrandMap(brandMap);
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
Utility.displayToast("Failed to read value." + error.toException());
}
});
return v;
}
Adapter class
private class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private List<Brand> brandList = new ArrayList<>();
private Context context;
public class MyViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
public MyViewHolder(View view) {
super(view);
imageView = (ImageView) view.findViewById(R.id.thumbnail);
}
}
public MyAdapter(Map<String, Brand> brands, Context context) {
//public MyAdapter(List<Brand> brands, Context context) {
this.brandList = new ArrayList<>(brandMap.values());
//this.brandList = brands;
this.context = context;
}
public void setBrandMap(Map<String, Brand> brandMap){
this.brandList = new ArrayList<>(brandMap.values());
notifyDataSetChanged();
}
public void addValues(Map<String, Brand> brands){
brandList.clear();
brandList.addAll(brands.values());
notifyDataSetChanged();
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.card_brand, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
if (brandList != null && brandList.size() > 0) {
Brand brand = brandList.get(position);
Glide.with(context).load(String.valueOf(brand.getImage()))
.error(R.drawable.placeholder)
.placeholder(R.drawable.placeholder)
.into(holder.imageView);
}
}
#Override
public int getItemCount() {
return brandList.size();
}
}
You have declared your adapter field as:
private RecyclerView.Adapter adapter;
That means wherever you use it, you'll see it as just a RecyclerView.Adapter, which doesn't have your custom methods on it. It doesn't matter that you've assigned there a subclass of RecyclerView.Adapter that has extra methods. It is because you might've assigned there a different subclass that didn't have those methods.
If you want to use your custom methods then change the declaration to:
private MyAdapter adapter;
Then you can use all methods declared in MyAdapter and inherited from superclasses. The tradeoff is that you cannot assign there any other subclass of RecyclerView.Adapter, but thanks to that compiler can know you can always use your extra methods.
The problem is this line.
private RecyclerView.Adapter adapter;
As you are holding your custom adapter object in the Base reference, hence those methods of your custom adapter is not visible to you. Change the reference to the type of your Custom Adapter and it should work fine.

RecyclerView Adapter not updating view content

I having a recyclerview with GridLayoutManager, it populating the grid properly but not updating the data.
Below is my code,
public class AppsGridViewAdapter extends RecyclerView.Adapter<AppsGridViewAdapter.GridViewHolder>{
private ArrayList<App> appArrayList;
private Context context;
public AppsGridViewAdapter(Context context,ArrayList<App> appArrayList){
this.appArrayList = appArrayList;
this.context = context;
}
public static class GridViewHolder extends RecyclerView.ViewHolder{
CompoundAppButton compoundAppButton;
public GridViewHolder(CompoundAppButton itemView){
super(itemView);
compoundAppButton = (CompoundAppButton)itemView;
}
}
#Override
public GridViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
CompoundAppButton appButton = new CompoundAppButton(context,null);
return new GridViewHolder(appButton);
}
#Override
public void onBindViewHolder(GridViewHolder holder, int position) {
App app = appArrayList.get(position);
holder.compoundAppButton.updateButtonConfig(app);
}
#Override
public int getItemCount() {
return appArrayList.size();
}
}
Having valid values in the list, but not updating. Where CustomAppButton is a customview. Anyone can help me why it doesnt update.
UPDATE:
I calling recyclerview from my activity, below is the specific code
recyclerView = (RecyclerView)findViewById(R.id.recycler_view);
recyclerView.addItemDecoration(new MarginDecoration(this));
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
AppsGridViewAdapter adapter = new AppsGridViewAdapter(this,appList);
recyclerView.setAdapter(adapter);
The activity contains only recyclerview.
updateButtonConfig is a function in CustomAppButton class, this is where view is updated. getting data to this function, have checked the log.
public void updateButtonConfig(App app){
Picasso.with(context)
.load(app.getAppIcon())
.placeholder(R.drawable.app_icon)
.into(appIcon);
appName.setText(app.getAppName());
category.setText(app.getAppCategory());
price.setText(app.getAppPrice());
appPackage = app.getAppPackage();
}

Categories

Resources