Gallery does not show updated dataset - java

I have an activity that searches in a set of images. The images are displayed in a gallery. There is an EditText where the user can enter a search term. When the user enters text in the EditText the gallery is filtered according to the entered text.
I have made a SearchResultAdapter extends BaseAdapter implements Filterable which works basically fine. If the user enters a text the data in the adapter is filtered. I logged the results: It works so far. Then I call notifyAdapterSetChanged so the gallery shows the updated data set. notifyAdapterSetChanged is actually called and the request is received by the gallery as it calls my adapters getCount() (I logged all calls).
Setting the selection to 0 crashes the application due to IndexOutOfBoundsException as I expect it when the gallery has no items. Still the gallery shows all images that were in it before.
The problem is:
When the data set is empty (i.e. the user has entered a search term that does not fit to any image) then the gallery does not show the update. The gallery receives the notifyAdapterSetChanged, queries the adapter on the item count (which is 0) and updates the scroll limits. It does not update the images shown in the gallery. I can not scroll through the images anymore as there are basically no images to display, but the images are not removed from the gallery. It looks to the user as if the gallery froze.
When the invalid search term is deleted (i.e. the data set is not empty) then the gallery shows the correct images. Also under some conditions the gallery shows the empty list like when the application is minimized and then reopened. I can not reproduce the conditions however under which the gallery empties itself(apart from the minimizing/reopening of the application):
I have tried invalidating and requestLayout()ing the gallery, but it does not help. Does anyone know how I can make the gallery update the list of displayed images?
Here the log messages when the user enters a text that matches no image:
[SearchResultAdapter.SearchFilter] Results: 0
[SearchResultAdapter.SearchFilter] called notifyDataSetChanged()
[SearchResultAdapter.getCount()] getCount called: dateset size 0
[SearchResultAdapter.getCount()] getCount called: dateset size 0
Notice how the adapter is actually called by the gallery on the data set size
The initialising code in the activity:
final Gallery gallery = (Gallery) findViewById(R.id.search_results);
final SearchResultAdapter adapter = new SearchResultAdapter(this, gallery);
gallery.setAdapter(adapter);
EditText searchField = (EditText) findViewById(R.id.search_searchfield);
searchField.addTextChangedListener(new TextWatcher()
{
#Override
public void onTextChanged(CharSequence s, int start, int before,
int count)
{
// TODO unhardcode criterion
adapter.putFilterTerm(SearchCriteria.OFFERING, s.toString());
adapter.getFilter().filter(s);
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after)
{
// do nothing
}
#Override
public void afterTextChanged(Editable s)
{
// do nothing
}
});
And the SearchResultAdapter (lines that do not matter are left out):
public class SearchResultAdapter extends BaseAdapter implements Filterable
{
private Context context;
private Filter filter;
public void putFilterTerm(SearchCriteria key, String value)
{
filterTerms.put(key, value);
}
public boolean containsFilterTerm(SearchCriteria key)
{
return filterTerms.containsKey(key);
}
public String getFilterTerm(SearchCriteria key)
{
return filterTerms.get(key);
}
List<PageContainer> completeList = new ArrayList<PageContainer>();
List<PageContainer> currentList = new ArrayList<PageContainer>();
Map<SearchCriteria, String> filterTerms = new HashMap<SearchCriteria, String>();
View view;
public SearchResultAdapter(Context context, View gallery)
{
this.context = context;
this.view = gallery;
for (ContentPropertyContainer page : Model.getInstance()
.getRootContainer().getChildren())
{
completeList.add((PageContainer) page);
}
currentList.addAll(completeList);
}
#Override
public int getCount()
{
return currentList.size();
}
#Override
public Object getItem(int position)
{
return currentList.get(position);
}
#Override
public long getItemId(int position)
{
PageContainer item = currentList.get(position);
for (int i = 0; i < completeList.size(); ++i)
{
if (completeList.get(i) == item)
{
return i;
}
}
return -1;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View listview = convertView;
// Code left out here tries to reuse the convertView
// like Romain Guy said in a Google I/O Talk
return listview;
}
private class ResultList
{
ResultList(List<PageContainer> results)
{
this.results = results;
}
List<PageContainer> results;
}
#Override
public Filter getFilter()
{
// implements Filterable
if (filter == null)
{
filter = new SearchFilter();
}
return filter;
}
private class SearchFilter extends Filter
{
SearchFilter()
{
// do nothing, needed for visibility
}
#Override
protected FilterResults performFiltering(CharSequence constraint)
{
FilterResults results = new FilterResults();
// Code left out here filters the list
return results;
}
#Override
protected void publishResults(CharSequence constraint,
FilterResults results)
{
if (results == null)
{
return;
}
if (results.values instanceof ResultList)
{
currentList = ((ResultList) (results.values)).results;
notifyDataSetChanged();
}
}
}
}
EDIT:
Setting the visibility of the gallery to invisible and then to visible again solved the problem.
view.post(new Runnable()
{
#Override
public void run()
{
view.setVisibility(View.INVISIBLE);
view.setVisibility(View.VISIBLE);
}
});
Is there a better solution? This seems rather hackish to me.

