setAdapter in recyclerView cannot be applied - java

So I followed an online tutorial to have a sort of gallery app. The pictures are shown inside a GridView but I needed to change it into a recyclerview. When I do that though I get that error and my adapter doesn't seem to work with the recyclerview. Here is my adapter code:
class AlbumAdapter extends BaseAdapter {
private Activity activity;
private ArrayList<HashMap< String, String >> data;
public AlbumAdapter(Activity a, ArrayList < HashMap < String, String >> d) {
activity = a;
data = d;
}
public int getCount() {
return data.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
AlbumViewHolder holder = null;
if (convertView == null) {
holder = new AlbumViewHolder();
convertView = LayoutInflater.from(activity).inflate(
R.layout.album_row, parent, false);
holder.galleryImage = (ImageView) convertView.findViewById(R.id.galleryImage);
holder.gallery_count = (TextView) convertView.findViewById(R.id.gallery_count);
holder.gallery_title = (TextView) convertView.findViewById(R.id.gallery_title);
convertView.setTag(holder);
} else {
holder = (AlbumViewHolder) convertView.getTag();
}
holder.galleryImage.setId(position);
holder.gallery_count.setId(position);
holder.gallery_title.setId(position);
HashMap < String, String > song = new HashMap < String, String > ();
song = data.get(position);
try {
holder.gallery_title.setText(song.get(Function.KEY_ALBUM));
holder.gallery_count.setText(song.get(Function.KEY_COUNT));
Glide.with(activity)
.load(new File(song.get(Function.KEY_PATH))) // Uri of the picture
.into(holder.galleryImage);
} catch (Exception e) {}
return convertView;
}
}
class AlbumViewHolder {
ImageView galleryImage;
TextView gallery_count, gallery_title;
}
And this is some of the code from the activity in which I set my adapter:
#Override
protected void onPostExecute(String xml) {
AlbumAdapter adapter = new AlbumAdapter(ProfileActivity.this, albumList);
galleryGridView.setAdapter(adapter);
galleryGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
final int position, long id) {
Intent intent = new Intent(ProfileActivity.this, AlbumActivity.class);
intent.putExtra("name", albumList.get(+position).get(Function.KEY_ALBUM));
startActivity(intent);
}
});
}
This is the error I'm currently getting:
Error message
I basically want to fix the adapter so that it works inside a recyclerview.

You have to create RecyclerView.Adapter to work with RecyclerView. It's bit different that BaseAdapter. Let me give you example of how to implement this.
public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder> {
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.album_row, viewGroup, false);
return new AlbumAdapter.ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
holder.galleryImage.setId(position);
holder.gallery_count.setId(position);
holder.gallery_title.setId(position);
}
#Override
public int getItemCount() {
return data.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
ImageView galleryImage;
TextView gallery_count, gallery_title;
public ViewHolder(View v) {
galleryImage = v.findViewById(R.id.galleryImage);
gallery_count =v.findViewById(R.id.gallery_count);
gallery_title = v.findViewById(R.id.gallery_title);
}
}
}

Related

How to get the item position in a ListView and GridView outside the adapter?

