Duplicate entries List View with Generic Adapter - java

I have a generic adapter to use with all kind of listView but I get duplicated items in a ListView. When I'm Scrolling back and down sometimes changes the item order. There is some threads about that but not with a generic adapter. I know Android reuse the Ui object but the view in getView is always null (said android Studio)
Here is my code about adapter :
Interface :
public interface Adaptable {
public View buildView(View v, LayoutInflater inflater, ViewGroup parent);
}
BaseView Class :
public abstract class BaseView<T,E> implements Adaptable{
private static final String TAG = "BaseView";
protected int layoutId;
protected T viewHolder;
protected E entity;
public BaseView(){
}
public BaseView(E entity, int layoutId){
this.entity = entity;
this.layoutId = layoutId;
}
protected void invokeView(View v){
try {
Field fs[] = viewHolder.getClass().getFields();
for (Field f : fs) {
InvokeView a = f.getAnnotation(InvokeView.class);
int id = a.viewId();
Log.d(TAG, "field name: " + f.getName());
Log.d(TAG, "view id: " + id);
Log.d(TAG, "class: " + f.getClass());
f.set(viewHolder, v.findViewById(id));
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
#SuppressWarnings("unchecked")
#Override
public View buildView(View v, LayoutInflater inflater, ViewGroup parent) {
// load the view
if (null == v) {
v = inflater.inflate(layoutId, parent, false);
// get the view
invokeView(v);
v.setTag(viewHolder);
} else {
viewHolder = (T) v.getTag();
}
// binding logic data to view
mappingData(viewHolder, entity, v.getContext());
return v;
}
protected abstract void mappingData(T viewHolder, E entity, Context mContext);
}
Custom adapter class :
public class CustomListAdapter extends BaseAdapter {
private LayoutInflater inflater;
private List<Adaptable> items;
#SuppressWarnings("unchecked")
public CustomListAdapter(List<?> items, Context c) {
this.items = (List<Adaptable>) items;
inflater = LayoutInflater.from(c);
}
#Override
public int getCount() {
return items.size();
}
#Override
public Object getItem(int position) {
return items.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
return items.get(position).buildView(convertView, inflater, parent); }
}
InvokeView Interface :
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface InvokeView {
int viewId();
}
Here how I set it in my activity :
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
ListView listViewPlaces = (ListView) rootView.findViewById(R.id.listLocality);
List<PlacesView> lstPlaceView = new ArrayList<PlacesView>();
ArrayList<PlaceModel> listPlaces = getArguments().getParcelableArrayList("listPlaces");
for (int i = 0; i < listPlaces.size(); i++)
{
Log.d("id", listPlaces.get(i).getId());
PlacesView mv = new PlacesView(listPlaces.get(i), R.layout.list_row_places);
lstPlaceView.add(mv);
}
CustomListAdapter adapter = new CustomListAdapter(lstPlaceView, rootView.getContext());
listViewPlaces.setAdapter(adapter);
return rootView;
}
If anyone have an idea.
Thanks in advance for help.

Related

RecyclerView onCreateViewHolder method not calling

Below are my ShelflifeAdapter and HomeFragment classes:-
public class HomeFragment extends Fragment {
RecyclerView shelflifeRecyclerview;
ShelflifeAdapter shelflifeAdapter;
Product product;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_home, container, false);
shelflifeRecyclerview = rootView.findViewById(R.id.shelflifeRecyclerview);
shelflifeAdapter = new ShelflifeAdapter(getContext());
shelflifeRecyclerview.setAdapter(shelflifeAdapter);
shelflifeRecyclerview.setLayoutManager(new LinearLayoutManager(getContext()));
shelflifeRecyclerview.setHasFixedSize(true);
//fragment->fragment 데이터받기
Bundle bundle = getArguments(); //번들 받기
if(bundle != null){
product = new Product();
product = (Product) bundle.getSerializable("bundle");
shelflifeAdapter.addItem(product);
Log.d("TAG", shelflifeAdapter.getItemCount() +" 갯수");
}
return rootView;
}
}
public class ShelflifeAdapter extends RecyclerView.Adapter<ShelflifeAdapter.ViewHolder>{
ArrayList<Product> items = new ArrayList<Product>();
Context mContext;
ShelflifeAdapter(Context context){
mContext = context;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
Log.d("TAG","onCreateViewHolder 작동함");
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View itemView = inflater.inflate(R.layout.layout_shelflife,parent,false);
return new ViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, int position) {
Log.d("TAG","onBindViewHolder 작동함");
Product item = items.get(position);
viewHolder.setItem(item,mContext);
}
#Override
public int getItemCount() {
return items.size();
}
public void addItem(Product item){
if(item != null){
Log.d("TAG","addItem 작동함(item 추가) : " + item.toString());
items.add(item);
notifyDataSetChanged();
}else{
Log.d("TAG","addItem 작동함(item 못가져옴)");
}
}
public void setItems(ArrayList<Product> items){
this.items = items;
}
public Product getItem(int position){
return items.get(position);
}
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
TextView tv_shelflife;
LinearLayout itemContainer;
public ViewHolder(#NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.imageView);
tv_shelflife = itemView.findViewById(R.id.tv_shelflife);
itemContainer = itemView.findViewById(R.id.itemContainer);
}
public void setItem(Product item, Context context){
if(item != null){
Log.d("TAG","어댑터의 item : "+ item.toString());
if(item.getImage()==null){
Glide.with(itemView).load(R.drawable.no_image).override(48,48).into(imageView);
}else{
Glide.with(itemView).load(item.image).override(48,48).into(imageView);
}
tv_shelflife.setText(item.shelflifeDate);
}else{
Log.d("TAG","item이 null임" );
}
}
}
}
addItem(Product item) is working well
But onCreateViewHolder method is not working.
Any help is appreciated !!!
initialize recycler view first ,then set adapter for recycler view.
shelflifeAdapter = new ShelflifeAdapter(getContext());
shelflifeRecyclerview.setLayoutManager(new LinearLayoutManager(getContext()));
shelflifeRecyclerview.setHasFixedSize(true);
//Always set adapter after setLayoutManager, setHasFixedSize
shelflifeRecyclerview.setAdapter(shelflifeAdapter);
Bundle bundle = getArguments(); //번들 받기
if(bundle != null){
product = new Product();
product = (Product) bundle.getSerializable("bundle");
shelflifeAdapter.addItem(product);
Log.d("TAG", shelflifeAdapter.getItemCount() +" 갯수");
}
And make sure item is not null
Product item = items.get(position);
if(item!=null)
viewHolder.setItem(item,mContext);
pass context into glide
if(item.getImage()==null){
Glide.with(context).load(R.drawable.no_image).override(48,48).into(imageView);
}else{
Glide.with(context).load(item.image).override(48,48).into(imageView);
}
tv_shelflife.setText(item.shelflifeDate);