Related

Array deletion taking place from the lower index first?

My app is in the foreground. and there are 2 items into a recyclerview list. whenever I delete my 2nd item from the list and after that click on the 1st item my app gets crash. and in Logcat I get the error like - java.lang.IndexOutOfBoundsException: Index: 1, Size: 1. But when I delete 1st item from my list and after that click on the remaining 2nd item my app works fine.
public void onClick(View v) {
onClick.onItemCli(position, banners.get(position));
}
I tried out by doing position -1 in this method like the below code.
public void onClick(View v) {
onClick.onItemCli(position-1, banners.get(position-1));
}
but by this case my app is crashing whenever there are 2 items in list and i click on 2nd item.
The error I am getting is :
java.lang.ArrayIndexOutOfBoundsException: length=12; index=-1
public class HeaderSliderAdapter extends RecyclerView.Adapter<HeaderSliderAdapter.ViewHolder> {
public List<Banner> banners;
public Context context;
private OnItemClicked onClick;
public HeaderSliderAdapter(Context context, List<Banner> banners) {
this.banners = banners;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.home_header, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final HeaderSliderAdapter.ViewHolder holder, final int position) {
if (TextUtils.isEmpty(banners.get(position).getmSliderImage())) {
holder.mSliderImageView.setImageResource(R.drawable.no_img_ava);
holder.mBackgroundImage.setVisibility(View.GONE);
} else {
Picasso.with(context)
.load(banners.get(position).getmSliderImage())
.fit()
.into(holder.mSliderImageView, new Callback() {
#Override
public void onSuccess() {
holder.mBackgroundImage.setVisibility(View.GONE);
holder.tvWarningFailedtoLoad.setVisibility(View.GONE);
holder.tvTitle.setVisibility(View.VISIBLE);
holder.mSliderImageView.setClickable(true);
}
#Override
public void onError() {
holder.mBackgroundImage.setVisibility(View.GONE);
holder.tvWarningFailedtoLoad.setVisibility(View.VISIBLE);
holder.tvTitle.setVisibility(View.GONE);
holder.mSliderImageView.setClickable(false);
}
});
}
holder.mSliderImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onClick.onItemCli(position, banners.get(position));
}
});
}
#Override
public int getItemCount() {
return banners.size(); }
public void setOnClick(OnItemClicked onClick) {
this.onClick = onClick;
}
public interface OnItemClicked {
void onItemCli(int position, Banner passData);
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ImageView mSliderImageView,mBackgroundImage;
public TextView tvWarningFailedtoLoad;
public TextView tvTitle;
View mView;
public ViewHolder(View itemView) {
super(itemView);
mView = itemView;
mSliderImageView = mView.findViewById(R.id.mSliderImage);
mBackgroundImage = mView.findViewById(R.id.backgroundImage);
tvWarningFailedtoLoad = mView.findViewById(R.id.tvFailedtoLoad);
tvTitle = mView.findViewById(R.id.mSliderImagetitle);
tvTitle.setSelected(true);
tvTitle.setSingleLine(true);
}
}
}
The error is getting in the below method.
holder.mSliderImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onClick.onItemCli(position, banners.get(position));
}
});
java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
I gues that the clue to your issue is in the following part of the documentation:
Note that unlike ListView, RecyclerView will not call this method again if the position of the item changes in the data set unless the item itself is invalidated or the new position cannot be determined. For this reason, you should only use the position parameter while acquiring the related data item inside this method and should not keep a copy of it. If you need the position of an item later on (e.g. in a click listener), use getAdapterPosition() which will have the updated adapter position. Override onBindViewHolder(ViewHolder, int, List) instead if Adapter can handle efficient partial bind.
So change the implementation of your setOnClickListener() method so it does not use the parametere position, but calls getAdapterPosition() instead to acquire the fresh value of your position.