I'm trying to get a View position through his view hierarchy.
When I have a RecyclerView, for get the current view position I do:
if(view.getParent() instanceof RecyclerView){
RecyclerView rv = (RecyclerView)view.getParent();
if(rv.getLayoutManager()!=null) {
position = rv.getLayoutManager().getPosition(view);
}
}
But when a ListView or GridView appears, I'm not able to get a Layout Manager to get the position of the view. The idea is to make it in a generic way, without knowing the Custom Adapter the view has.
I have tried to get the position through the ListView and GridView adapter but I dont see any method that do that.
Someone can help me?
Thank you a lot!
Create interface for get position for outside adapter class
here is adapter code:
public class ReportMediaAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private ArrayList<File> reportMediaList = new ArrayList<>();
private Context context;
private int selectedPos = -1;
private OnRemoveImage onRemoveImage;
public ReportMediaAdapter(Context context, ArrayList<File> reportMediaList, OnRemoveImage onRemoveImage) {
this.reportMediaList = reportMediaList;
this.onRemoveImage = onRemoveImage;
this.context = context;
}
**public interface OnRemoveImage {
void onRemove(int pos);
}**
public class MyViewHolder extends RecyclerView.ViewHolder {
private ImageView iv_image, iv_remove;
public MyViewHolder(View itemView) {
super(itemView);
iv_image = itemView.findViewById(R.id.iv_image);
iv_remove = itemView.findViewById(R.id.iv_remove);
}
}
#Override
public int getItemCount() {
return reportMediaList.size()-1;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_media, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
try {
MyViewHolder menuItemHolder = (MyViewHolder) holder;
CommonMethods.loadImage(context, reportMediaList.get(position), menuItemHolder.iv_image);
menuItemHolder.iv_remove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
**onRemoveImage.onRemove(position);**
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
Here is activity code:
#Override
public void onRemove(int pos) {
// use adapter position
}
I have found a solution:
if(view.getParent() instanceof ViewGroup) {
position = ((ViewGroup)view.getParent()).indexOfChild(view);
}

How can i modify getItemViewType() with adapter input as a string and cursor?

I have created a recycler view and want to put two lists in it.
The first list is just a string that gets changed into fonts, which I have implemented in the onBindView method.
The second list is the cursor which includes the favorite fonts of the users.
I followed this answer on SO but I don't have any idea how I'm going to modify the getItemViewType() method so that I can get to know which list type is currently calling for view.
My adapter code
here data is the class that contains the list of fonts
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final int VIEW_TYPE_TEXTVIEW = 0;
private final int VIEW_TYPE_ITEM_1 = 1;
private int total_no_of_row;
private Context context;
private String str;
private Cursor cursor;
private final LayoutInflater inflater;
public MyAdapter(Context context, int total_no_of_row, String str , Cursor cursor) {
this.context = context;
this.total_no_of_row = total_no_of_row;
this.str = str;
this.cursor = cursor;
inflater = LayoutInflater.from(context);
}
#Override
public int getItemViewType(int position) {
return super.getItemViewType(position);
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
if(viewType == VIEW_TYPE_TEXTVIEW) {
View view = inflater.inflate(R.layout.row_layout, parent, false);
return new Item1Holder(view);
}
else if (viewType == VIEW_TYPE_ITEM_1){
View view = inflater.inflate(R.layout.row_layout, parent, false);
return new Item2Holder(view);
}
return null;
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
if(holder instanceof Item1Holder){
data d = new data();
cursor.moveToPosition(position);
Log.d("this2",cursor.getInt(1)+"");
String temp = d.Convert(str, cursor.getInt(1));
((Item1Holder)holder).textView.setText(temp);
((Item1Holder)holder).rowNumber.setText("⚫");
((Item1Holder)holder).fav.setImageResource(R.drawable.ic_baseline_favorite_24);
}else if(holder instanceof Item2Holder){
data d = new data();
String temp = d.Convert(str, position);
((Item2Holder)holder).textView.setText(temp);
((Item2Holder)holder).rowNumber.setText((position + 1) + ".");
if (util.COPY) {
if (position == util.CURRENT_POSITION) {
((Item2Holder)holder).imageView.setBackgroundResource(R.drawable.background_when_row_clicked);
} else {
((Item2Holder)holder).imageView.setBackgroundResource(R.drawable.background_when_row_clicked_two);
}
}
}
}
#Override
public int getItemCount() {
return total_no_of_row + cursor.getCount();
}
class Item1Holder extends RecyclerView.ViewHolder {
TextView textView;
ImageView imageView , fav;
TextView rowNumber;
public Item1Holder(#NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.text_body);
imageView = itemView.findViewById(R.id.copy_png);
rowNumber = itemView.findViewById(R.id.row_number);
fav = itemView.findViewById(R.id.fav);
}
}
class Item2Holder extends RecyclerView.ViewHolder {
TextView textView;
ImageView imageView , fav;
TextView rowNumber;
public Item2Holder(#NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.text_body);
imageView = itemView.findViewById(R.id.copy_png);
rowNumber = itemView.findViewById(R.id.row_number);
fav = itemView.findViewById(R.id.fav);
}
}
}
in main activity
here temp is the string that users want to convert into the fonts
Cursor cursor = show();
myAdapter = new MyAdapter(this , 500 , temp , cursor);
recyclerView.setAdapter(myAdapter);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
I'm not a professional android developer I'm still learning the stuff. so sorry if my code is too bad to understand
You are passing null in the onCreateViewHolder() method, and not specified position in getItemViewType() method. All you have to do is, update your code. do not pass the null value in the onCreateViewHolder method. Below code, I've tried, and works perfectly. Happy coding...
private static final int CATEGORY = 1;
private static final int NAME = 2;
private Collection<CategorizedName> data;
#Override
public int getItemViewType(int position) {
if (items.get(position) instanceof Category) {
return CATEGORY;
} else if (items.get(position) instanceof Name) {
return NAME;
}
throw new RuntimeException('error');
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
RecyclerView.ViewHolder viewHolder;
LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
switch (viewType) {
case CATEGORY:
View categoryView = inflater.inflate(R.layout.viewholder_category, viewGroup,
false);
viewHolder = new CategoryViewHolder(categoryView);
break;
case NAME:
View nameView = inflater.inflate(R.layout.viewholder_name, viewGroup, false);
viewHolder = new NameViewHolder(nameView);
break;
}
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
switch (viewHolder.getItemViewType()) {
case USER:
CategoryViewHolder categoryViewHolder = (CategoryViewHolder) viewHolder;
bindCategoryViewHolder(categoryViewHolder, position);
break;
case IMAGE:
NameViewHolder nameViewHolder = (NameViewHolder) viewHolder;
bindNameViewHolder(nameViewHolder, position);
break;
}
}
Replace your getItemViewType() with this
#Override
public int getItemViewType(int position){
if(position < total_no_of_row){
return VIEW_TYPE_TEXTVIEW;
}
if(position - total_no_of_row < cursor.getCount()){
return VIEW_TYPE_ITEM_1;
}
return -1;
}
you can also refer to my answer this

Interact with view of a specific item in a custom ListView

I am using a custom BaseAdapter to create a custom list. What I'm trying to do is have a public function outside of getView(), in this example setName(), that can interact with a view of a specific item on the list.
For example calling setName(1); should make invisible the TextView of the second item on the list.
Thank you in advance.
public class ListAdapterNew extends BaseAdapter {
private int size;
private Context context;
private ViewHolder viewHolder;
String[][] data;
ArrayList<DataModel> listArray;
public ListAdapterNew(Context context, String[][] data, int size) {
listArray = new ArrayList<DataModel>(size);
for(int i=0;i<size;i++){
listArray.add(new DataModel(i));
}
this.context=context;
this.data=data;
this.size=size;
}
#Override
public int getCount() {
return listArray.size();
}
#Override
public Object getItem(int i) {
return listArray.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
public int getViewTypeCount() { return getCount(); }
#Override
public int getItemViewType(int position) {
return position;
}
private static class ViewHolder
{
TextView number,name;
}
#Override
public View getView(int index, View view, final ViewGroup parent) {
if (view == null) {
LayoutInflater li = (LayoutInflater) parent.getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
view = li.inflate(R.layout.main_user_list_item, parent, false);
viewHolder = new ViewHolder();
viewHolder.number = view.findViewById(R.id.main_list_number);
viewHolder.name = view.findViewById(R.id.main_list_name);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
viewHolder.number.setText((index+1)+")");
viewHolder.name.setText(data[index][0]);
}
view.setClickable(true);
view.setFocusable(true);
return view;
}
public void setName(int index){
viewHolder.name.setVisibility(View.GONE);
}
}
The answer was simple. I use a public function inside the ListAdapterNew to update the data[][] and call notifyDataSetChanged(); on the adapter.
There is also a small change in the getView() of the adapter that allows the view to update when items become visible, as shown below.
if (view == null) {
LayoutInflater li = (LayoutInflater) parent.getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
view = li.inflate(R.layout.main_user_list_item, parent, false);
viewHolder = new ViewHolder();
viewHolder.number = view.findViewById(R.id.main_list_number);
viewHolder.name = view.findViewById(R.id.main_list_name);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
if (view != null){
viewHolder.number.setText((index+1)+")");
viewHolder.name.setText(data[index][0]);
}
Function that updates the data
public void updateIcons(int index, int data){
this.icons[index]=data;
}

Add static default item in RecyclerView

I have a horizontal RecyclerView that displays 7 images from the users device (changing as user keeps taking pictures). I would like to add a default icon at the end of the 7 images, with an onclick capability. How can I go about doing this?
Something like this:
In the image above the plus icon should be the default icon, however it should be at the end of the images.
UPDATED:
RecentPhotosAdapter.java
public class RecentPhotosAdapter extends RecyclerView.Adapter<RecentPhotosAdapter.ViewHolder> {
// Variables
private Context mContext;
private ArrayList<String> mImage;
private int VIEW_TYPE_DEFAULT = 0;
private int VIEW_TYPE_IMAGE = 1;
// Limit the recent photo selection
int RECENT_PHOTO_LIMIT = 7;
public RecentPhotosAdapter(Context mContext, ArrayList<String> mImage) {
this.mContext = mContext;
this.mImage = mImage;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_IMAGE) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recent_photos_item, parent, false);
return new ViewHolder(view);
}
else {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.default_select_photos_item, parent, false);
return new ViewHolder(view);
}
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
if(position < Math.min(mImage.size(), RECENT_PHOTO_LIMIT)){
String images = mImage.get(position);
// Recent Photos
Glide.with(mContext)
.load(images)
.placeholder(R.drawable.background_gallery_placeholder)
.transform(new CenterCrop(), new RoundedCorners(30))
.into(holder.recent_photos_iv);
// Default select photos
holder.recent_photos_iv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Do something here
// Take user to image select slider
}
});
}
else {
//code for default view
}
}
#Override
public int getItemViewType(int position) {
return (position == mImage.size()) ? VIEW_TYPE_DEFAULT : VIEW_TYPE_IMAGE;
}
#Override
public int getItemCount() {
return Math.min(mImage.size(), RECENT_PHOTO_LIMIT) + 1;
}
public class ViewHolder extends RecyclerView.ViewHolder{
ImageView recent_photos_iv;
ImageView default_select_photo_iv;
public ViewHolder(View itemView) {
super(itemView);
recent_photos_iv = itemView.findViewById(R.id.recent_photos_iv);
default_select_photo_iv = itemView.findViewById(R.id.default_select_photo_iv);
}
}
}
You can achieve this by making the default icon as a "ViewType" of your adapter.
Override getItemViewType to return a different value for your last item.
#Override
public int getItemViewType(int position) {
return (position == mData.size()) ? VIEW_TYPE_DEFAULT : VIEW_TYPE_IMAGE;
}
Now in the onCreateViewHolder, handle both the view Types.
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_IMAGE) {
//Create viewholder for your images
}
else {
//Create viewholder for default view
}
}
Add 1 to your ItemList size to accomodate this extra view:
#Override
public int getItemCount() {
return mData.size() + 1;
}
Your Updated code:
public class RecentPhotosAdapter extends RecyclerView.Adapter<RecentPhotosAdapter.ViewHolder> {
// Variables
private Context mContext;
private ArrayList<String> mImage;
private int VIEW_TYPE_DEFAULT=0;
private int VIEW_TYPE_IMAGE=1;
public RecentPhotosAdapter(Context mContext, ArrayList<String> mImage) {
this.mContext = mContext;
this.mImage = mImage;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_IMAGE) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recent_photos_item, parent, false);
return new ViewHolder(view);
}
else {
//Create viewholder for default view
}
}
#Override
public int getItemViewType(int position) {
return (position == Math.min(mImage.size(), RECENT_PHOTO_LIMIT)) ?VIEW_TYPE_DEFAULT : VIEW_TYPE_IMAGE;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
if(position < Math.min(mImage.size(), RECENT_PHOTO_LIMIT)){
String images = mImage.get(position);
Glide.with(mContext)
.load(images)
.placeholder(R.drawable.background_gallery_placeholder)
.transform(new CenterCrop(), new RoundedCorners(30))
.into(holder.recent_photos_iv);
holder.recent_photos_iv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Do something here
// Take user to image select slider
}
});
}
else {
//code for default view
}
}
#Override
public int getItemCount() {
// Limit the recent photo selection
int RECENT_PHOTO_LIMIT = 7;
return Math.min(mImage.size(), RECENT_PHOTO_LIMIT)+1;
}
public class ViewHolder extends RecyclerView.ViewHolder{
ImageView recent_photos_iv;
public ViewHolder(View itemView) {
super(itemView);
recent_photos_iv = itemView.findViewById(R.id.recent_photos_iv);
}
}
}

