I have an UpdateFragment which display cards group by tags using a RecyclerView and ViewModel. In UpdateFragment I can also modify the name of the tags but I don't know why the change isn't detected by UpdateFragment until I recreate the fragment so UI don't update. The strange thing is that the MainActivity instead detect the update of the list and the code is equal.
UpdateFragment.class
public class UpdateFragment extends BaseCardFragment {
// TODO show total cards number
private static final String TAG = "UpdateFragment";
private RecyclerView recyclerView;
public UpdateFragment(List<CardWithTags> cardList, List<Tag> tagList) {
super(cardList, tagList);
}
#Override
public void updateUI(List<CardWithTags> cardListWithTags, List<Tag> tagList) {
RecyclerViewAdapterUpdate adapter = (RecyclerViewAdapterUpdate) recyclerView.getAdapter();
Log.d(TAG, "Adapter:" + adapter);
Log.d(TAG, "Cards:" + cardListWithTags);
Log.d(TAG, "Tags:" + tagList);
if (adapter != null && cardListWithTags != null && tagList != null) {
adapter.setCardList(cardListWithTags);
adapter.setTagList(tagList);
adapter.notifyDataSetChanged();
Log.d(TAG, ">>Update, Total cards: " + adapter.getItemCount());
Log.d(TAG, ">>Update, Total tags: " + tagList.size());
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_update, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setViewModel();
setRecyclerView();
}
private void setViewModel() {
Log.d(TAG, ">>SetViewModel()");
viewModel = new ViewModelProvider(this).get(ViewModelMainActivity.class);
viewModel.getAllCards().observe(getActivity(), cardListLoaded -> {
cardList = cardListLoaded;
Log.d(TAG, ">>CardList updated:" + cardList);
updateUI(cardList, tagList);
});
viewModel.getAllTags().observe(getActivity(), tagListLoaded -> {
tagList = tagListLoaded;
Log.d(TAG, ">>TagList updated:" + tagList);
updateUI(cardList, tagList);
});
}
private void setRecyclerView() {
Log.d(TAG, ">>SetRecyclerView()");
recyclerView = getView().findViewById(R.id.recycler_view_list);
RecyclerViewAdapterUpdate recyclerViewAdapter = new RecyclerViewAdapterUpdate(cardList, tagList,
getContext(), getLayoutInflater(),
viewModel);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getContext(),
RecyclerView.VERTICAL, false);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(recyclerViewAdapter);
}
}
ViewModelMainActivity.class
public class ViewModelMainActivity extends AndroidViewModel {
private static final String TAG = "ViewModelMainActivity";
private static boolean cardListIsUpdatedWithDb = false;
private static boolean tagListIsUpdatedWithDb = false;
private LiveData<List<CardWithTags>> cardList = new MutableLiveData<>();
private LiveData<List<Tag>> tagList = new MutableLiveData<>();
private final CardDAO cardDAO;
private final ExecutorService executor;
public ViewModelMainActivity(#NonNull Application application) {
super(application);
this.cardDAO = DatabaseTaboom.getDatabase(application).cardDao();
this.executor = Executors.newSingleThreadExecutor();
}
public LiveData<List<CardWithTags>> getAllCards() {
Log.d(TAG, ">>GetAllCards()");
if (!cardListIsUpdatedWithDb) {
cardList = cardDAO.getAllCards();
cardListIsUpdatedWithDb = true;
}
return cardList;
}
public LiveData<List<Tag>> getAllTags() {
Log.d(TAG, ">>GetAllTags()");
if (!tagListIsUpdatedWithDb) {
tagList = cardDAO.getAllTags();
tagListIsUpdatedWithDb = true;
}
return tagList;
}
public void insertCard(CardWithTags card) {
Log.d(TAG, ">>InsertCard(): " + card);
executor.execute(() -> {
long idCard = cardDAO.insertCard(card.getCard());
if (idCard >= 1) {
cardListIsUpdatedWithDb = false;
Log.d(TAG, ">>Inserted Card: " + card.getCard().getTitle());
}
for (Tag t: card.getTagList()) {
long idTag = cardDAO.insertTag(t);
CardTagCrossRef cardTagCrossRef = new CardTagCrossRef();
cardTagCrossRef.idCard = idCard;
if (idTag < 1) {
// If Tag already exist, retrieve that to get id to try insert cwt
idTag = cardDAO.getTag(t.getTag()).getIdTag();
} else {
// New Tag
tagListIsUpdatedWithDb = false;
Log.d(TAG, ">>Inserted Tag: " + t.getTag());
}
cardTagCrossRef.idTag = idTag;
long idCWT = cardDAO.insertCardWithTags(cardTagCrossRef);
if (idCWT >= 1) {
Log.d(TAG, ">>Inserted CWT: [" + idCard + "," + idTag + "]");
// Tag linked to a card
cardListIsUpdatedWithDb = false;
}
}
});
}
public void shuffle(List<CardWithTags> list) {
if (list != null) {
Collections.shuffle(list);
cardList = new MutableLiveData<>(list);
Log.d(TAG, ">>List shuffled: " + list);
} else {
Log.d(TAG, ">>List is null");
}
}
public void updateTag(Tag tag) {
executor.execute(() -> {
cardDAO.updateTag(tag);
tagListIsUpdatedWithDb = false;
cardListIsUpdatedWithDb = false;
});
}
}
RecyclerViewAdapterUpdate.class
public class RecyclerViewAdapterUpdate extends RecyclerView.Adapter<RecyclerViewAdapterUpdate.ViewHolder> {
private static final String TAG = "RecyclerViewAdapterUpdate";
private List<CardWithTags> cardList;
private List<Tag> tagList;
private Context context;
private LayoutInflater layoutInflater;
private ViewModelMainActivity viewModelFragment;
public RecyclerViewAdapterUpdate(List<CardWithTags> cardList, List<Tag> tagList, Context context,
LayoutInflater layoutInflater, ViewModelMainActivity viewModelFragment) {
this.cardList = cardList;
this.tagList = tagList;
this.context = context;
this.layoutInflater = layoutInflater;
this.viewModelFragment = viewModelFragment;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_update, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
if (position == 0) {
holder.numberOfItems.setText(String.valueOf(cardList.size()));
holder.tagName.setText(R.string.all_cards_tag);
holder.clearTag.setVisibility(View.GONE);
} else {
Tag tag = tagList.get(position - 1);
List<CardWithTags> listOfSingleTag = new ArrayList<>();
for (CardWithTags cwt: cardList) {
for (Tag t: cwt.getTagList()) {
if (t.getTag().equals(tag.getTag()))
listOfSingleTag.add(cwt);
}
}
holder.numberOfItems.setText(String.valueOf(listOfSingleTag.size()));
holder.tagName.setText(tag.getTag());
View viewDialogTag = layoutInflater.inflate(R.layout.dialog_modify_tag, null);
EditText tagNameEditText = viewDialogTag.findViewById(R.id.tag_name_dialog);
tagNameEditText.setText(tag.getTag());
// In this way the dialog is created only one time
AlertDialog dialog = new AlertDialog.Builder(context)
.setView(viewDialogTag)
.setTitle(R.string.title_modify_tag)
.setPositiveButton(R.string.modify, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
String newTag = tagNameEditText.getText().toString();
if (!newTag.isEmpty()&& !newTag.equalsIgnoreCase(tag.getTag())) {
tag.setTag(newTag);
viewModelFragment.updateTag(tag);
Log.d(TAG, ">>Update TAG: " + tag.getTag() + "->" + newTag);
}
}
})
.create();
holder.tagName.setOnLongClickListener( view -> {
dialog.show();
return true;
});
holder.clearTag.setOnClickListener( v -> Log.d(TAG, ">>CLICKED"));
}
}
#Override
public int getItemCount() {
if (tagList == null)
return 1;
return tagList.size() + 1;
}
public class ViewHolder extends RecyclerView.ViewHolder {
private static final String TAG = "ViewHolder";
private final TextView numberOfItems;
private final TextView tagName;
private final Button clearTag;
private final CheckBox checkBox;
public ViewHolder(#NonNull View itemView) {
super(itemView);
numberOfItems = itemView.findViewById(R.id.number_of_items);
tagName = itemView.findViewById(R.id.tag_name);
clearTag = itemView.findViewById(R.id.clear_tag);
checkBox = itemView.findViewById(R.id.check_box);
}
}
public void setCardList(List<CardWithTags> cardList) {
this.cardList = cardList;
}
public void setTagList(List<Tag> tagList) {
this.tagList = tagList;
}
}
I don't understand why this piece of code isn't called:
viewModel.getAllCards().observe(getActivity(), cardListLoaded -> {
cardList = cardListLoaded;
Log.d(TAG, ">>CardList updated:" + cardList);
updateUI(cardList, tagList);
});
viewModel.getAllTags().observe(getActivity(), tagListLoaded -> {
tagList = tagListLoaded;
Log.d(TAG, ">>TagList updated:" + tagList);
updateUI(cardList, tagList);
});
MainActivity.class method that instead is called even if is equal to that one in UpdateFragment (the activity is the same):
private void firstLoadCardList() {
ConstraintLayout fragmentContainer = findViewById(R.id.fragment_container);
ConstraintLayout progressBarContainer = findViewById(R.id.loading_container);
fragmentContainer.setVisibility(View.GONE);
progressBarContainer.setVisibility(View.VISIBLE);
Log.d(TAG, ">>FirstLoadCardList()");
viewModel = new ViewModelProvider(this).get(ViewModelMainActivity.class);
checkIfDatabaseAlreadyExist();
viewModel.getAllCards().observe(this, cardListLoaded -> {
cardList = cardListLoaded;
Log.d(TAG, ">>Total cards found: " + cardList.size());
if (tagList != null /*&& appJustOpened*/) {
appJustOpened = false;
progressBarContainer.setVisibility(View.GONE);
fragmentContainer.setVisibility(View.VISIBLE);
bottomNav.setSelectedItemId(R.id.play_nav);
}
});
viewModel.getAllTags().observe(this, tagListLoaded -> {
tagList = tagListLoaded;
Log.d(TAG, ">>Total tags found: " + tagList.size());
// If tagList not loaded before creation of BottomNav update Fragment list
// and cardList already loaded
if (cardList!= null /*&& appJustOpened*/) {
appJustOpened = false;
progressBarContainer.setVisibility(View.GONE);
fragmentContainer.setVisibility(View.VISIBLE);
bottomNav.setSelectedItemId(R.id.play_nav);
}
});
}
Please stop talking about notifyDataSetChanged() in the comments, I know how it works, my problem is with ViewModel/observer. The part about observer shouldn't be called every time the lists of the ViewModel change? Thank you.
I think you just need to add the below function in your recycler adapter.
public void setCardList(List<CardWithTags> cardList){
this.cardList=new ArrayList<CardWithTags>()
this.cardList.addAll(cardList)
notifyDataSetChanged()
}
public void setTagList(List<Tag> tagList){
this.tagList=new ArrayList<Tag>();
this.tagList.addAll(tagList);
notifyDataSetChanged();
}
Finally I found the answer: the two observer methods were not equals. In fact both in the Activity and in the Fragment I wrote: viewModel.getAllCards().observe(this, cardListLoaded -> {...} but this is different if called from Activity or Fragment, in the Fragment I have to use requireActivity() instead.
Related
In this part of my app, I am trying to implement deleting of selected favorite items via contextual action mode/bar, the problem is when I select an item then delete, it's deleted from the database and selected list but it is still available in recyclerView and it adds a duplicate from another item, the following gif clarify the problem
Edited the full adapter code FavoritesPostAdapter
public class FavoritesPostAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final FragmentActivity fragmentActivity;
private final List<FavoritesEntity> favoritesList;
private View rootView;
private static final int CARD = 0;
private static final int CARD_MAGAZINE = 1;
private static final int TITLE = 2;
private static final int GRID = 3;
private static final int SDK_VERSION = Build.VERSION.SDK_INT;
public static final String TAG = "POST ADAPTER";
private int viewType;
public final Fragment fragment;
public final PostViewModel postViewModel;
private ActionMode mActionMode;
private boolean multiSelection = false;
// private int selectedPostPosition ;
private final List<FavoritesEntity> selectedPosts = new ArrayList<>();
private final List<RecyclerView.ViewHolder> myViewHolders = new ArrayList<>();
public FavoritesPostAdapter(FragmentActivity fragmentActivity,
List<FavoritesEntity> favoritesList, Fragment fragment,
PostViewModel postViewModel) {
this.fragmentActivity = fragmentActivity;
this.favoritesList = favoritesList;
this.fragment = fragment;
this.postViewModel = postViewModel;
}
public void setViewType(int viewType) {
this.viewType = viewType;
notifyDataSetChanged();
}
public int getViewType() {
return this.viewType;
}
private final ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
#Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
mActionMode = actionMode;
actionMode.getMenuInflater().inflate(R.menu.favorites_contextual_menu, menu);
applyStatusBarColor(R.color.contextualStatusBarColor);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return true;
}
#Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
if (menuItem.getItemId() == R.id.delete_favorites_post) {
for (FavoritesEntity favoritesEntity : selectedPosts) {
postViewModel.deleteFavoritePost(favoritesEntity);
}
showSnackBar(selectedPosts.size() + " post/s deleted");
multiSelection = false;
selectedPosts.clear();
notifyDataSetChanged();
mActionMode.finish();
}
return true;
}
#Override
public void onDestroyActionMode(ActionMode actionMode) {
for (RecyclerView.ViewHolder holder : myViewHolders) {
changePostStyle(holder, R.color.cardBackgroundColor, R.color.strokeColor);
}
multiSelection = false;
selectedPosts.clear();
applyStatusBarColor(R.color.statusBarColor);
}
};
private void showSnackBar(String message){
Snackbar.make(rootView,message,Snackbar.LENGTH_SHORT).show();
}
private void applyStatusBarColor(int color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
fragmentActivity.getWindow().setStatusBarColor(ContextCompat.getColor(fragmentActivity, color));
}
}
private void applySelection(RecyclerView.ViewHolder holder, FavoritesEntity currentSelectedPost) {
if (selectedPosts.contains(currentSelectedPost)) {
selectedPosts.remove(currentSelectedPost);
changePostStyle(holder, R.color.cardBackgroundColor, R.color.strokeColor);
applyActionModeTitle();
} else {
selectedPosts.add(currentSelectedPost);
changePostStyle(holder, R.color.cardBackgroundLightColor, R.color.primaryColor);
applyActionModeTitle();
}
}
private void changePostStyle(RecyclerView.ViewHolder holder, int backgroundColor, int strokeColor) {
if (holder instanceof CardViewHolder) {
((CardViewHolder) holder).cardLayoutBinding.mainLinearLayout.setBackgroundColor(
ContextCompat.getColor(fragmentActivity.getApplicationContext(),
backgroundColor)
);
((CardViewHolder) holder).cardLayoutBinding.cardView.setStrokeColor(
strokeColor);
}
}
private void applyActionModeTitle() {
if (selectedPosts.size() == 0) {
mActionMode.finish();
multiSelection = false;
} else if (selectedPosts.size() == 1) {
mActionMode.setTitle(selectedPosts.size() + " item selected");
} else {
mActionMode.setTitle(selectedPosts.size() + " items selected");
}
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(fragmentActivity);
View view;
if (this.viewType == CARD) {
final CardLayoutBinding cardLayoutBinding
= CardLayoutBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new FavoritesPostAdapter.CardViewHolder(cardLayoutBinding);
} else if (this.viewType == CARD_MAGAZINE) {
final CardMagazineBinding cardMagazineBinding
= CardMagazineBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new FavoritesPostAdapter.CardMagazineViewHolder(cardMagazineBinding);
} else if (this.viewType == TITLE) {
if (SDK_VERSION < Build.VERSION_CODES.LOLLIPOP) {
view = inflater.inflate(R.layout.title_layout_v15, parent, false);
} else {
view = inflater.inflate(R.layout.title_layout, parent, false);
}
return new FavoritesPostAdapter.TitleViewHolder(view);
} else {
if (SDK_VERSION < Build.VERSION_CODES.LOLLIPOP) {
view = inflater.inflate(R.layout.grid_layout_v15, parent, false);
} else {
view = inflater.inflate(R.layout.grid_layout, parent, false);
}
return new FavoritesPostAdapter.GridViewHolder(view);
}
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
myViewHolders.add(holder);
rootView = holder.itemView.getRootView();
// selectedPostPosition = position;
int itemType = getViewType();
FavoritesEntity favoriteItem = favoritesList.get(position);
final Document document = Jsoup.parse(favoriteItem.getItem().getContent());
final Elements elements = document.select("img");
// Log.e("IMAGE", document.getAllElements().select("img").get(0).attr("src"));
switch (itemType) {
case CARD:
if (holder instanceof FavoritesPostAdapter.CardViewHolder) {
((FavoritesPostAdapter.CardViewHolder) holder).bind(favoriteItem);
((CardViewHolder) holder).cardLayoutBinding.cardView.setOnClickListener(view -> {
if (multiSelection) {
applySelection(holder, favoriteItem);
} else {
mActionMode.finish();
if (Objects.requireNonNull(Navigation.findNavController(
view
).getCurrentDestination()).getId() == R.id.nav_favorites) {
Navigation.findNavController(view)
.navigate(FavoritesFragmentDirections
.actionFavoritesFragmentToDetailsFragment(favoriteItem.getItem()));
}
}
}
);
((CardViewHolder) holder).cardLayoutBinding.cardView.setOnLongClickListener(view -> {
if (!multiSelection) {
multiSelection = true;
fragmentActivity.startActionMode(mActionModeCallback);
applySelection(holder, favoriteItem);
return true;
} else {
applySelection(holder, favoriteItem);
return true;
}
});
}
break;
case CARD_MAGAZINE:
if (holder instanceof FavoritesPostAdapter.CardMagazineViewHolder) {
FavoritesPostAdapter.CardMagazineViewHolder
cardMagazineViewHolder = (FavoritesPostAdapter.CardMagazineViewHolder) holder;
cardMagazineViewHolder.bind(favoriteItem);
}
break;
case TITLE:
if (holder instanceof FavoritesPostAdapter.TitleViewHolder) {
FavoritesPostAdapter.TitleViewHolder titleViewHolder = (FavoritesPostAdapter.TitleViewHolder) holder;
titleViewHolder.postTitle.setText(favoriteItem.getItem().getTitle());
Log.d("TITLE", "title layout called");
try {
Log.e("IMAGE", elements.get(0).attr("src"));
Glide.with(fragmentActivity).load(elements.get(0).attr("src"))
.transition(DrawableTransitionOptions.withCrossFade(600))
.placeholder(R.drawable.loading_animation)
.error(R.drawable.no_image)
.into(titleViewHolder.postImage);
} catch (IndexOutOfBoundsException e) {
titleViewHolder.postImage.setImageResource(R.drawable.no_image);
Log.e(TAG, e.toString());
}
if (position == getItemCount() - 1)
if (fragment instanceof HomeFragment) {
postViewModel.getPosts();
} else {
postViewModel.getPostListByLabel();
}
}
break;
case GRID:
if (holder instanceof FavoritesPostAdapter.GridViewHolder) {
FavoritesPostAdapter.GridViewHolder gridViewHolder = (FavoritesPostAdapter.GridViewHolder) holder;
gridViewHolder.postTitle.setText(favoriteItem.getItem().getTitle());
try {
Log.e("IMAGE", elements.get(0).attr("src"));
Glide.with(fragmentActivity).load(elements.get(0).attr("src"))
.transition(DrawableTransitionOptions.withCrossFade(600))
.placeholder(R.drawable.loading_animation)
.error(R.drawable.no_image)
.into(gridViewHolder.postImage);
} catch (IndexOutOfBoundsException e) {
gridViewHolder.postImage.setImageResource(R.drawable.no_image);
Log.e(TAG, e.toString());
}
if (position == getItemCount() - 1)
if (fragment instanceof HomeFragment) {
postViewModel.getPosts();
} else {
postViewModel.getPostListByLabel();
}
}
}
}
#Override
public int getItemCount() {
return favoritesList.size();
}
#Override
public void setHasStableIds(boolean hasStableIds) {
super.setHasStableIds(hasStableIds);
}
#Override
public long getItemId(int position) {
return position;
}
public static class CardViewHolder extends RecyclerView.ViewHolder {
final CardLayoutBinding cardLayoutBinding;
final Context context;
private CardViewHolder(final CardLayoutBinding binding) {
super(binding.getRoot());
cardLayoutBinding = binding;
context = cardLayoutBinding.getRoot().getContext();
}
private void bind(FavoritesEntity favoriteItem) {
final Document document = Jsoup.parse(favoriteItem.getItem().getContent());
final Elements elements = document.select("img");
// Log.e("IMAGE", document.getAllElements().select("img").get(0).attr("src"));
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat
("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault());
cardLayoutBinding.postTitle.setText(favoriteItem.getItem().getTitle());
try {
Log.e("IMAGE", elements.get(0).attr("src"));
Glide.with(context).load(elements.get(0).attr("src"))
.transition(DrawableTransitionOptions.withCrossFade(600))
.placeholder(R.drawable.loading_animation)
.error(R.drawable.no_image)
.into(cardLayoutBinding.postImage);
} catch (IndexOutOfBoundsException e) {
cardLayoutBinding.postImage.setImageResource(R.drawable.no_image);
Log.e(TAG, e.toString());
}
cardLayoutBinding.postDescription.setText(document.text());
try {
date = format.parse(favoriteItem.getItem().getPublished());
} catch (ParseException e) {
e.printStackTrace();
}
PrettyTime prettyTime = new PrettyTime();
cardLayoutBinding.postDate.setText(prettyTime.format(date));
}
}
public static class CardMagazineViewHolder extends RecyclerView.ViewHolder {
final CardMagazineBinding cardMagazineBinding;
final Context context;
private CardMagazineViewHolder(final CardMagazineBinding binding) {
super(binding.getRoot());
cardMagazineBinding = binding;
context = cardMagazineBinding.getRoot().getContext();
}
private void bind(FavoritesEntity favoriteItem) {
final Document document = Jsoup.parse(favoriteItem.getItem().getContent());
final Elements elements = document.select("img");
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat
("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault());
// Log.e("IMAGE", document.getAllElements().select("img").get(0).attr("src"));
cardMagazineBinding.postTitle.setText(favoriteItem.getItem().getTitle());
try {
Log.e("IMAGE", elements.get(0).attr("src"));
Glide.with(context).load(elements.get(0).attr("src"))
.transition(DrawableTransitionOptions.withCrossFade(600))
.placeholder(R.drawable.loading_animation)
.error(R.drawable.no_image)
.into(cardMagazineBinding.postImage);
} catch (IndexOutOfBoundsException e) {
cardMagazineBinding.postImage.setImageResource(R.drawable.no_image);
Log.e(TAG, e.toString());
}
try {
date = format.parse(favoriteItem.getItem().getPublished());
} catch (ParseException e) {
e.printStackTrace();
}
PrettyTime prettyTime = new PrettyTime();
cardMagazineBinding.postDate.setText(prettyTime.format(date));
}
}
public static class TitleViewHolder extends RecyclerView.ViewHolder {
TextView postTitle;
com.blogspot.abtallaldigital.utils.MyImageview postImage;
private TitleViewHolder(#NonNull View itemView) {
super(itemView);
postTitle = itemView.findViewById(R.id.postTitle);
postImage = itemView.findViewById(R.id.postImage);
}
}
public static class GridViewHolder extends RecyclerView.ViewHolder {
TextView postTitle;
MyImageview postImage;
private GridViewHolder(#NonNull View itemView) {
super(itemView);
postTitle = itemView.findViewById(R.id.postTitle);
postImage = itemView.findViewById(R.id.postImage);
}
}
}
favorites_contextual_menu xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/delete_favorites_post"
android:title="#string/delete_post"
app:showAsAction="ifRoom"
app:iconTint="#color/white"
android:icon="#drawable/ic_delete"
>
</item>
</menu>
PS: I tried to get the selected position from the holder and assign it to selectedPostPosition int value to use it in notifyItemRemoved(position); and notifyItemRangeChanged(position, getItemCount()); like in this answer but it doesn't fix the issue
The problem was happening because variable
private List<FavoritesEntity> favoritesList;
inside FavouritesFragment which kept all previous objects even after deleting items from a local database.
On every delete event, you were getting updates about database change -> postViewModel.metal favorites().observe, where you called addAll to this reference which contained all previous items.
Solution: https://github.com/dautovicharis/DummyApp2/commit/752a48fc98761d53c6a8f72076489a0f68ee348b
Source: https://github.com/dautovicharis/DummyApp2
Instead of using notifyItemRangeChanged(position, getItemCount());,
you can use
notifyItemRemoved(position);
this is because notifyItemRangeChanged(position, getItemCount()); does not remove the item like your requirements!
So I've been trying to fix this issue for so many hours but can't find the cause behind it.
Issue: My app shows data from my API into recyclerView, a standard feature. The issue comes when I use the search function. When I search for something, my search adapter shows the query data but going back to my Main fragment again, the view loader shows content fine but when I click on it, search items are actually being loaded instead.
Check my app to find out what I'm talking about: https://play.google.com/store/apps/details?id=envision.apps.newsextra
To reproduce, search for something, click on any article from search results, then go back and click any article from main feed, search items are actually being loaded instead.
Here's my main fragment:
public class FeedsFragment extends Fragment implements ArticleListener, LocalMessageCallback {
private PullRefreshLayout pullRefreshLayout;
private RecyclerView recyclerView;
private FeedsAdapter adapter;
private View layout;
private ArrayList<Object> data = new ArrayList<>();
private List<Favorites> favorites = new ArrayList<>();
private List<Articles> articles = new ArrayList<>();
private boolean init = true;
private DataViewModel dataViewModel;
private NativeAdsManager mNativeAdsManager;
private String sort_date = SharedPrefernces.getFeedSortDate();
public static FeedsFragment newInstance() {
return new FeedsFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
layout = inflater.inflate(R.layout.feeds_fragment_layout, container, false);
init_views();
setRecyclerView();
initNativeAds();
dataViewModel = ViewModelProviders.of(this).get(DataViewModel.class);
dataViewModel.getFavorites().observe(this, favorites -> {
if(favorites!=null){
this.favorites = favorites;
}
});
dataViewModel.getArticles().observe(this, articles -> {
this.articles = articles;
if(init) {
if (articles!= null && articles.size() > 0) {
//this.articles = articles;
data = new ArrayList<>();
if(SharedPrefernces.getActiveInterest().equalsIgnoreCase(getString(R.string.all_stories))){
data.add(new Info("Showing stories based on all your interests"));
}else{
data.add(new Info("Showing stories on "+SharedPrefernces.getActiveInterest()));
}
data.addAll(articles);
adapter.setData(data);
}
init = false;
}
});
new Handler().postDelayed(() -> {
//we first check if time set to fetch feeds again has elapsed
pullRefreshLayout.setRefreshing(true);
fetchFeeds();
SharedPrefernces.setReloadArticles(false);
}, 1000);
return layout;
}
//init view layouts
private void init_views(){
pullRefreshLayout = layout.findViewById(R.id.pullRefreshLayout);
int[] colorScheme = getResources().getIntArray(R.array.refresh_color_scheme);
pullRefreshLayout.setColorSchemeColors(colorScheme);
pullRefreshLayout.setOnRefreshListener(this::fetchFeeds);
}
//init recyclerview
private void setRecyclerView() {
recyclerView = (RecyclerView) layout.findViewById(R.id.recyclerView);
GridLayoutManager mLayoutManager = new GridLayoutManager(getActivity(), 1);
recyclerView.setLayoutManager(mLayoutManager);
adapter = new FeedsAdapter(getActivity(),recyclerView,this);
//int index = movies.size() - 1;
adapter.setLoadMoreListener(() -> recyclerView.post(() -> {
if(data.size()>0 && data.get(1) instanceof Articles){
adapter.setLoader();
loadMoreFeeds();
}
}));
recyclerView.setAdapter(adapter);
}
private void initNativeAds(){
mNativeAdsManager = new NativeAdsManager(getActivity(), getResources().getString(R.string.FACEBOOK_FEED_NATIVE_AD), 10);
mNativeAdsManager.loadAds();
mNativeAdsManager.setListener(new NativeAdsManager.Listener() {
#Override
public void onAdsLoaded() {
}
#Override
public void onAdError(AdError adError) {
}
});
}
private void fetchFeeds(){
if(!NetworkUtil.hasConnection(getActivity())) {
setNetworkError();
return;
}
NetworkService service = StringApiClient.createServiceWithToken(NetworkService.class);
try {
JSONObject jsonData = new JSONObject();
if(SharedPrefernces.getActiveInterest().equalsIgnoreCase(getString(R.string.all_stories))) {
jsonData.put("interests", new JSONArray(SharedPrefernces.getUserInterests()));
}else{
ArrayList<String> interest = new ArrayList<>();
interest.add(SharedPrefernces.getActiveInterest());
jsonData.put("interests", new JSONArray(interest));
}
if(SharedPrefernces.getUserUnfollowedFeedSources()!=null && SharedPrefernces.getUserUnfollowedFeedSources().size()>0) {
jsonData.put("sources", new JSONArray(SharedPrefernces.getUserUnfollowedFeedSources()));
}
jsonData.put("location", Misc.getCurrentCountryCode());
String requestBody = jsonData.toString();
Log.e("final requestbody",requestBody);
Call<String> callAsync = service.getArticles(requestBody);
callAsync.enqueue(new Callback<String>() {
#Override
public void onResponse(#NonNull Call<String> call, #NonNull Response<String> response) {
Log.e("response",String.valueOf(response.body()));
pullRefreshLayout.setRefreshing(false);
if(response.body()==null){
setNetworkError();
return;
}
try {
JSONObject res = new JSONObject(response.body());
// Add Your Logic
if(res.getString("status").equalsIgnoreCase("ok")){
//create a new object
data = new ArrayList<>();
if(SharedPrefernces.getActiveInterest().equalsIgnoreCase(getString(R.string.all_stories))){
data.add(new Info("Showing stories based on all your interests"));
}else{
data.add(new Info("Showing Stories on "+SharedPrefernces.getActiveInterest()));
}
sort_date = res.getString("date");
SharedPrefernces.setFeedSortDate(sort_date);
ArrayList<Articles> articles = JsonParser.getArticles(res.getJSONArray("feeds"));
//delete all previously store articles, and add new items to database
dataViewModel.deleteAllArticles();
dataViewModel.insertAllArticles(articles);
//append interests to our object list
data.addAll(articles);
//set data to adapter
adapter.setData(data);
//set last fetched time to sharedpreferences
if(articles.size()>0)SharedPrefernces.setArticleLastRefreshTime(System.currentTimeMillis());
}
}catch (Exception e){
e.printStackTrace();
Log.e("error",e.getMessage());
}
}
#Override
public void onFailure(#NonNull Call<String> call, #NonNull Throwable throwable) {
Log.e("error",String.valueOf(throwable.getMessage()));
setNetworkError();
pullRefreshLayout.setRefreshing(false);
}
});
} catch (JSONException e) {
Log.e("parse error",e.getMessage());
e.printStackTrace();
}
}
private void loadMoreFeeds(){
// ToDo
}
private void setNetworkError(){
dataViewModel.deleteAllArticles();
dataViewModel.insertAllArticles(articles);
pullRefreshLayout.setRefreshing(false);
data = new ArrayList<>();
if(SharedPrefernces.getActiveInterest().equalsIgnoreCase(App.getContext().getString(R.string.all_stories))){
data.add(new Info("Showing stories based on all your interests"));
}else{
data.add(new Info("Showing stories on "+SharedPrefernces.getActiveInterest()));
}
data.add(new Error(""));
adapter.setData(data);
}
#Override
public void OnItemClick(Articles article) {
//List<Integer> contestWinners = data.subList(0, 5);
int position = 0;
for (Articles arts: this.articles) {
if(arts.getId() == article.getId()){
position = this.articles.indexOf(arts);
}
}
Gson gson = new Gson();
String json = gson.toJson(article);
Intent intent = new Intent(getActivity(), FeedViewerActivity.class);
intent.putExtra("position", position);
intent.putExtra("article",json);
intent.putExtra(FeedViewerActivity.VIEW_TYPE, Constants.ARTICLE_VIEW);
intent.putExtra(FeedViewerActivity.VIEW_SIZE, get_feeds_view_size(this.articles,position));
startActivity(intent);
Objects.requireNonNull(getActivity()).overridePendingTransition(R.anim.slide_left_in, R.anim.still);
}
#Override
public void OnPinClick(Articles articles,String action) {
if(articles==null)return;
if(action.equalsIgnoreCase(getResources().getString(R.string.add_pin))){
dataViewModel.insertFavorites(ObjectMapper.mapFavorites(articles));
}else {
dataViewModel.deleteFavorite(ObjectMapper.mapFavorites(articles).getId());
}
}
#Override
public void OnShareClick(Articles articles) {
Intent share = new Intent(android.content.Intent.ACTION_SEND);
share.setType("text/plain");
share.putExtra(Intent.EXTRA_SUBJECT, articles.getTitle());
share.putExtra(Intent.EXTRA_TEXT, articles.getLink());
startActivity(Intent.createChooser(share, "Share Article"));
}
#Override
public boolean IsPinned(Articles articles) {
for (Favorites fav: favorites) {
if(fav.getId() == articles.getId()){
return true;
}
}
return false;
}
#Override
public void requestAds(int position) {
NativeAd ad = mNativeAdsManager.nextNativeAd();
if(ad!=null){
adapter.setAd(ad,position);
}
}
#Override
public void loadSingleFeedsActivity(Articles articles) {
Gson gson = new Gson();
String myJson = gson.toJson(articles);
Intent intent = new Intent(getActivity(), FeedSourceActivity.class);
intent.putExtra("article", myJson);
startActivity(intent);
}
#Override
public boolean isSingleFeedsActivity() {
return false;
}
#Override
public void onDestroy() {
LocalMessageManager.getInstance().send(R.id.remove_listener);
LocalMessageManager.getInstance().removeListener(this);
super.onDestroy();
}
#Override
public void onStart() {
super.onStart();
LocalMessageManager.getInstance().addListener(this);
}
#Override
public void handleMessage(#NonNull LocalMessage localMessage) {
if(localMessage.getId() == R.id.reload_feeds){
pullRefreshLayout.setRefreshing(true);
fetchFeeds();
SharedPrefernces.setReloadArticles(false);
}
if(localMessage.getId() == R.id.scroll_feeds_to_top){
recyclerView.smoothScrollToPosition(0);
}
}
}
Adapter:
public class FeedsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements View.OnClickListener {
private ArrayList<Object> data = new ArrayList<>();
private Context context;
private int lastItemPosition = -1;
private final int VIEW_TYPE_HEADER = 1;
private final int VIEW_TYPE_LIST = 2;
private final int VIEW_TYPE_LOADER = 3;
private final int VIEW_TYPE_NETWORK_ERROR = 4;
private final int VIEW_TYPE_INFO = 5;
private final int VIEW_TYPE_AD = 6;
private boolean isLoading = false;
private LoadMoreListener loadMoreListener;
private int visibleThreshold = 2;//visible items before loading next feeds
private int firstVisibleItem,lastVisibleItem, totalItemCount;
private ArticleListener articleListener;
public FeedsAdapter(Context context, RecyclerView mRecyclerView, ArticleListener articleListener) {
this.context=context;
this.articleListener = articleListener;
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
LocalMessageManager.getInstance().send(R.id.recyclerview_scroll);
firstVisibleItem = linearLayoutManager.findFirstVisibleItemPosition();
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if ((firstVisibleItem + Constants.ADS.NUMBER_OF_ITEMS_BEFORE_REQUEST_AD) % Constants.ADS.LOAD_ADS_AT_POSITION == 0){
//
int pos = firstVisibleItem + Constants.ADS.NUMBER_OF_ITEMS_BEFORE_REQUEST_AD;
if(pos > lastItemPosition && data.size()>pos && data.get(pos - 1) != null/*dont load ad if we r currently making a request*/) {
if (!(data.get(pos) instanceof NativeAd)) {
articleListener.requestAds(pos);
}
}
}
if (!isLoading && NetworkUtil.hasConnection(context)) {
if (totalItemCount <= (lastVisibleItem + visibleThreshold)) {
if (loadMoreListener != null) {
loadMoreListener.onLoadMore();
}
isLoading = true;
}
}
}
});
}
#Override
public int getItemViewType(int position) {
if(data.get(position) instanceof Error)return VIEW_TYPE_NETWORK_ERROR;
if(data.get(position) instanceof Info)return VIEW_TYPE_INFO;
if(data.get(position) instanceof NativeAd)return VIEW_TYPE_AD;
if(SharedPrefernces.get_feed_images_show()
&& SharedPrefernces.get_feed_type() == 1
&& position==1 && data.get(position) instanceof Articles){
return VIEW_TYPE_HEADER;
}
if(data.get(position) == null)return VIEW_TYPE_LOADER;
return VIEW_TYPE_LIST;
}
public void setData(ArrayList<Object> objectList) {
Log.e("objectList size",String.valueOf(objectList.size()));
this.data.clear();
this.data.addAll(objectList);
Log.e("data size",String.valueOf(data.size()));
this.notifyDataSetChanged();
}
public void setMoreData(ArrayList<Articles> articles) {
//int start = data.size() + 2;
data.addAll(articles);
//this.notifyItemRangeInserted(start, articles.size());
this.notifyDataSetChanged();
}
public void setAd(NativeAd ad, int pos) {
data.add(pos, ad);
this.notifyItemInserted(pos);
}
#Override
public int getItemCount() {
return data != null ? data.size() : 0;
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, final int position) {
lastItemPosition = position;
//Log.e("view type",String.valueOf(holder.getItemViewType()));
switch (holder.getItemViewType()) {
case VIEW_TYPE_LIST: case VIEW_TYPE_HEADER:
final ArticleViewHolder viewHolder = (ArticleViewHolder) holder;
viewHolder.bindTo((Articles) data.get(position));
break;
case VIEW_TYPE_LOADER:
final ViewLoader viewLoader = (ViewLoader) holder;
viewLoader.rotateLoading.start();
break;
case VIEW_TYPE_NETWORK_ERROR:
ViewError viewError = (ViewError) holder;
if(SharedPrefernces.getUseNightMode()){
viewError.img.setColorFilter(App.getContext().getResources().getColor(R.color.white));
}else{
viewError.img.setColorFilter(App.getContext().getResources().getColor(R.color.black));
}
break;
case VIEW_TYPE_INFO:
final ViewInfo viewInfo = (ViewInfo) holder;
Info info = (Info)data.get(position);
viewInfo.body.setText(info.getContent());
break;
case VIEW_TYPE_AD:
final AdsViewHolder adsViewHolder = (AdsViewHolder) holder;
NativeAd nativeAd = (NativeAd)data.get(position);
adsViewHolder.bind(nativeAd);
break;
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int i) {
RecyclerView.ViewHolder viewHolder = null;
LayoutInflater inflater = LayoutInflater.from(context);
switch (i) {
case VIEW_TYPE_HEADER:
View v = inflater.inflate(R.layout.feeds_header, parent, false);
viewHolder = new ArticleViewHolder(v, articleListener);
break;
case VIEW_TYPE_LIST:
View va;
if(SharedPrefernces.get_feed_images_show() && SharedPrefernces.get_feed_type()==0){
va = inflater.inflate(R.layout.large_image_feeds_list, parent, false);
}else{
va = inflater.inflate(R.layout.feeds_list, parent, false);
}
viewHolder = new ArticleViewHolder(va, articleListener);
break;
case VIEW_TYPE_LOADER:
View ld = inflater.inflate(R.layout.loader, parent, false);
viewHolder = new ViewLoader(ld);
break;
case VIEW_TYPE_NETWORK_ERROR:
View ne = inflater.inflate(R.layout.no_stories, parent, false);
viewHolder = new ViewError(ne);
break;
case VIEW_TYPE_INFO:
View info = inflater.inflate(R.layout.info, parent, false);
viewHolder = new ViewInfo(info);
break;
case VIEW_TYPE_AD:
View ads = inflater.inflate(R.layout.ad_item_large, parent, false);
viewHolder = new AdsViewHolder(ads);
break;
}
return viewHolder;
}
#Override
public void onClick(View view) {
//int pos = (int) view.getTag();
switch (view.getId()){
case R.id.pin:
break;
case R.id.share:
break;
}
}
public class ViewLoader extends RecyclerView.ViewHolder {
private RotateLoading rotateLoading;
ViewLoader(View view) {
super(view);
rotateLoading = (RotateLoading) view.findViewById(R.id.rotateloading);
}
}
public class ViewError extends RecyclerView.ViewHolder {
private ImageView img;
ViewError(View view) {
super(view);
img = view.findViewById(R.id.img);
}
}
public class ViewInfo extends RecyclerView.ViewHolder {
private TextView body;
ViewInfo(View view) {
super(view);
body = view.findViewById(R.id.body);
}
}
public void setLoaded(){
data.remove(data.size()-1);
this.notifyItemRemoved(data.size()-1);
isLoading = false;
}
public void setLoadMoreListener(LoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
public void setLoader(){
data.add(null);
this.notifyItemInserted(data.size()-1);
}
}
Search Adapter:
public class SearchAdapter extends RecyclerView.Adapter< RecyclerView.ViewHolder>{
private List<Object> items = new ArrayList<>();
private final int VIEW_TYPE_MEDIA = 0;
private final int VIEW_TYPE_LOADING = 1;
private final int VIEW_TYPE_AD = 2;
private SearchClickListener searchClickListener;
private LoadMoreListener mOnLoadMoreListener;
private boolean isLoading;
private int visibleThreshold = 2;
public int firstVisibleItem,lastVisibleItem, totalItemCount;
private int lastItemPosition = -1;
public SearchAdapter(RecyclerView mRecyclerView, SearchClickListener searchClickListener) {
this.searchClickListener = searchClickListener;
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
firstVisibleItem = linearLayoutManager.findFirstVisibleItemPosition();
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if ((firstVisibleItem + Constants.ADS.NUMBER_OF_ITEMS_BEFORE_REQUEST_AD) % Constants.ADS.LOAD_ADS_AT_POSITION == 0){
//
int pos = firstVisibleItem + Constants.ADS.NUMBER_OF_ITEMS_BEFORE_REQUEST_AD;
if(pos > lastItemPosition && items.size()>pos && items.get(pos - 1) != null/*dont load ad if we r currently making a request*/) {
if (!(items.get(pos) instanceof NativeAd)) {
searchClickListener.requestAds(pos);
}
}
}
if (!isLoading && NetworkUtil.hasConnection(App.getContext())) {
if (totalItemCount <= (lastVisibleItem + visibleThreshold)) {
if (items.size() > 1 && mOnLoadMoreListener != null) {
mOnLoadMoreListener.onLoadMore();
}
isLoading = true;
}
}
}
});
}
public void setMoreAdapter(List<Search> data) {
items.addAll(data);
//items.addAll((items.size()-1),data);
this.notifyDataSetChanged();
}
public void setAdapter(List<Search> data) {
items = new ArrayList<>();
items.addAll(data);
this.notifyDataSetChanged();
}
#Override
public int getItemCount() {
return items != null ? items.size() : 0;
}
#Override
public int getItemViewType(int position) {
if(items.get(position) instanceof NativeAd)return VIEW_TYPE_AD;
if(items.get(position)==null && position == (items.size()-1)){
return VIEW_TYPE_LOADING;
}else{
return VIEW_TYPE_MEDIA;
}
}
public void setLoader() {
items.add(null);
this.notifyItemInserted(items.size() - 1);
}
public void setAd(NativeAd ad, int pos) {
items.add(pos, ad);
this.notifyItemInserted(pos);
}
public void removeLoader() {
items.remove(items.size() - 1);
this.notifyItemRemoved(items.size());
}
public void setOnLoadMoreListener(LoadMoreListener mOnLoadMoreListener) {
this.mOnLoadMoreListener = mOnLoadMoreListener;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
RecyclerView.ViewHolder viewHolder = null;
LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
switch (i) {
case VIEW_TYPE_MEDIA:
View v = inflater.inflate(R.layout.search_list, viewGroup, false);
viewHolder = new SearchViewHolder(v,searchClickListener);
viewHolder.itemView.setClickable(true);
break;
case VIEW_TYPE_LOADING:
View vL = inflater.inflate(R.layout.loader, viewGroup, false);
viewHolder = new LoadingViewHolder(vL);
break;
case VIEW_TYPE_AD:
View ads = inflater.inflate(R.layout.ad_item_small, viewGroup, false);
viewHolder = new AdsViewHolder(ads);
break;
}
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int i) {
lastItemPosition = i;
switch (holder.getItemViewType()) {
case VIEW_TYPE_LOADING:
LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder;
loadingViewHolder.progressBar.start();
break;
case VIEW_TYPE_MEDIA:
final SearchViewHolder viewHolder = (SearchViewHolder) holder;
final Search ci = (Search)items.get(i);
viewHolder.bindTo(ci);
break;
case VIEW_TYPE_AD:
final AdsViewHolder adsViewHolder = (AdsViewHolder) holder;
NativeAd nativeAd = (NativeAd)items.get(i);
adsViewHolder.bind(nativeAd);
break;
}
}
private static class LoadingViewHolder extends RecyclerView.ViewHolder {
private RotateLoading progressBar;
private LoadingViewHolder(View itemView) {
super(itemView);
progressBar = itemView.findViewById(R.id.rotateloading);
}
}
public void setLoaded() {
isLoading = false;
}
public interface SearchClickListener {
void onClick(Search search);
void requestAds(int position);
}
}
Seriously any help will be greatly appreciated.
Due to the character limit, I'm posting my viewHolder code here as a comment.
ArticleViewHolder:
public class ArticleViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, LocalMessageCallback {
private Articles articles;
private TextView title,interest,time,source,content;
private LinearLayout revealView;
private ImageView thumbnail,pin,source_link;
private Animation alphaAnimation;
private float pixelDensity;
private boolean flag = false;
private RelativeLayout revealLayout,layoutButtons;
private ArticleListener articleListener;
private CardView cardView;
private String pin_action = "add";
public ArticleViewHolder(View view, ArticleListener articleListener) {
super(view);
this.articleListener = articleListener;
pixelDensity = App.getContext().getResources().getDisplayMetrics().density;
alphaAnimation = AnimationUtils.loadAnimation(App.getContext(), R.anim.alpha_anim);
LocalMessageManager.getInstance().addListener(this);
FrameLayout source_holder = view.findViewById(R.id.source_holder);
cardView = view.findViewById(R.id.card_view);
source_link = view.findViewById(R.id.source_link);
revealLayout = view.findViewById(R.id.revealLayout);
revealView = view.findViewById(R.id.revealView);
layoutButtons = view.findViewById(R.id.layoutButtons);
title = view.findViewById(R.id.title);
content = view.findViewById(R.id.content);
interest = view.findViewById(R.id.interest);
thumbnail = view.findViewById(R.id.thumbnail);
time = view.findViewById(R.id.time);
source = view.findViewById(R.id.source);
ImageView reveal = view.findViewById(R.id.reveal);
ImageView close = view.findViewById(R.id.close);
pin = view.findViewById(R.id.pin);
ImageView share = view.findViewById(R.id.share);
reveal.setOnClickListener(this);
close.setOnClickListener(this);
pin.setOnClickListener(this);
share.setOnClickListener(this);
title.setOnClickListener(this);
content.setOnClickListener(this);
thumbnail.setOnClickListener(this);
source_holder.setOnClickListener(this);
}
public void bindTo(Articles articles) {
this.articles = articles;
title.setText(articles.getTitle());
content.setText(articles.getContent().replace("\n", " ").replace("\r", " "));
interest.setText(articles.getInterest());
//Log.e("thumbnail",String.valueOf(articles.getThumbnail()));
if(SharedPrefernces.get_feed_images_show()) {
thumbnail.setVisibility(View.VISIBLE);
ImageLoader.loadImage(thumbnail, articles.getThumbnail());
}else{
thumbnail.setVisibility(View.GONE);
}
time.setText(TimUtil.timeAgo(articles.getTimeStamp()));
String _source = articles.getSource();
source.setText(_source.substring(0,1).toUpperCase() + _source.substring(1).toLowerCase());
if(articleListener.IsPinned(articles)){
set_pin_view(true);
pin_action = App.getContext().getResources().getString(R.string.remove_pin);
}else{
set_pin_view(false);
pin_action = App.getContext().getResources().getString(R.string.add_pin);
}
if(flag){
revealView.setVisibility(View.VISIBLE);
layoutButtons.setVisibility(View.VISIBLE);
}else{
revealView.setVisibility(View.GONE);
layoutButtons.setVisibility(View.GONE);
}
if(articleListener.isSingleFeedsActivity()){
source_link.setVisibility(View.GONE);
}else{
source_link.setVisibility(View.VISIBLE);
}
if(!SharedPrefernces.getUseNightMode()){
cardView.setCardBackgroundColor(App.getContext().getResources().getColor(R.color.material_grey_100));
}
}
private void set_pin_view(boolean isPinned){
Drawable mDrawable;
if(!isPinned){
mDrawable = ContextCompat.getDrawable(App.getContext(),R.drawable.pin_outline);
mDrawable.setColorFilter(new
PorterDuffColorFilter(App.getContext().getResources().getColor(R.color.material_grey_200), PorterDuff.Mode.SRC_IN));
}else{
mDrawable = ContextCompat.getDrawable(App.getContext(),R.drawable.pin_outline);
mDrawable.setColorFilter(new
PorterDuffColorFilter(App.getContext().getResources().getColor(R.color.colorAccent), PorterDuff.Mode.SRC_IN));
}
pin.setImageDrawable(mDrawable);
}
#Override
public void onClick(View view) {
LocalMessageManager.getInstance().send(R.id.hide_reveal_layout,articles.getId());
if (articleListener != null) {
if(view.getId() == R.id.reveal || view.getId() == R.id.close){
revealLayout();
}else if(view.getId() == R.id.source_holder){
articleListener.loadSingleFeedsActivity(articles);
}else if(view.getId() == R.id.pin){
articleListener.OnPinClick(articles,pin_action);
if(pin_action.equalsIgnoreCase(App.getContext().getResources().getString(R.string.add_pin))){
pin_action = App.getContext().getResources().getString(R.string.remove_pin);
set_pin_view(true);
}else{
pin_action = App.getContext().getResources().getString(R.string.add_pin);
set_pin_view(false);
}
revealLayout();
}else if(view.getId() == R.id.share){
articleListener.OnShareClick(articles);
revealLayout();
}else if(view.getId() == R.id.title || view.getId() == R.id.thumbnail|| view.getId() == R.id.content) {
articleListener.OnItemClick(articles);
}
}
}
private void revealLayout() {
/*
MARGIN_RIGHT = 16;
FAB_BUTTON_RADIUS = 28;
*/
boolean isAttachedToWindow = ViewCompat.isAttachedToWindow(revealView);
if (isAttachedToWindow) {
int x = revealLayout.getRight();
int y = revealLayout.getBottom();
x -= ((28 * pixelDensity) + (16 * pixelDensity));
int hypotenuse = (int) Math.hypot(revealLayout.getWidth(), revealLayout.getHeight());
if (!flag) {
RelativeLayout.LayoutParams parameters = (RelativeLayout.LayoutParams)
revealView.getLayoutParams();
parameters.height = revealLayout.getHeight();
revealView.setLayoutParams(parameters);
Animator anim = ViewAnimationUtils.createCircularReveal(revealView, x, y, 0, hypotenuse);
anim.setDuration(200);
anim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationEnd(Animator animator) {
layoutButtons.setVisibility(View.VISIBLE);
layoutButtons.startAnimation(alphaAnimation);
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
}
});
revealView.setVisibility(View.VISIBLE);
anim.start();
flag = true;
} else {
Animator anim = ViewAnimationUtils.createCircularReveal(revealView, x, y, hypotenuse, 0);
anim.setDuration(200);
anim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationEnd(Animator animator) {
revealView.setVisibility(View.GONE);
layoutButtons.setVisibility(View.GONE);
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
}
});
anim.start();
flag = false;
}
}
}
#Override
public void handleMessage(#NonNull LocalMessage localMessage) {
switch (localMessage.getId()){
case R.id.hide_reveal_layout:
int id = localMessage.getArg1();
if(flag && id != articles.getId()){
revealLayout();
}
break;
case R.id.recyclerview_scroll:
if(flag){
revealLayout();
}
break;
}
}
}
I get duplicate data items in the RecyclerView when data is retrieved.
I have tried some such like way NotifyDataSetChanged() and setHasStableIds (true). But still has not succeeded and I tried this way (How to solve duplicate data items in recyclerview) but still has not succeededed too.
private void loadFirstPage() {
Log.d(TAG, "loadFirstPage: ");
callTopRatedMoviesApi().enqueue(new Callback<JsonObject>() {
#Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
if (!response.isSuccessful()) {
Log.e(TAG, "Response Error : " + response.code());
} else {
try {
JSONObject jsonObject = new JSONObject(response.body().toString());
JSONObject dataObject = jsonObject.getJSONObject("data");
JSONArray itemsObject = dataObject.getJSONArray("items");
modelGetProductSearchList = new ArrayList<>();
progressBar.setVisibility(View.GONE);
if (itemsObject.length() == 0) {
// Set GONE Visibility of TextView
} else {
for (int a = 0; a <= itemsObject.length(); a++) {
JSONObject object = itemsObject.getJSONObject(a);
ModelGetProductSearch modelGetProductSearch = new ModelGetProductSearch();
modelGetProductSearch.setId(object.getInt("id"));
modelGetProductSearch.setName(object.getString("name"));
JSONObject sourceObject = object.getJSONObject("source");
modelGetProductSearch.setSourceNames(sourceObject.getString("name"));
modelGetProductSearchList.add(modelGetProductSearch);
adapter.addAll(modelGetProductSearchList);
progressBar.setVisibility(View.GONE);
tvTidakAdaHasil.setVisibility(View.GONE);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
if (currentPage <= TOTAL_PAGES && currentPage <= adapter.getItemCount()) adapter.addLoadingFooter();
else isLastPage = true;
}
}
#Override
public void onFailure(Call<JsonObject> call, Throwable t) {
Log.e(TAG, "onFailure: " + t.getMessage());
tvTidakAdaHasil.setText("Maaf, cek koneksi internet anda dan coba kembali");
progressBar.setVisibility(View.GONE);
}
});
}
private void loadNextPage() {
Log.d(TAG, "loadNextPage: " + currentPage);
callTopRatedMoviesApi().enqueue(new Callback<JsonObject>() {
#Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
adapter.removeLoadingFooter();
isLoading = false;
if (!response.isSuccessful()) {
Log.e(TAG, "Response Error : " + response.code());
} else {
try {
JSONObject jsonObject = new JSONObject(response.body().toString());
JSONObject dataObject = jsonObject.getJSONObject("data");
JSONArray itemsObject = dataObject.getJSONArray("items");
modelGetProductSearchList = new ArrayList<>();
progressBar.setVisibility(View.GONE);
for (int a = 0; a <= itemsObject.length(); a++) {
JSONObject object = itemsObject.getJSONObject(a);
ModelGetProductSearch modelGetProductSearch = new ModelGetProductSearch();
modelGetProductSearch.setId(object.getInt("id"));
modelGetProductSearch.setName(object.getString("name"));
JSONObject sourceObject = object.getJSONObject("source");
modelGetProductSearch.setSourceNames(sourceObject.getString("name"));
modelGetProductSearchList.add(modelGetProductSearch);
adapter.addAll(modelGetProductSearchList);
progressBar.setVisibility(View.GONE);
}
} catch (JSONException e) {
e.printStackTrace();
}
if (currentPage != TOTAL_PAGES && currentPage <= adapter.getItemCount()) adapter.addLoadingFooter();
else isLastPage = true;
}
}
#Override
public void onFailure(Call<JsonObject> call, Throwable t) {
Log.e(TAG, "onFailure: " + t.getMessage());
tvTidakAdaHasil.setText("Maaf, cek koneksi internet anda dan coba kembali");
progressBar.setVisibility(View.GONE);
}
});
}
and this is my adapter
public class AdapterDetailSearch extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int ITEM = 0;
private static final int LOADING = 1;
private List<ModelGetProductSearch> modelGetProductSearchList;
private Context context;
private boolean isLoadingAdded = false;
public AdapterDetailSearch(Context context) {
this.context = context;
modelGetProductSearchList = new ArrayList<>();
}
public List<ModelGetProductSearch> getMovies() {
return modelGetProductSearchList;
}
public void setMovies(List<ModelGetProductSearch> movieResults) {
this.modelGetProductSearchList = movieResults;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder viewHolder = null;
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType) {
case ITEM:
viewHolder = getViewHolder(parent, inflater);
break;
case LOADING:
View v2 = inflater.inflate(R.layout.row_item_progress, parent, false);
viewHolder = new LoadingVH(v2);
break;
}
return viewHolder;
}
#NonNull
private RecyclerView.ViewHolder getViewHolder(ViewGroup parent, LayoutInflater inflater) {
RecyclerView.ViewHolder viewHolder;
View viewHolder = inflater.inflate(R.layout.row_item_detail_list, parent, false);
return new MovieVH(viewHolder);
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
final ModelGetProductSearch result = modelGetProductSearchList.get(position);
switch (getItemViewType(position)) {
case ITEM:
final MovieVH itemsListVH = (MovieVH) holder;
// Visible and Invisible set TextView
}
}
#Override
public int getItemCount() {
return modelGetProductSearchList == null ? 0 : modelGetProductSearchList.size();
}
#Override
public int getItemViewType(int position) {
return (position == modelGetProductSearchList.size() - 1 && isLoadingAdded) ? LOADING : ITEM;
}
/*
Helpers
_________________________________________________________________________________________________
*/
public void add(ModelGetProductSearch r) {
modelGetProductSearchList.add(r);
notifyItemInserted(modelGetProductSearchList.size() - 1);
}
public void addAll(List<ModelGetProductSearch> moveResults) {
for (ModelGetProductSearch result : moveResults) {
add(result);
}
}
public void remove(ModelGetProductSearch r) {
int position = modelGetProductSearchList.indexOf(r);
if (position > -1) {
modelGetProductSearchList.remove(position);
notifyItemRemoved(position);
}
}
public void clear() {
isLoadingAdded = false;
while (getItemCount() > 0) {
remove(getItem(0));
}
}
public boolean isEmpty() {
return getItemCount() == 0;
}
public void addLoadingFooter() {
isLoadingAdded = true;
add(new ModelGetProductSearch());
}
public void removeLoadingFooter() {
isLoadingAdded = false;
int position = modelGetProductSearchList.size() - 1;
ModelGetProductSearch result = getItem(position);
if (result != null) {
modelGetProductSearchList.remove(position);
notifyItemRemoved(position);
}
}
public ModelGetProductSearch getItem(int position) {
return modelGetProductSearchList.get(position);
}
/*
View Holders
_________________________________________________________________________________________________
*/
/**
* Main list's content ViewHolder
*/
protected class MovieVH extends RecyclerView.ViewHolder {
private LinearLayout llContainer;
private ImageView ivItem;
private TextView tvItemTitle, tvPriceRegular, tvPriceAfterDiscount, textFrom;
public MovieVH(View itemView) {
super(itemView);
llContainer = itemView.findViewById(R.id.container);
ivItem = itemView.findViewById(R.id.iv_item);
textFrom = itemView.findViewById(R.id.tv_from);
}
}
protected class LoadingVH extends RecyclerView.ViewHolder {
public LoadingVH(View itemView) {
super(itemView);
}
}
}
You add the same list multiple times in your adapter inside for-loop that's why it creates duplication. Move adapter.addAll outside for loop like below:
if (itemsObject.length() == 0) {
// Set GONE Visibility of TextView
} else {
for (int a = 0; a < itemsObject.length(); a++) {
...
//Remove from here
/*adapter.addAll(modelGetProductSearchList);
progressBar.setVisibility(View.GONE);
tvTidakAdaHasil.setVisibility(View.GONE);*/
}
//Add list here
adapter.addAll(modelGetProductSearchList);
progressBar.setVisibility(View.GONE);
tvTidakAdaHasil.setVisibility(View.GONE);
}
There is Scroll by loading RecyclerView(Lazy loading). When an item quantity is incremented by adding the plus button to say 10. after loading the next set of items while scrolling, The item quantity(10) is reset to 1 and 10 will be displayed for another item.
In the same sequence, if the unit is changed(by the spinner) to another unit the corresponding image will be loaded but after scrolling the unit and image will change back to initial unit.
When the image of an item is clicked, a dialog will show the details of the selected item . Sometimes the image in the dialog is correct but image of the RecyclerView is incorrect, will take time to load or will not load.
public class ArticleRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
implements Filterable {
private static final String TAG = "ArticleAdapter";
private final int VIEW_TYPE_ITEM = 0;
private final int VIEW_TYPE_LOADING = 1;
private Context context;
private Dialog articleDescriptionDialog;
private UOMOffersLIistViewAdapter uomOffersLIistViewAdapter;
private List<ArticleDetails> articleDetailsList;
private HomeActivityViewModel homeActivityViewModel;
private ItemFilter itemFilter = new ItemFilter();
private GetViewListener getViewListener;
private int lastPosition = -1;
private OnLoadMoreListener loadMoreListener;
private boolean isLoading = false, isMoreDataAvailable = true;
/*
* isLoading - to set the remote loading and complete status to fix back to back load more call
* isMoreDataAvailable - to set whether more data from server available or not.
* It will prevent useless load more request even after all the server data loaded
* */
public ArticleRecyclerViewAdapter(Context context, List<ArticleDetails> articleDetailsList
, HomeActivityViewModel homeActivityViewModel, Fragment fragment) {
this.context = context;
this.articleDetailsList = articleDetailsList;
this.homeActivityViewModel = homeActivityViewModel;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
if (viewType == VIEW_TYPE_ITEM) {
return new ItemViewHolder(inflater.inflate(R.layout.recycler_view_article_layout, parent, false));
} else {
return new LoadHolder(inflater.inflate(R.layout.item_loading_layout, parent, false));
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
if (position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) {
isLoading = true;
loadMoreListener.onLoadMore();
}
if (getItemViewType(position) == VIEW_TYPE_ITEM) {
populateItemRows((ItemViewHolder) viewHolder, position);
}
//No else part needed as load holder doesn't bind any data
}
#Override
public int getItemViewType(int position) {
if (articleDetailsList.get(position).isLoading()) {
return VIEW_TYPE_LOADING;
} else {
return VIEW_TYPE_ITEM;
}
}
#Override
public int getItemCount() {
return articleDetailsList.size();
}
#Override
public long getItemId(int position) {
return position;
}
/* VIEW HOLDERS */
static class ItemViewHolder extends RecyclerView.ViewHolder {
private ImageView stockImageView, copyStockImageView;
private TextView articleNameTextView, articleStockAmountTextView, articleOfferTextView, addCartTextView;
private NumberPicker articleStockQuantityNumberPicker;
private Spinner articleStockSpinner;
private ImageButton offerInfoImageButton;
private int selectedStockItemPosition, stockQuantity;
private String articleStockQuantityString = "";
private Integer stockId;
private double stockAmount;
public ItemViewHolder(View itemView) {
super(itemView);
stockImageView = itemView.findViewById(R.id.stockImgv);
copyStockImageView = itemView.findViewById(R.id.copyStockImgv);//for fly to cart animation
articleNameTextView = itemView.findViewById(R.id.articleNameTxt);
articleStockAmountTextView = itemView.findViewById(R.id.stock_amount_txt);
articleOfferTextView = itemView.findViewById(R.id.offer_txt);
offerInfoImageButton = itemView.findViewById(R.id.offerInfo_imgbtn);
addCartTextView = itemView.findViewById(R.id.addCart_txt);
articleStockSpinner = itemView.findViewById(R.id.stock_spnr);
articleStockQuantityNumberPicker = itemView.findViewById(R.id.qty_numberPicker);
articleStockQuantityNumberPicker.setMin(1);
articleStockQuantityNumberPicker.setUnit(1);
// no limit.
// viewHolder.quantityNumberPicker.setMax(15);
}
}
static class LoadHolder extends RecyclerView.ViewHolder {
public LoadHolder(View itemView) {
super(itemView);
}
}
public void setMoreDataAvailable(boolean moreDataAvailable) {
isMoreDataAvailable = moreDataAvailable;
}
/**
* notifyDataSetChanged is final method so we can't override it
* call articleRecyclerViewAdapter.notifyDataChanged(); after update the list
*/
public void notifyDataChanged() {
notifyDataSetChanged();
isLoading = false;
}
public interface OnLoadMoreListener {
void onLoadMore();
}
public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
private void populateItemRows(ItemViewHolder itemViewHolder, int itemPos) {
int itemPosition = itemViewHolder.getAdapterPosition();
try {
itemViewHolder.copyStockImageView.setImageResource(R.drawable.error_logo);//initialize with error logo.
itemViewHolder.stockImageView.setImageResource(R.drawable.error_logo);//initialize with error logo.
} catch (Exception e) {
e.printStackTrace();
}
itemViewHolder.articleNameTextView.setText(articleDetailsList.get(itemPosition).getArticleName());
itemViewHolder.articleNameTextView.setSelected(true);//for marquee
itemViewHolder.articleOfferTextView.setSelected(true);//for marquee
itemViewHolder.articleStockAmountTextView.setSelected(true);//for marquee
itemViewHolder.articleOfferTextView.setVisibility(View.GONE);//for demo (now no offer and schemes).
itemViewHolder.offerInfoImageButton.setVisibility(View.GONE);//for demo
setStockSpinner(itemViewHolder, itemPosition);
itemViewHolder.offerInfoImageButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//setUOMOffersDIalog(articleDetailsList.get(itemPosition));
}
});
itemViewHolder.articleStockQuantityNumberPicker.setValueChangedListener(new ValueChangedListener() {
#Override
public void valueChanged(int quantity, ActionEnum action) {
itemViewHolder.articleStockQuantityString = Integer.valueOf(quantity).toString();
}
});
itemViewHolder.addCartTextView.setOnClickListener(new SingleClickListener() {
#Override
public void onSingleClick(View v) {
itemViewHolder.articleStockQuantityString = Integer.valueOf(itemViewHolder.articleStockQuantityNumberPicker.getValue()).toString();
itemViewHolder.stockQuantity = Integer.valueOf(itemViewHolder.articleStockQuantityString);
itemViewHolder.stockAmount = articleDetailsList.get(itemPosition).getStockDetailsList()
.get(itemViewHolder.articleStockSpinner.getSelectedItemPosition()).getmRP();
itemViewHolder.stockId = articleDetailsList.get(itemPosition).getStockDetailsList()
.get(itemViewHolder.articleStockSpinner.getSelectedItemPosition()).getStockId();
Double stockDiscountAmount = 0.0;
//TODO: 26-Oct-19 discount hardcoded.
if (itemViewHolder.stockQuantity > 0) {
addItemToCart(itemViewHolder, itemViewHolder.stockId, itemViewHolder.stockQuantity, itemViewHolder.stockAmount, stockDiscountAmount);
} else {
//not using (used for when user enter invalid quantity)
MDToast.makeText(context, FinalVariables.ToastMessages.VALID_QUANTITY
, MDToast.LENGTH_SHORT, MDToast.TYPE_WARNING).show();
}
}
});
itemViewHolder.stockImageView.setOnClickListener(new SingleClickListener() {
#Override
public void onSingleClick(View v) {
itemViewHolder.articleOfferTextView.setVisibility(View.VISIBLE);
itemViewHolder.articleOfferTextView.setText( ""+ itemViewHolder.stockQuantity);
DialogUtils.showArticleDescription(context, articleDetailsList.get(itemPosition)
, itemViewHolder.selectedStockItemPosition, new DialogButtonClickListener() {
#Override
public void positiveButtonClick() {
//do nothing.
}
});
}
});
// Here you apply the animation when the view is bound
setAnimation(itemViewHolder.itemView, itemPosition);
}
private void setStockSpinner(ItemViewHolder itemViewHolder, int itemPosition) {
UOMSpinnerAdapter uomSpinnerAdapter = new UOMSpinnerAdapter(context, R.layout.spinner_uom_layout
, StringUtils.makeUomStringArrayForSpinner(articleDetailsList.get(itemPosition).getStockDetailsList()));
itemViewHolder.articleStockSpinner.setAdapter(uomSpinnerAdapter);
// Setting OnItemClickListener to the Spinner
itemViewHolder.articleStockSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
itemViewHolder.selectedStockItemPosition = position;
itemViewHolder.articleStockAmountTextView.setText(StringUtils.addAED(StringUtils.round3(
+articleDetailsList.get(itemPosition)
.getStockDetailsList().get(position).getmRP())));
//show image from link
try {
if (!articleDetailsList.get(itemPosition).getStockDetailsList().
get(position).getStockImageDetailsList().isEmpty()) {
ImageUtils.setGlide(context, itemViewHolder.stockImageView
, articleDetailsList.get(itemPosition).getStockDetailsList().
get(position).getStockImageDetailsList().get(0).getStockImage());
//same as stockImageView but used to animate fly to cart
ImageUtils.setGlide(context, itemViewHolder.copyStockImageView
, articleDetailsList.get(itemPosition).getStockDetailsList().
get(position).getStockImageDetailsList().get(0).getStockImage());
} else {
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
if (articleDetailsList.get(itemPosition).getStockDetailsList().size() > 0)
itemViewHolder.articleStockAmountTextView.setText(StringUtils.addAED(
StringUtils.round3(+articleDetailsList.get(itemPosition).getStockDetailsList().get(0).getmRP())));
itemViewHolder.selectedStockItemPosition = itemViewHolder.articleStockSpinner.getSelectedItemPosition();
}
});
}
private void addItemToCart(ItemViewHolder itemViewHolder, Integer stockId, Integer stockQuantity
, Double stockAmount, Double stockDiscountAmount) {
homeActivityViewModel.isItemAlreadyCarted(stockId
, new RetrieveDataListner() {
#Override
public void onDone(Object object) {
boolean isItemAlreadyCarted = (boolean) object;
if (!isItemAlreadyCarted) {//item not in cart,add to cart.
CartedItems cartedItem = new CartedItems();
cartedItem.setStockId(stockId);
cartedItem.setStockQuantity(stockQuantity);
cartedItem.setStockAmount(stockAmount);
cartedItem.setTotalAmount(CalcUtils.calculateTotalAmount(stockQuantity, stockAmount));
cartedItem.setNetAmount(CalcUtils.calculateNetAmount(stockQuantity
, stockAmount, stockDiscountAmount));
homeActivityViewModel.insertCartedItem(cartedItem
, new InsertDbSuccessListner() {
#Override
public void onSuccess() {
//set view to call back method for fly to cart animation
if (getViewListener != null){
getViewListener.onGetView(itemViewHolder.copyStockImageView);
}
itemViewHolder.articleStockQuantityNumberPicker.setValue(1);//reset item quantity in ui.
// TODO: 21-Mar-19 check fly to cart only in home activity or not
if (context instanceof MainActivity) {
MDToast.makeText(context, TextMessages.ITEM_ADDED
, MDToast.LENGTH_SHORT, MDToast.TYPE_SUCCESS).show();
} else if (context instanceof HomeActivity) {
try {
((HomeActivity) context).setCartDetails();
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure() {
}
});
} else {//item already carted,asking to add new quantity to carted quantity.
DialogUtils.showConformAlertDialog1(context, TextMessages.ITEM_ALREADY_CARTED
, TextMessages.ITEM_ALREADY_CARTED_WARNING
, StringValues.NO, StringValues.YES, new DialogButtonClickListener() {
#Override
public void positiveButtonClick() {//adding new quantity to existing quantity.
//set view to call back method for fly to cart animation
if (getViewListener != null)
getViewListener.onGetView(itemViewHolder.copyStockImageView);
homeActivityViewModel.updateCartedItemWithExistingValues(stockId, stockQuantity
, CalcUtils.calculateTotalAmount(stockQuantity, stockAmount),
CalcUtils.calculateNetAmount(stockQuantity, stockAmount, stockDiscountAmount)
, null);
itemViewHolder.articleStockQuantityNumberPicker.setValue(1);//reset item quantity in ui.
}
#Override
public void negativeButtonClick() {
}
});
}
}
});
}
/**
* Here is the key method to apply the animation
*/
private void setAnimation(View viewToAnimate, int position) {
// If the bound view wasn't previously displayed on screen, it's animated
if (position > lastPosition) {
Animation animation = AnimationUtils.loadAnimation(context, R.anim.fall_down);
viewToAnimate.startAnimation(animation);
lastPosition = position;
}
}
/**
* register listener for get article image(copyStockImageView)
* for fly to cart animation.
* the view get back to the call back(categorizedArticleFragment)).
*
* #param getViewListener
*/
public void setGetViewListener(GetViewListener getViewListener) {
this.getViewListener = getViewListener;
}
#Override
public Filter getFilter() {
return itemFilter;
}
private class ItemFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
String filterString = constraint.toString().toLowerCase();
FilterResults results = new FilterResults();
final List<ArticleDetails> list = articleDetailsList;
int count = list.size();
final List<ArticleDetails> nlist = new ArrayList<ArticleDetails>(count);
ArticleDetails filterableString;
for (int i = 0; i < count; i++) {
filterableString = list.get(i);
if (filterableString.getArticleName().toLowerCase().contains(filterString)) {
nlist.add(filterableString);
}
}
results.values = nlist;
results.count = nlist.size();
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
articleDetailsList = (ArrayList<ArticleDetails>) results.values;
notifyDataSetChanged();
}
}
}
Fragments onCreate
#Override
public View onCreateView(#NonNull LayoutInflater layoutInflater, ViewGroup viewGroup,
Bundle savedInstanceState) {
context = viewGroup.getContext();
parentView = layoutInflater.inflate(R.layout.fragment_article, viewGroup, false);
homeActivityViewModel = getViewModel();
articleRecyclerView = parentView.findViewById(R.id.subcategory_rcylv);
Bundle bundle = getArguments();
Integer offset = bundle.getInt(TagNames.OFFSET, 0);
Integer numberOfRows = bundle.getInt(TagNames.NUMBER_OF_ROWS, FinalVariables.GETTING_DATA_COUNT_FROM_API);
filterTypeId = bundle.getInt(TagNames.FILTER_TYPE_ID, FilterTypes.SUGGESTED);
String filterText = bundle.getString(TagNames.FILTER_TEXT, "");
Integer categoryId = bundle.getInt(TagNames.CATEGORY_ID, 0);
initArticleRecyclerViewAdapter(articleDetailsList, filterText, categoryId, offset, numberOfRows);
return parentView;
}
Initializing Adapter
private void initArticleRecyclerViewAdapter(List<ArticleDetails> articleDetailsList
, String filterText, Integer categoryId, int offset, int numberOfRows) {
articleRecyclerViewAdapter = new ArticleRecyclerViewAdapter(context, this.articleDetailsList, homeActivityViewModel, this);
articleRecyclerViewAdapter.setLoadMoreListener(new ArticleRecyclerViewAdapter.OnLoadMoreListener() {
#Override
public void onLoadMore() {
articleRecyclerView.post(new Runnable() {
#Override
public void run() {
int index = ArticleFragment.this.articleDetailsList.size();
loadMore(filterText, categoryId, index, numberOfRows);
Log.e(TAG, "scrolling,index: " + index);
}
});
//Calling loadMore function in Runnable to fix the
// java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling error
}
});
articleRecyclerView.setHasFixedSize(true);
articleRecyclerView.setLayoutManager(new GridLayoutManager(context, 3));
articleRecyclerView.setAdapter(articleRecyclerViewAdapter);
load(filterText, categoryId, offset, numberOfRows);
}
Loading data
private void loadMore(String filterText, Integer categoryId, int offset, int numberOfRows) {
//add loading progress view
articleDetailsList.add(new ArticleDetails(true));
articleRecyclerViewAdapter.notifyItemInserted(articleDetailsList.size() - 1);
Integer storeId = FileUtils.getPreferenceInt(context
, Preferences.CUSTOMER_PREFERENCE, TagNames.STORE_ID);
Integer distributionChannelId = FileUtils.getPreferenceInt(context
, Preferences.CUSTOMER_PREFERENCE, TagNames.DISTRIBUTION_CHANNEL_ID);
homeActivityViewModel.getAllStockItemByCustomer(
DeviceUtils.getCredential(context, ServiceNames.GET_ALL_STOCK_ITEM_BY_CUSTOMER)
, storeId, distributionChannelId, filterTypeId, filterText, categoryId, offset, numberOfRows
, new ApiCallbackListener() {
#Override
public void onSuccess(Object object) {
try {
if (object != null) {
if (object instanceof GetAllStockItemByCustomerStatusReturn) {
//otp generation failed,
GetAllStockItemByCustomerStatusReturn getAllStockItemByCustomerStatusReturn
= (GetAllStockItemByCustomerStatusReturn) object;
showGetAllStockItemByCustomerErrorDialog(getAllStockItemByCustomerStatusReturn);
} else if (object instanceof List) {
List<GetAllStockItemByCustomerResponseData> getAllStockItemByCustomerResponseDataList
= (List<GetAllStockItemByCustomerResponseData>) object;
//remove loading view
articleDetailsList.remove(articleDetailsList.size() - 1);
List<ArticleDetails> result = new ArrayList<>();
result = homeActivityViewModel.getArticles(getAllStockItemByCustomerResponseDataList);
homeActivityViewModel.insertAllStockItemByCustomer(context,filterTypeId
, getAllStockItemByCustomerResponseDataList, null);
if (result.size() > 0) {
//add loaded data
articleDetailsList.addAll(result);
} else {//result size 0 means there is no more data available at server
articleRecyclerViewAdapter.setMoreDataAvailable(false);
//telling articleRecyclerViewAdapter to stop calling load more as no more server data available
//Toast.makeText(context, "No More Data Available", Toast.LENGTH_LONG).show();
}
articleRecyclerViewAdapter.notifyDataChanged();
//should call the custom method articleRecyclerViewAdapter.notifyDataChanged here to get the correct loading status
} else {
MDToast.makeText(context, FinalVariables.ToastMessages.SOMETHING_WENT_WRONG
, MDToast.LENGTH_SHORT, MDToast.TYPE_WARNING).show();
}
} else {
MDToast.makeText(context, FinalVariables.ToastMessages.SOMETHING_WENT_WRONG
, MDToast.LENGTH_SHORT, MDToast.TYPE_WARNING).show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private void load(String filterText, Integer categoryId, int offset, int numberOfRows) {
Integer storeId = FileUtils.getPreferenceInt(context
, Preferences.CUSTOMER_PREFERENCE, TagNames.STORE_ID);
Integer distributionChannelId = FileUtils.getPreferenceInt(context
, Preferences.CUSTOMER_PREFERENCE, TagNames.DISTRIBUTION_CHANNEL_ID);
homeActivityViewModel.getAllStockItemByCustomer(
DeviceUtils.getCredential(context, ServiceNames.GET_ALL_STOCK_ITEM_BY_CUSTOMER)
, storeId, distributionChannelId, filterTypeId, filterText, categoryId, offset, numberOfRows
, new ApiCallbackListener() {
#Override
public void onSuccess(Object object) {
try {
if (object != null) {
if (object instanceof GetAllStockItemByCustomerStatusReturn) {
GetAllStockItemByCustomerStatusReturn getAllStockItemByCustomerStatusReturn
= (GetAllStockItemByCustomerStatusReturn) object;
showGetAllStockItemByCustomerErrorDialog(getAllStockItemByCustomerStatusReturn);
} else if (object instanceof List) {
List<GetAllStockItemByCustomerResponseData> getAllStockItemByCustomerResponseDataList
= (List<GetAllStockItemByCustomerResponseData>) object;
if (!getAllStockItemByCustomerResponseDataList.isEmpty()) {
if (offset == 0 && getAllStockItemByCustomerResponseDataList.get(0)
.getCategoryID() == StatusCodes.INVALID_CODE
&& filterTypeId == FilterTypes.SUGGESTED) {
//shows all article from store (filter type 0) if no article is mapped in suggested.
filterTypeId = FilterTypes.ALL;
load(filterText, categoryId, offset, numberOfRows);
}
}
articleDetailsList.addAll(homeActivityViewModel.getArticles(getAllStockItemByCustomerResponseDataList));
homeActivityViewModel.insertAllStockItemByCustomer(context,filterTypeId
, getAllStockItemByCustomerResponseDataList, null);
articleRecyclerViewAdapter.notifyDataChanged();
} else {
}
} else {
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
I implemented the displaying contacts with checkboxes. When I selected the multiple contacts and click the button it shows this error "
Attempt to invoke virtual method 'boolean
java.lang.Boolean.booleanValue()' on a null object reference"
. at mCustomAdapter.mCheckedStates.get(i). So i wrote like this in adapter class is "
mCheckedStates = new LongSparseArray<>(ContactList.size())
And again it shows the same error after assigning some value. When I print the size of the mCustomAdapter.mCheckedStates.size it show the correct value of how many contacts I selected but when getting the value it shows the error. How to solve that?
This is My adapter class :
public class Splitadapter extends BaseAdapter implements Filterable,CompoundButton.OnCheckedChangeListener
{
// public SparseBooleanArray mCheckStates;
LongSparseArray<Boolean> mCheckedStates = new LongSparseArray<>();
private ArrayList<COntactsModel> ContactList;
private Context mContext;
private LayoutInflater inflater;
private ValueFilter valueFilter;
ArrayList<COntactsModel> ContactListCopy ;
public Splitadapter(Context context, ArrayList<COntactsModel> ContactList) {
super();
mContext = context;
this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.ContactList = ContactList;
this.ContactListCopy = this.ContactList;
mCheckedStates = new LongSparseArray<>(ContactList.size());
System.out.println("asdfghjk" + mCheckedStates);
getFilter();
}//End of CustomAdapter constructor
#Override
public int getCount() {
return ContactListCopy.size();
}
#Override
public Object getItem(int position) {
return ContactListCopy.get(position).getName();
}
#Override
public long getItemId(int position) {
return ContactListCopy.get(position).getId();
}
public class ViewHolder {
TextView textviewName;
TextView textviewNumber;
CheckBox checkbox;
Button b;
int id;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
final int pos = position;
//
if (convertView == null) {
holder = new ViewHolder();
convertView = LayoutInflater.from(mContext).inflate(R.layout.list, null);
holder.textviewName = (TextView) convertView.findViewById(R.id.name);
holder.textviewNumber = (TextView) convertView.findViewById(R.id.mobile);
holder.checkbox = (CheckBox) convertView.findViewById(R.id.check);
holder.b = convertView.findViewById(R.id.round_icon);
convertView.setTag(holder);
}//End of if condition
else {
holder = (ViewHolder) convertView.getTag();
}//End of else
COntactsModel c = ContactListCopy.get(position);
holder.textviewName.setText(c.getName());
holder.textviewNumber.setText(c.getPhonenum());
holder.checkbox.setTag(c.getId());
holder.checkbox.setChecked(mCheckedStates.get(c.getId(), false));
holder.checkbox.setOnCheckedChangeListener(this);
holder.b.setText(c.getName().substring(0,1));
//holder.id = position;
return convertView;
// }//End of getView method
}
boolean isChecked(long id) {// it returns the checked contacts
return mCheckedStates.get(id, false);
}
void setChecked(long id, boolean isChecked) { //set checkbox postions if it sis checked
mCheckedStates.put(id, isChecked);
System.out.println("hello...........");
notifyDataSetChanged();
}
void toggle(long id) {
setChecked(id, !isChecked(id));
}
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
mCheckedStates.put((Long) buttonView.getTag(), true);
} else {
mCheckedStates.delete((Long) buttonView.getTag());
}
}
#Override
public Filter getFilter() {
if (valueFilter == null) {
valueFilter = new ValueFilter();
}
return valueFilter;
}
private class ValueFilter extends Filter {
//Invoked in a worker thread to filter the data according to the constraint.
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint != null && constraint.length() > 0) {
ArrayList<COntactsModel> filterList = new ArrayList<COntactsModel>();
for (int i = 0; i < ContactList.size(); i++) {
COntactsModel ca = ContactList.get(i);
if ((ca.getName().toUpperCase())
.contains(constraint.toString().toUpperCase())) {
//COntactsModel contacts = new COntactsModel();
filterList.add(ca);
}
}
results.count = filterList.size();
results.values = filterList;
} else {
results.count = ContactList.size();
results.values = ContactList;
}
return results;
}
//Invoked in the UI thread to publish the filtering results in the user interface.
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
ContactListCopy = (ArrayList<COntactsModel>) results.values;
notifyDataSetChanged();
}
}
}
This my Main Activity :
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
public static String TAG = "amount";
ListView mainListView;
ProgressDialog pd;
public static final int PERMISSIONS_REQUEST_READ_CONTACTS = 100;
final static List<String> name1 = new ArrayList<>();
List<String> phno1 = new ArrayList<>();
List<Long> bal = new ArrayList<>();
List<Bitmap> img = new ArrayList<>();
private Splitadapter mCustomAdapter;
private ArrayList<COntactsModel> _Contacts = new ArrayList<COntactsModel>();
HashSet<String> names = new HashSet<>();
Set<String>phonenumbers = new HashSet<>();
Button select;
int amount=100;
float result;
String ph;
String phoneNumber;
EditText search;
String contactID;
String name;
// private FirebaseAuth mAuth;
// FirebaseUser firebaseUser;
//
// FirebaseFirestore db = FirebaseFirestore.getInstance();
#SuppressLint("StaticFieldLeak")
#Override
protected void onCreate(Bundle savedInstanceState) {
setTitle("Split");
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
search = findViewById(R.id.search_bar);
final List<String> phonenumber = new ArrayList<>();
System.out.print(phonenumber);
mainListView = findViewById(R.id.listview);
showContacts();
select = findViewById(R.id.button1);
search.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
// When user chan ged the Text
mCustomAdapter.getFilter().filter(cs.toString());
//
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub
//ma.filter(text);
}
});
select.setOnClickListener(new View.OnClickListener() {
#SuppressLint("NewApi")
#Override
public void onClick(View v) {
StringBuilder checkedcontacts = new StringBuilder();
ArrayList checkedcontacts1 = new ArrayList();
ArrayList names = new ArrayList();
System.out.println(".............." + (mCustomAdapter.mCheckedStates.size()));
System.out.println("name size is" + name1.size());
int a = mCustomAdapter.mCheckedStates.size();
result = ((float) amount / a);
System.out.println("final1 amount is " + result);
long result1 = (long) result;
System.out.println("final amount is " + result1);
for (int k = 0; k < a; k++) {
bal.add(result1);
}
System.out.println("balance" + bal);
System.out.println("selected contacts split amount" + result);
System.out.println("names" + name1.size());
// int as = name1.size();
// mCustomAdapter.mCheckedStates = new LongSparseArray<>(as);
System.out.println("cjgygytygh" + mCustomAdapter.mCheckedStates);
for (int i = 0; i < name1.size(); i++) // it displays selected contacts with amount
{
System.out.println("checked contcts" + mCustomAdapter.mCheckedStates.get(i));
if (mCustomAdapter.mCheckedStates.get(i)) {
checkedcontacts.append(phno1.get(i)).append("\t").append("\t").append("\t").append(result1);
checkedcontacts1.add((phno1.get(i)));
names.add((name1.get(i)));
checkedcontacts.append("\n");
System.out.println("checked contacts:" + "\t" + phno1.get(i) + "\t" + "amount" + "\t" + result1);
}
}
System.out.println("checked names" + names);
System.out.println(
"checkec contcts foggfgfgfgfgf" + checkedcontacts1
);
List<Object> list = new ArrayList<>();
for (Object i : checkedcontacts1) {
list.add(i);
}
System.out.println("checked contacts size is" + checkedcontacts1.size());
HashMap<String, HashMap<String, Object>> Invites = new HashMap<>();
for (int i = 0; i < checkedcontacts1.size(); i++) {
HashMap<String, Object> entry = new HashMap<>();
entry.put("PhoneNumber", list.get(i));
entry.put("Name", names.get(i));
System.out.println("entry is" + entry);
for (int j = i; j <= i; j++) {
System.out.println("phonenumber" + i + ":" + list.get(i));
System.out.println("amount" + j + ":" + bal.get(j));
//dataToSave.put("phonenumber" +i, list.get(i));
entry.put("Amount", bal.get(j));
}
Invites.put("Invite" + i, entry);
}
Intent intent = new Intent(MainActivity.this, Display.class);
intent.putExtra("selected", checkedcontacts1.toString().split(","));
startActivity(intent);
}
});
}
private void showContacts() // it is for to check the build versions of android . if build version is >23 or above it is set the permissions at the run time . if the build version is less than 23 the we give the permissions at manifest file .
{if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, PERMISSIONS_REQUEST_READ_CONTACTS);
}
else {
mCustomAdapter = new Splitadapter(MainActivity.this,_Contacts);
//ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1,aa);
mainListView.setAdapter(mCustomAdapter);
mainListView.setOnItemClickListener(this);
mainListView.setItemsCanFocus(false);
mainListView.setTextFilterEnabled(true);
getAllContacts();
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, // it is display the request access permission dilogue box to access the contacts of user.
#NonNull int[] grantResults) {
if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission is granted
showContacts();
} else {
Toast.makeText(this, "Until you grant the permission, we canot display the names", Toast.LENGTH_SHORT).show();
}
}
}
private void getAllContacts() {
// it displays the contact phonenumber and name rom the phone book. and add to the list.
ContentResolver cr = getContentResolver();
String[] PROJECTION = new String[] {
ContactsContract.RawContacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.PHOTO_URI,
ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER,
ContactsContract.CommonDataKinds.Photo.CONTACT_ID };
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String filter = ""+ ContactsContract.Contacts.HAS_PHONE_NUMBER + " > 0 and " + ContactsContract.CommonDataKinds.Phone.TYPE +"=" + ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE;
String order = ContactsContract.Contacts.DISPLAY_NAME + " ASC";
Cursor phones = cr.query(uri, PROJECTION, filter, null, order);
while (phones.moveToNext()) {
long id = phones.getLong(phones.getColumnIndex(ContactsContract.Data._ID));
name = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
_Contacts.add(new COntactsModel(id,name,phoneNumber));
name1.add(name);
phno1.add(phoneNumber);
}
phones.close();
}
public static Bitmap loadContactPhoto(ContentResolver cr, long id) {
Uri uri = ContentUris.withAppendedId(
ContactsContract.Contacts.CONTENT_URI, id);
InputStream input = ContactsContract.Contacts
.openContactPhotoInputStream(cr, uri);
if (input == null) {
return null;
}
return BitmapFactory.decodeStream(input);
}
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
mCustomAdapter.toggle(arg3);
}
This my Model Class :
public class COntactsModel
{
String phonenum;
long id;
String cname;
boolean selected = false;
public COntactsModel(long id, String name,String phonenumber) {
this.id = id;
this.cname = name;
this.phonenum = phonenumber;
}
public long getId() {
return this.id;
}
public String getName() {
return this.cname;
}
public String getPhonenum() {
return this.phonenum;
}
}
How to solve that error?