Change the View visibility of all items of RecyclerView

I have a RecyclerView who play the recording when certain item is clicked. I want the behave when a user clicks on item1 that specific recording is playing and button View is changed which is working fine.
But at the same time when item1 recording is playing and user click on item2 then item1 row Button come back to its original position.
Below Image show the View when item1(Row 1) is clicked. (This is working fine)
I have also test this to control the View in inBindViewHolder method.But it is not working because whenever I clicked holder object control the View of current selected row only.
Below Code Section is placed in the ViewHolder
mPlayAudio.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
Log.d(TAG, "onClick: Present in onClick mPlayAudio");
if (listener != null)
{
final int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION)
{
// This section contain the code to play and stop
the audio
// Using below line I only able to change selected
// row button View not other row Button View
mPlayAudio.setImageResource(R.drawable.play);
}
}
}
});
I have also try this with in onBindViewHolder method but still not working.
Below Code added in onBindViewHolder
holder.mPlayAudio.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view)
{
// This section contain code to play and stop audio
//Using below statement I only able to change the
//visibility of current selected row View not others
holder.mPlayAudio.setImageResource(R.drawable.play);
}
}
So I finally was able to try this out on my own project.
Answer
In BindViewHolder, after you have made an item click, save the value of the position of that item. Then call notifyDataSetChanged inside the click event, which will refresh the adapter. Now it obtain your result, inside BindViewHolder have an if statement checking if that value should be set accordingly (or invisible), otherwise display as visible.
Example Code
public class SelectorAdapter extends RecyclerView.Adapter<SelectorAdapter.ItemHolder> implements View.OnClickListener {
private List itemList;
private int selectedKey;
public SelectorAdapter(List list) {
itemList = list;
}
#Override
public void onClick(View v) {
}
/* ViewHolder for each item */
class ItemHolder extends RecyclerView.ViewHolder {
//title
#BindView(R.id.selector_title)
TextView title;
#BindView(R.id.selector_layout)
LinearLayout selector;
ItemHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
#Override
public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_layout_selector, parent, false);
return new ItemHolder(itemView);
}
#Override
public void onBindViewHolder(ItemHolder holder, int position) {
String title = (String) itemList.get(position);
holder.title.setText(title);
if (position != selectedKey) {
holder.title.setBackgroundResource(R.drawable.selector);
} else {
holder.title.setBackgroundResource(R.drawable.selector_selected);
}
holder.itemView.setOnClickListener(v -> {
Timber.e("selected item: %s", position);
selectedKey = position;
notifyDataSetChanged();
});
}
#Override
public int getItemCount() {
Timber.e("itemCount: %s", itemList.size());
return itemList.size();
}
}
Here is my own project where when I select an item, it changes the background resource to selected, and then the rest are returned to the default state.

RecyclerView Adapter notifyItemChanged triggers twice

I'm trying to highlight my selected item in recyclerView when it's clicked.But it triggers two items instead. Please help me. Should i store clicked items as arraylist and clear them on new one clicked?
public class StationsAdapter extends RecyclerView.Adapter<StationsHolder> {
List<Station> stations;
public StationsAdapter(List<Station> stations){
this.stations = stations;
}
public void changeItemAtPosition(int position) {
notifyItemChanged(position);
}
#Override
public StationsHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new StationsHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.stations_item,parent,false));
}
#Override
public void onBindViewHolder(StationsHolder holder, int position) {
bind(holder);
}
private void bind(final StationsHolder holder) {
holder.tvTitle.setText(stations.get(holder.getAdapterPosition()).getName());
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder.tvTitle.setTextColor(ContextCompat.getColor(AppDelegate.getContext(),R.color.colorAccent));
}
});
}
#Override
public int getItemCount() {
return stations.size();
}
}
This is due to recycler reusing the same view when you scroll. In order to fix that, you will have to do the next:
Store the selected item when you click on it. In a variable or in an array if you want more than one item
Check the selected item variable/array in the bind method to know if you have to color it or not
That way it will work flawlessly

Android - Adding Views to Images doesn't update - onClick