ListView Adapter with multiple Item layouts not working

I am trying to display a ListView of some docs and images with different layouts.
it worked for docs but images are still not showing.
I have used the .contains method to check if the item is doc or image. Help me with this.
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater layoutInflater = activity.getLayoutInflater();
String fileName = uriList.get(position).getFileName();
return viewSetup(position, layoutInflater, fileName);
}
private View viewSetup(final int position, LayoutInflater layoutInflater, String fileName) {
if (fileName.contains(".png") || fileName.contains(".jpg") || fileName.contains(".jpeg")) {
View inflate = layoutInflater.inflate(R.layout.main_list_item_img, null, false);
ImageView imageView = inflate.findViewById(R.id.imgPrev);
Glide.with(activity).load(uriList.get(position).getDownloadLink()).into(imageView);
itemSetup(position, fileName, inflate);
return inflate;
} else {
View inflate = layoutInflater.inflate(R.layout.main_list_item_docs, null, false);
itemSetup(position, fileName, inflate);
return inflate;
}
}
private void itemSetup(final int position, String fileName, View inflate) {
TextView title = inflate.findViewById(R.id.uriTitle);
TextView desc = inflate.findViewById(R.id.uriDesc);
ImageView download = inflate.findViewById(R.id.download);
TextView createdOn = inflate.findViewById(R.id.createdOn);
title.setText(fileName + "");
desc.setText(uriList.get(position).getDescription());
createdOn.setText(uriList.get(position).getSendTime());
download.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
savefile(uriList.get(position).getDownloadLink());
}
});
}
I think there is a problem in your image loading. You can use Picasso.
Picasso.with(activity).load(yourUrl).
placeholder(R.drawable.image_loader).into(myImage);
You need to use type variable you can check how I did in below example :-
public class JobsAdapter extends BaseAdapter {
private Activity context;
private LinkedList<KeyValuesPair> listItemArrayList;
private LinkedList<Integer> type;
private LayoutInflater inflater;
public JobsAdapter(Activity context, LinkedList<KeyValuesPair> objects, LinkedList<Integer> type) {
this.context = context;
this.listItemArrayList = objects;
this.type = type;
inflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return type.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public boolean isEnabled(int position) {
return type.get(position) != 0;
}
#TargetApi(Build.VERSION_CODES.O)
public View getView(int position, View convertView, ViewGroup parent) {
// used new view instead of convertView so the spinner could support multiple views
View view = null;
// if type is equals to 0 it will load jobs header else jobs child
if (type.get(position) == 0) {
view = inflater.inflate(R.layout.lv_header, null, false);
TextView header = view.findViewById(R.id.jobsHeading);
header.setText(listItemArrayList.get(position).getValue());
if (position == 0) {
header.setTextSize(16);
header.setTypeface(context.getResources().getFont(R.font.raleway_regular));
header.setTextColor(context.getResources().getColor(R.color.colorPrimaryDark));
} else {
header.setTextColor(context.getResources().getColor(R.color.colorBlack));
}
} else if (type.get(position) == 1) {
view = inflater.inflate(R.layout.lv_child, null, false);
TextView child = view.findViewById(R.id.jobsChild);
child.setText(listItemArrayList.get(position).getValue());
}
return view;
}
}

How to pass data to getView method

I'm getting a variable data sent from activity to my adapter by using
sendData method, but every time when I try to access it in my getView method it resets to 0, please help. I've tried to debug code to check if the data from an activity is passing and it looks ok. I also created a getNumb method but still, the variable resets to 0. Here is my adapter code:
public class WorkoutListAdapterTwo extends BaseAdapter {
private int y;
public WorkoutListAdapterTwo() {
}
public int sendData(int x){
this.y = x;
return y;
}
public int getNumb(){
return this.y;
}
private static LayoutInflater mLayoutInflater = null;
public WorkoutListAdapterTwo(Activity ctx) {
this.mLayoutInflater = ctx.getLayoutInflater();
}
#Override
public int getCount() {
return WorkoutContentTwo.WORKOUTSTWO.size();
}
#Override
public Object getItem(int position) {
return WorkoutContentTwo.WORKOUTSTWO.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
int j = getNumb();
WorkoutTwo workout = (WorkoutTwo) getItem(j);
String [] arrOfStrings = workout.name.split(",");
if (convertView == null) {
convertView = mLayoutInflater.inflate(R.layout.adapter_workout_row, parent, false);
holder = new ViewHolder();
holder.id = (TextView) convertView.findViewById(R.id.workout_id);
holder.name = (TextView) convertView.findViewById(R.id.workout_name);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// Set the content for the ListView row
//holder.id.setText(workout.id);
//holder.name.setText(arrOfStrings[i]);
holder.id.setText(Integer.toString(position+1));
holder.name.setText(workout.ArrList[position]);
// Set the color for the ListView row
holder.id.setBackgroundColor(workout.dark);
holder.name.setBackgroundColor(workout.light);
return convertView;
}
Here I'm adding the code where I'm calling my method:
public void onItemSelected(int position) {
// Start the detail activity for the selected workout ID.
Intent detailIntent = new Intent(this, WorkoutDetailActivityTwo.class);
detailIntent.putExtra(WorkoutDetailFragmentTwo.ARG_WORKOUT_POS, position);
WorkoutListAdapterTwo newAdd = new WorkoutListAdapterTwo();
newAdd.sendData(position);
newAdd.notifyDataSetChanged();
startActivity(detailIntent);
}
Are you notifying your adapter to update views after updating the value? If your sendData() is not called until after the adapter has done it's first draw, you will need to call notifyDataSetChanged() so that the adapter knows there are new values that should be used to update your views.
You have to make a interface or you can a use notifyDataSetChanged depends on the use if you are doing search operation then use the notifyDataSetChanged method but if you want to send some data then
Fragment or activity
public class ExampleFragment extends Fragment implements MyAdapter.SuccessResponse{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View contentView = inflater.inflate(R.layout.my_layout, container, false);
MyAdapter myAdapter = new MyAdapter(getActivity(), 0);
myAdapter.successResponse = this;
return contentView;
}
#Override
public void onSuccess() {
}
}
The adapter code
class MyAdapter extends ArrayAdapter{
SuccessResponse successResponse;
public MyAdapter(Context context, int resource) {
super(context, resource);
}
public interface SuccessResponse{
void onSuccess();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//ur views
linearLayout.setOnClickListener(new View.OnClickListener{
#Override
public void onClick (View view){
if(successResponse!=null)
successResponse.onSuccess();
}
})
}
}
You can use any type of adapter i am use arrayadaper here.

How to fetch an image from a url to an arrayList

I'm trying to show images that are read from a url, they are more than an image so I had to put all of them in an arraylist and then make the images display in a gridview, for some reason it's not showing anything, the gridview is completely blank, please advise what am I doing wrong.
BottomSheetDialog_Smiles.java
Communicator.getInstance().on("subscribe start", new Emitter.Listener() {
#Override
public void call(Object... args) {
try{
JSONDictionary response = (JSONDictionary) args[0];
String str = response.get("emojiPack").toString();
JSONArray emojies = new JSONArray(str);
for(int i=0;i<emojies.length();i++){
JSONObject response2 = (JSONObject)
emojies.getJSONObject(i);
emojiModel = new EmojiModel((String) response2.get("urlFile"));
emojiUrl = emojiModel.getEmojiFile();
Picasso.with(getApplicationContext()).load(emojiUrl);
JSONDictionary t = JSONDictionary.fromString(response2.toString());
emojiModel.init(t);
emojieModels.add(new EmojiModel(emojiUrl));
}
EmojiAdapter emojiAdapter = new EmojiAdapter(getApplicationContext(),
emojieModels);
gridView2.setAdapter(emojiAdapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
EmojiAdapter emojiAdapter = new EmojiAdapter(getApplicationContext(),
emojieModels);
gridView2.setAdapter(emojiAdapter);
EmojiAdapter.java
public class EmojiAdapter extends ArrayAdapter<EmojiModel> {
Context context;
ArrayList<EmojiModel> list = new ArrayList<>();
public EmojiAdapter(Context context,ArrayList<EmojiModel> list) {
super(context, R.layout.smiles_items_layout, list);
this.context = context;
this.list = list;
}
#NonNull
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater o =
(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = o.inflate(R.layout.gifts_layout_2, parent , false);
ImageView imageView = (ImageView) v.findViewById(R.id.smile_image_view);
imageView.setImageResource(Integer.parseInt((list.get(position)).urlFile));
return v;
}
}
EmojiModel.Java
public class EmojiModel {
private int id;
private int price;
public String urlFile;
public EmojiModel(String urlFile) {
this.urlFile=urlFile;
}
public String getEmojiFile() {
return urlFile;
}
public void init(JSONDictionary data){
try{
urlFile = (String) data.get("urlFile");
id = Integer.parseInt((String) data.get("id"));
price = Integer.parseInt((String) data.get("price"));
}catch(Exception e){
e.printStackTrace();
}
}
}
obviously this line of code wont work :
imageView.setImageResource(Integer.parseInt((list.get(position)).urlFile));
instead of that just use glide or piccaso to load pics.
first add this line to your gradle file :
implementation 'com.github.bumptech.glide:glide:4.5.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.5.0'
then instead of above line ,just write :
Glide.with(context).load(list.get(position)).urlFile).into(imageView);
also the picaso library is pretty same
also change your adapter in this way :
public class EmojiAdapter extends BaseAdapter {
Context context;
ArrayList<EmojiModel> list = new ArrayList<>();
public EmojiAdapter(Context context,ArrayList<EmojiModel> list) {
super(context, R.layout.smiles_items_layout, list);
this.context = context;
this.list = list;
}
#NonNull
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater o =
(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = o.inflate(R.layout.gifts_layout_2, parent , false);
ImageView imageView = (ImageView) v.findViewById(R.id.smile_image_view);
imageView.setImageResource(Integer.parseInt((list.get(position)).urlFile));
return v;
}
#Override
public int getCount() {
return list.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return position;
}
}
Use Picasso in Adapter to show image
#NonNull
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater o =
(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = o.inflate(R.layout.gifts_layout_2, parent , false);
ImageView imageView = (ImageView) v.findViewById(R.id.smile_image_view);
Picasso.with(getApplicationContext()).load(list.get(position).getEmojiUrl()).into(imageView);
return v;
}
}

non static variable cannot be referenced from a static context in Adapter

I am using Base Adapter for displaying image in grid view. The working fine when images are fixed IMAGE_URLS directly but am try with geting url from list and assign into IMAGE_URLS that shows non static variable cannot be referenced from a static context. I don't know how to solve this issue. please help to solve this issue
public class ImageGridFragment extends AbsListViewBaseFragment {
public static final int INDEX = 1;
String description="";
ArrayList<String> img = new ArrayList<String>();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fr_image_grid, container, false);
listView = (GridView) rootView.findViewById(R.id.grid);
img.clear();
Bundle bundle = this.getArguments();
description = bundle.getString("description");
String[] separated= description.split(",");
for(int i=0;i<separated.length;i++)
{
img.add(separated[i]);
}
ImageGalleryFragment.imageLoader.init(ImageLoaderConfiguration.createDefault(getActivity()));
((GridView) listView).setAdapter(new ImageAdapter(getActivity()));
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
startImagePagerActivity(position);
}
});
return rootView;
}
private static class ImageAdapter extends BaseAdapter {
String[] IMAGE_URLS = img.toArray(new String[img.size()]);
private LayoutInflater inflater;
private DisplayImageOptions options;
ImageAdapter(Context context) {
inflater = LayoutInflater.from(context);
options = new DisplayImageOptions.Builder()
.showImageOnLoading(R.drawable.ic_stub)
.showImageForEmptyUri(R.drawable.ic_empty)
.showImageOnFail(R.drawable.ic_error)
.cacheInMemory(true)
.cacheOnDisk(true)
.considerExifParams(true)
.bitmapConfig(Bitmap.Config.RGB_565)
.build();
}
#Override
public int getCount() {
return IMAGE_URLS.length;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
View view = convertView;
if (view == null) {
view = inflater.inflate(R.layout.item_grid_image, parent, false);
holder = new ViewHolder();
assert view != null;
holder.imageView = (ImageView) view.findViewById(R.id.image);
holder.progressBar = (ProgressBar) view.findViewById(R.id.progress);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
ImageLoader.getInstance()
.displayImage(IMAGE_URLS[position], holder.imageView, options, new SimpleImageLoadingListener() {
#Override
public void onLoadingStarted(String imageUri, View view) {
holder.progressBar.setProgress(0);
holder.progressBar.setVisibility(View.VISIBLE);
}
#Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
holder.progressBar.setVisibility(View.GONE);
}
#Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
holder.progressBar.setVisibility(View.GONE);
}
}, new ImageLoadingProgressListener() {
#Override
public void onProgressUpdate(String imageUri, View view, int current, int total) {
holder.progressBar.setProgress(Math.round(100.0f * current / total));
}
});
return view;
}
}
static class ViewHolder {
ImageView imageView;
ProgressBar progressBar;
}
}
Change the class from private static to "private class ImageAdapter".

Categories

Resources