Android. Java. RecyclerAdapter

I have two different card view in one layout. I need that The latest news is added to one card view, and the rest in another. For exapmle, on image
MyRecyclerAdapter code
public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.CustomViewHolder> {
private List<FeedItem> feedItemList;
private Context mContext;
public MyRecyclerAdapter(Context context, List<FeedItem> feedItemList) {
this.feedItemList = feedItemList;
this.mContext = context;
}
#Override
public CustomViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_row, null);
CustomViewHolder viewHolder = new CustomViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(CustomViewHolder customViewHolder, int i) {
FeedItem feedItem = feedItemList.get(i);
//Download image using picasso library
Picasso.with(mContext).load(feedItem.getThumbnail())
.error(R.drawable.placeholder)
.placeholder(R.drawable.placeholder)
.into(customViewHolder.imageView);
//Setting text view title
customViewHolder.textView.setText(Html.fromHtml(feedItem.getTitle()));
View.OnClickListener clickListener = new View.OnClickListener() {
#Override
public void onClick(View view) {
CustomViewHolder holder = (CustomViewHolder) view.getTag();
int position = holder.getPosition();
FeedItem feedItem = feedItemList.get(position);
Toast.makeText(mContext, feedItem.getTitle(), Toast.LENGTH_SHORT).show();
}
};
//Handle click event on both title and image click
customViewHolder.textView.setOnClickListener(clickListener);
customViewHolder.imageView.setOnClickListener(clickListener);
customViewHolder.textView.setTag(customViewHolder);
customViewHolder.imageView.setTag(customViewHolder);
}
#Override
public int getItemCount() {
return (null != feedItemList ? feedItemList.size() : 0);
}
public class CustomViewHolder extends RecyclerView.ViewHolder {
protected ImageView imageView;
protected TextView textView;
public CustomViewHolder(View view) {
super(view);
this.imageView = (ImageView) view.findViewById(R.id.thumbnail);
this.textView = (TextView) view.findViewById(R.id.title);
}
}
}
The approach I would use if I were in you, to accomplish what you posted in the picture is to override getItemViewType and have two different types of ViewHolder, once for the header, the one with the big image and the other adapter for the small rows. onBindViewHolder gets the type as parameter. In your case is int i.
I write a quickdemo like this:
private class MyCustomAdapter extends BaseAdapter {
private static final int TYPE_ITEM = 0;
private static final int TYPE_SEPARATOR = 1;
private static final int TYPE_MAX_COUNT = TYPE_SEPARATOR + 1;
private ArrayList mData = new ArrayList();
private LayoutInflater mInflater;
private TreeSet mSeparatorSet = new TreeSet();
public MyCustomAdapter() {
mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void addItem(String item) {
mData.add(item);
notifyDataSetChanged();
}
public void addSeparator(String item) {
mData.add(item);
mSeparatorSet.add(mData.size() - 1);
notifyDataSetChanged();
}
#Override
public int getItemViewType(int position) {
return mSeparatorSet.contains(position) ? TYPE_SEPARATOR : TYPE_ITEM;
}
#Override
public int getViewTypeCount() {
return TYPE_MAX_COUNT;
}
#Override
public int getCount() {
return mData.size();
}
#Override
public Object getItem(int position) {
return mData.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
int type = getItemViewType(position);
System.out.println("getView " + position + " " + convertView + "type " + type);
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
switch (type) {
case TYPE_ITEM:
convertView = mInflater.inflate(R.layout.item1, null);
holder.textView = (TextView) convertView.findViewById(R.id.text_view);
break;
case TYPE_SEPARATOR:
convertView = mInflater.inflate(R.layout.item2, null);
holder.textView = (TextView) convertView.findViewById(R.id.textSeparator);
break;
}
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.textView.setText(mData.get(position) + "");
return convertView;
}
}
public static class ViewHolder {
public TextView textView;
}
or if you want to use header and footer, create headerView layout:
View header = (View) getLayoutInflater().inflate(R.layout.headerView,null);
listView.addHeaderView(header);

Categories