Summary
When a user clicks on the RecyclerView item, I would like to add tags to that image from the information that has been stored in a BaaS [Sashido] (X Co-ordinates, Y Co-ordinates and Tag name). But, the problem I'm having isn't getting the position per-say. I create a toast when the image has been clicked, it shows the correct position corresponding to the view itself. (zero for the beginning, so on and so forth)
But how to update the position once the user clicks on another item in the list, so that the tags that correspond to the position in the array in Sashido, match the position in the RecyclerView, because at the moment the first row in the Sashido class is populating all images with that row's tags.
My assumption was to the pass the position to the getTagInformation() method using getLayoutPosition() so that when objects.get(position) array is called, it'll get the same position for Sashido class but it isn't. I feel the adapter must not be updating correctly after the user has clicked on a new item.
onBindViewHolder:
#Override
public void onBindViewHolder(RecyclerViewHolderPreviousPosts holder, int position) {
holder.bind(previousPostsList.get(position), listener);
}
onBind:
void bind(final PreviousPostsDataModel model, final OnItemClickListener listener) { ...
uploadedImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (count == 0) {
imageid = model.getImageId();
Toast.makeText(App.getContext(), "Image ID: " + imageid, Toast.LENGTH_SHORT).show();
Toast.makeText(App.getContext(), "Position: " + getAdapterPosition(), Toast.LENGTH_SHORT).show();
getTagInformation(getLayoutPosition());
} else {
Log.e("qwert", "" + imageid);
imageContainer.removeAllViews();
imageContainer.addView(uploadedImage);
count = 0;
}
}
});
... }
getTagInformation:
private void getTagInformation(final int position) {
ParseQuery<ParseObject> query = ParseQuery.getQuery("FashionFeed");
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> objects, ParseException e) {
if (e == null) {
Toast.makeText(context, "" + position, Toast.LENGTH_SHORT).show();
JSONArray tagNamesArray = objects.get(position).getJSONArray("tagName");
JSONArray posXArray = objects.get(position).getJSONArray("tagPointX");
JSONArray posYArray = objects.get(position).getJSONArray("tagPointY");
for (int i = 0; i < tagNamesArray.length(); i++) {
for (int t = 0; t < tagNamesArray.length(); t++) {
tagNames.add(tagNamesArray.optString(t));
tagXPositions.add(posXArray.optString(t));
tagYPositions.add(posYArray.optString(t));
}
for (int o = 0; o < tagNamesArray.length(); o++) {
tag = new TextView(App.getContext());
tag.setX(Float.parseFloat(tagXPositions.get(o)));
tag.setY(Float.parseFloat(tagYPositions.get(o)));
tag.setText(tagNames.get(o));
tag.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
tag.setMaxLines(1);
tag.setTextSize(11);
tag.setClickable(true);
tag.setHintTextColor(Color.WHITE);
tag.setTextColor(Color.WHITE);
tag.setBackgroundResource(R.drawable.tags_rounded_corners);
imageContainer.addView(tag);
count = 1;
}
}
} else {
Toast.makeText(context, "" + e.getMessage(), Toast.LENGTH_LONG).show();
}
}
});
}
I have also tried
public void getTagInformation(String imageid) {
ParseQuery query = ParseQuery.getQuery("FashionFeed");
query.WhereEqualTo("objectId", imageId);
....
}
with the imageId passed into the method and with also me manually entering an objectId that will match, it'll still only produce the tags that belong to that objectId. it just doesn't seem that this query is going through all of the objects. Just getting the tag information from that one object and then setting all the images with those tags.
if you need me to provide anymore code, I'm more than happy to.
Hi #BIW please follow below link link
In onBindViewHolder, you are adding listener every time, so it returns same object every time as recyclerView ViewHolder pattern uses same object to render recyclerView item in onBindViewHolder. So you need to add when you are creating holder object and set listener to it so that you will get a proper position.
package com.subbu.moviemasti.adapter;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.squareup.picasso.Picasso;
import com.subbu.moviemasti.Constants;
import com.subbu.moviemasti.R;
import com.subbu.moviemasti.entities.Movie;
import java.util.List;
import butterknife.Bind;
import butterknife.ButterKnife;
/**
* Created by subrahmanyam on 25-11-2015.
*/
public class MovieAdapter extends RecyclerView.Adapter<MovieAdapter.ViewHolder> {
private final List<Movie> movieList;
private onRecyclerViewItemClickListener mItemClickListener;
public MovieAdapter(List<Movie> movieList) {
this.movieList = movieList;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.grid_item, null);
ViewHolder holder = new ViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
final Movie movie = movieList.get(position);
String imageUrl = Constants.MOVIE_POSTER_BASE_URL + movie.getPosterPath();
if (imageUrl != null) {
Picasso.with(holder.posterImage.getContext()).load(imageUrl).
placeholder(R.drawable.img_default).
into(holder.posterImage);
}
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public int getItemCount() {
return movieList.size();
}
public void setOnItemClickListener(onRecyclerViewItemClickListener mItemClickListener) {
this.mItemClickListener = mItemClickListener;
}
public interface onRecyclerViewItemClickListener {
void onItemClickListener(View view, int position);
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
#Bind(R.id.poster)
ImageView posterImage;
public ViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
view.setOnClickListener(this);
}
#Override
public void onClick(View v) {
mItemClickListener.onItemClickListener(v, getAdapterPosition());
}
}
}
Where we are creating adaper object, from there we need to set listener
like adapter.setOnItemClickListener(this)
class MyActivity extendsActivity implements onRecyclerViewItemClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
manager = new GridLayoutManager(getActivity(), cols);
gridView.setLayoutManager(manager);
gridView.setAdapter(adapter);
adapter.setOnItemClickListener(this);
}
#Override
public void onItemClickListener(View view, int position) {
//Do wantever you want to do
}
}
From ViewHolder class we need to pass position of a recyclerView or we can write code what you need to execute when click on item.
Solved the problem. It wasn't so much that the position was wrong, it was because I was trying to find the tags before I was populating the list of images due to Parse's FindInBackground() callback, it was being populated far too late.
The solution was that I got the JSONArray that contained the Tag names, x-coordindates and y co-ordinates inside the original query that was populating the original list of images. So they would execute simultaneously, then I passed the JSONArray values into the model, which then was passed to the bind() function in the Adapter.
Before, the problem was that the adapter was binding all of the tags onto every image, so when the click event happened on the image it would only add the tag to the imageContainer that was currently selected (in the current position), not any partiular view in any particular position.
This made it so every time the image was clicked it was always finding the first object in the database and assigning it to the selected image. [due to the click event triggering the getTagInformation() function).
With the automation of the getTagInformation method within the Bind function of the ViewHolder, I was able to populate every image with the correct tags and further manipulate it using an onClickListener assigned to the image as shown below:
RecyclerView Holder:
public class RecyclerViewHolderPreviousPosts extends RecyclerView.ViewHolder implements View.OnClickListener {
// View holder for gridview recycler view as we used in listview
public TextView createdAt;
public ImageView uploadedImage;
public TextView caption;
TextView number_of_likes;
TextView number_of_comments;
TextView number_of_tags;
public ImageView comments;
public RelativeLayout imageContainer;
RecyclerViewHolderPreviousPosts(View view) {
super(view);
// Find all views ids
this.createdAt = (TextView) view
.findViewById(R.id.created_date);
this.uploadedImage = (ImageView) view
.findViewById(R.id.image);
this.caption = (TextView) view
.findViewById(R.id.caption_post);
this.number_of_likes = (TextView) view
.findViewById(R.id.number_of_likes);
this.number_of_comments = (TextView) view
.findViewById(R.id.number_of_comments);
this.number_of_tags = (TextView) view
.findViewById(R.id.number_of_tags);
this.comments = (ImageView) view
.findViewById(R.id.comments_image);
this.imageContainer = (RelativeLayout) view
.findViewById(R.id.image_container);
view.setOnClickListener(this);
}
void bind(PreviousPostsDataModel model1, final int position) { ....
model = previousPostsList.get(position);
getTagInformation();
....}
private void getTagInformation() {
for (int o = 0; o < model.getTagSize(); o++) {
tag = new TextView(App.getContext());
tag.setX(Float.parseFloat(model.getXpoints(o)));
tag.setY(Float.parseFloat(model.getYpoints(o)));
Log.e("x", "" + tag.getX());
Log.e("y", "" + tag.getY());
tag.setText(model.getTagName(o));
tag.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
tag.setMaxLines(1);
tag.setTextSize(11);
tag.setClickable(true);
tag.setHintTextColor(Color.WHITE);
tag.setTextColor(Color.WHITE);
tag.setBackgroundResource(R.drawable.tags_rounded_corners);
imageContainer.addView(tag);
tags.add(tag);
}
}
#Override
public void onClick(View v) {
if (count == 0) {
for (int i = 0; i < tags.size(); i++) {
tags.get(i).setVisibility(View.INVISIBLE);
}
count = 1;
}
else {
for (int j = 0; j < tags.size(); j++) {
tags.get(j).setVisibility(View.VISIBLE);
}
count = 0;
}
}
}
Profile Fragment [Original Query] :
private void populateSelectedUserRecyclerView(String objectid) {
ParseQuery<ParseObject> query = ParseQuery.getQuery("FashionFeed");
query.whereEqualTo("uploader", ParseObject.createWithoutData("_User", objectid));
query.orderByDescending("createdAt");
Log.e("get order", "ordered");
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> objects, ParseException e) {
Log.e("gets done", "gets into done");
if(e == null) {
if (objects.size() > 0) {
Log.e("does it get here", "it got here");
latestPostList = new ArrayList<>();
for (ParseObject j : objects) {
JSONArray tagNamesArray = j.getJSONArray("tagName");
JSONArray posXArray = j.getJSONArray("tagPointX");
JSONArray posYArray = j.getJSONArray("tagPointY");
latestPostList.add(new PreviousPostsDataModel(tagNamesArray, posXArray, posYArray));
}
}
else {
no_follow_display.setVisibility(View.VISIBLE);
no_follow_display.setText(R.string.no_posts);
no_follow_display.bringToFront();
recyclerView.setVisibility(View.GONE);
}
adapter = new RecyclerViewAdapterPreviousPosts(getActivity(), latestPostList, listener);
recyclerView.setAdapter(adapter);// set adapter on recyclerview
adapter.notifyDataSetChanged();
}
else {
Log.e("failed", "failed" + e.getMessage());
}
}
});
}
Thanks for your help.
If I understand correctly question the problem is that ParseQuery don't return objects in the same order. So the assumptions that position of object in Your RecycleView is the same as in ParseDatabase is wrong.
If u want to get TAG from Sashido You should firstly make some relations to Images e.g additional column. Then make query white extra parameter like:
private static final String UNIQ_TAG_ID= "tagId";
query.whereContainedIn(UNIQ_TAG_ID, id);
or get All ParseObjects like u doing now and find that TAG that correspond to Your image, then take info.

Able to click on two items at the same time in a RecyclerView

I have a list of items in a RecyclerView and i set the onClickListener in the onBindViewHolder for each view. The click listener works just fine, the issue is that I can click on two items in the list at the same time and both of them will run their onClick method. When you have ListViews if you try to click on two items at the same time it does not allow you.
For example:
Lets say you are already touching on an item in a listview and during that time you try to touch another item it won't let you. Recyclerview allows that.
How can we make the RecyclerView to work like a ListView for when clicking?
Below is my implementation
public class DataCardAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context mContext;
private ArrayList<Data> mDatas = new ArrayList<>();
private Data mData;
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View card = LayoutInflater.from(mContext).inflate(R.layout.card, parent, false);
return new DataCardViewHolder(mContext, card, mData);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Data data = mDatas.get(position);
((DataCardViewHolder )holder).configureDataCard(data);
}
public static class DataCardViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private Context mContext;
private Data mData;
public DataCardViewHolder(Context context, View view, Data data) {
super(view);
mContext = context;
mData= data;
}
public void configureDataCard(final Data data) {
mData= data;
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Log.v("DataCardViewHolder","onClick with data: " + mData.getData().toString());
}
}
}
My RecyclerView is programmatically add in Java but not in xml. And I try this and it works:
mRecyclerView.setMotionEventSplittingEnabled(false);
If your RecyclerView is add in xml, you may try adding this in your RecyclerView:
android:splitMotionEvents="false"
And now in the recycler-list when you click on one item and don't let go, you can not click another item.
Unfortunately, RecyclerView will not handle that for you. Create a Handler with timeout:
public class DelayedClick {
protected boolean canClick = true;
protected Handler myHandler = new Handler();
private Runnable mMyRunnable = new Runnable()
{
#Override
public void run() {
canClick = true;
}
};
public boolean getState() {
if(canClick) {
myHandler.postDelayed(mMyRunnable, 200);
canClick = false;
return true;
}
else return false;
}
}
#Override
public void onClick(View v) {
if (!reClick.getState()) {
return;
}
//Code to execute on click
}

Categories

Resources