Some questions regarding data loading in RecyclerView Android

Hello guys,
I’m working on an Android application in which there is a RecyclerView where I load Feeds data: User Profile Picture, User name, Posted image, tag. Basically I’m working on a Social network app and want to know the following as I’m new to backendless.
Wanted to know the following:
I want to implement the Like feature. I set a button in the recyclerview item layout and than in backendless console I created a table called likes (int).
I use Feeds.java for retrieving all the objects from backendless to recyclerview.
The class has the set and get function like:
public int getLikes() {return likes;}
public void setLikes(int likes){this.likes = likes;}.
Now in the recyclerview adapter I set a onclick listener to the like button and there’s a textview to display total likes.
When the button is clicked I do the following :
int likesTotal = feeds.getLikes();
feeds.setLikes(likesTotal+1);
holder.likesCounter.setText(feeds.getLikes());
But the app closes when I click the button. Nothing showing in the log window.

  1. How can I achieve that? Get int, set int, update textview?
  2. I want to created a field of likers (multiple user names in 1 columns cell). I read that it can be achieved with relations but how? Can you give me some code snippet? I want to use this cell for checking if in that cell there’s current logged in user’s name and if there is than the like button will have the color red (initially it’s a heart with just borders and when user clicks on it it become completely red) so it will show that current user has liked the certain feed item.
  3. I want to implement the comment feature and I know that this can be achieved with relations but again how? Do I need to create 1 table for every feed item? If yes than there will be a huge amount of tables in the server lol. Please help.
  4. Is it possible to get the link of the certain feed to share on any messenger like Whatsapp so when user clicks on it the app will send the user to that feed post?

For now these are the questions I have.
I know I’m asking too much but please I need serious help.

Thanks

Need urgent help please

Hello, Asama!

Answering your questions:

  1. This question is not related to backendless. I can just offer you to debug this part of code and find out what line breaks your app.
  2. Yes, it can be accomplished using relations. Declare a relationship one-to-many named “usersThatLike” from table “Feeds” to “Users”, or a relation one-to-many from “Users” to “Feeds” named “likedFeeds”. After that you’ll be able to retrieve Users objects that “liked” this item. Here you can read more about relations: https://backendless.com/documentation/data/rest/data_relations.htm.
  3. No, you don’t need it. Just create table “Comments” and declare a relation from “Feeds” to it.
  4. Yes, declare a “link” field in your “Feeds” table and saved there the link. The only Backendless function you’ll use here would be storing the link in particular Feeds object.
    Before implementing your app I strongly offer you to read docs for relationships in Backendless. Here are some more links with docs and examples:
    https://backendless.com/documentation/data/android/data_relations_save_update.htm
    https://backendless.com/documentation/data/android/data_relations_delete.htm
    https://backendless.com/documentation/data/android/data_relations_retrieve.htm

best regards,
Alex

I want to generate the link for the entire item not to a single view in the item view in recyclerview. My recyclerview item layout contains 2 images and some tectviews. So the link should display full itemview. I know how to get the link of a singles item like pic. Bit how to generate link for entire itemview layout?
Can you please explain?

I tried to create a relation column called userThatLike in the Feeds table.

In Feeds class in my app project I added:

private Object userThatLike;

and set the get and set functions.
Than in my recyclerview adapter I get set the object like this:

String user = Backendless.UserService.CurrentUser.getObjectId();
feed.setUserThatLike(user);

It is saving the user in the relation column but how can I retrieve the user and do some checks?

Object newUser = feeds.getUserThatLike();
if (newUser.toString().contains(user)){
disable "like" button....
}

But this works partially. User can click the button once. Than if they click second time it is disabled. User close the than relaunch and than click on the same post’s like button and it isn’t disabled. Current user should already be added to the userThatLike column but this isn’t working. User is able to click the button once and than it’s like I explained before.
Please help

First of all, your “userThatLike” object should have type “List<BackendlessUser>” ( I guess that more than one user can “like” item, right? ).
Second: your code doesn’t save relation - you just put objectId of current user to the “userThatLike” field. In order to establish relation between Feeds object and User object, your code should look like this:

// getting current user
BackendlessUser currentUser = Backendless.UserService.CurrentUser();
// adding current user as one who "liked" feed, you should implement "adding" by yourself
feed.addUserThatLike( currentUser );
// saving changes to server
Backendless.Data.of( Feeds.class ).save( feed, new AsyncCallback&lt;Feeds&gt;{
  public void handleResponse( Feeds savedFeed ) {
    // disable "like" button here
  }


  public void handleFault( BackendlessFault fault )
  {
    // log error
  }
} );

But it’s not the end. The code above implements functionality of “liking”. But you also need functionality of showing “liked” items later. Here is how you can do it. When getting collection of “feeds” you’re going to show, you should find out whether current user already liked it. So, you should make “find” request to the server:

// configuring request parameters
QueryOptions options = new QueryOptions();
options.setRelated( Arrays.asList( "userThatLike" ) );
BackendlessDataQuery query = new BackendlessDataQuery();
query.setQueryOptions( options );


// getting all saved feeds with related users
Backendless.Data.of( Feeds.class ).find( query, new AsyncCallback&lt;BackendlessCollection&lt;Feeds&gt;> {
  public void handleResponse( BackendlessCollection&lt;Feeds&gt; response ) {
    String userId = Backendless.UserService.CurrentUser().getObjectId();
    for( Feeds feed : response ) {
      List&lt;BackendlessUser&gt; likedUsers = feed.getUserThatLiked();
      for( BackendlessUser user : likedUsers )
        if( user.getObjectId().equals( userId ) )
          // user found! disable "like" button and break the "for" cycle
    }
  }
  public void handleFault( BackendlessFault fault ) {
    // log error
  }
}  );

I tried to implement you code with some modifications to get rid of errors.

It’s working good. But there’s another problem I can’t figure out what but I think it’s in the line:

for (Feeds feed: response.getCurrentPage()) {
                    List&lt;BackendlessUser&gt; likedUsers = feeds.getUsersThatLike();

As you can see instead of using feed I’m using “feeds” to get the exact position of an item because if I use “feed” it changes the background of all my button in all the views:

List&lt;BackendlessUser&gt; likedUsers = feed.getUsersThatLike();

Posting my Adapter class and my Feeds class. Please help me.

public class FeedAdapter extends RecyclerView.Adapter&lt;FeedAdapter.FeedsHolder&gt; {

    private List&lt;Feeds&gt; list;
    private Context context;
    private static String TAG = "MainActivity";

    public FeedAdapter(Context context, List&lt;Feeds&gt; list) {
        this.context = context;
        this.list = list;

    }

    @Override
    public FeedsHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.feed_item, parent, false);
        return new FeedsHolder(view);
    }

    @Override
    public void onBindViewHolder(final FeedsHolder holder, int position) {
        //Starting Feeds
        final Feeds feeds = list.get(position);

        //Name
        holder.name.setText(feeds.getOwner());

        //Profile picture
        holder.profilePictureURL = feeds.getProfilePictureURL();

        //Image
        holder.imageURL = feeds.getImageUrl();

        //Getting date
        Date myD = feeds.getCreated();
        long ddate = myD.getTime();
        String myDate = String.valueOf(DateUtils.getRelativeTimeSpanString(ddate, System.currentTimeMillis(), DateUtils.SECOND_IN_MILLIS));
        holder.timeAgo.setText("• " + myDate);

        //Get total likes
        final int i = feeds.getLikes();

        //Query
        QueryOptions options = new QueryOptions();
        options.setRelated( Arrays.asList( "usersThatLike" ) );
        BackendlessDataQuery query = new BackendlessDataQuery();
        query.setQueryOptions( options );

        // getting all saved feeds with related users
        Backendless.Data.of(Feeds.class).find(query, new AsyncCallback&lt;BackendlessCollection&lt;Feeds&gt;>() {
            @Override
            public void handleResponse(BackendlessCollection&lt;Feeds&gt; response) {
                String userId = Backendless.UserService.CurrentUser().getObjectId();
                for (Feeds feed: response.getCurrentPage()) {
                    List&lt;BackendlessUser&gt; likedUsers = feeds.getUsersThatLike();
                    for (BackendlessUser user : likedUsers)
                        if (user.getObjectId().equals(userId)) {
                            Log.d(TAG, "No -------------------------------------");
                            holder.like.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.ic_star_rate_on));
                            holder.like.setOnClickListener(new View.OnClickListener() {
                                @Override
                                public void onClick(View v) {
                                    Toast.makeText(context, "You already like this item", Toast.LENGTH_SHORT).show();
                                }
                            });
                        } else {
                            holder.like.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.ic_star_rate_off));
                            holder.like.setOnClickListener(new View.OnClickListener() {
                                @Override
                                public void onClick(View v) {
                                    Log.d(TAG, "It should work +++++++++++++++++++++++++++++++");

                                    // getting current user
                                    Toast.makeText(context, "Arrived", Toast.LENGTH_SHORT).show();
                                    BackendlessUser currentUser = Backendless.UserService.CurrentUser();
                                    // adding current user as one who "liked" feed, you should implement "adding" by yourself
                                    List&lt;BackendlessUser&gt; list = new ArrayList&lt;&gt;();
                                    list.add(currentUser);
                                    feeds.setUsersThatLike(list);
                                    holder.like.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.ic_star_rate_on));
                                    smallBang.setmListener(new SmallBangListener() {
                                        @Override
                                        public void onAnimationStart() {
                                            holder.like.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.ic_star_rate_on));
                                        }

                                        @Override
                                        public void onAnimationEnd() {
                                            holder.like.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.ic_star_rate_on));
                                        }
                                    });
                                    feeds.setLikes(i + 1);
                                    Backendless.Data.of(Feeds.class).save(feeds, new AsyncCallback&lt;Feeds&gt;() {
                                        @Override
                                        public void handleResponse(Feeds feeds) {
                                            int likes = feeds.getLikes();
                                            if (likes == 1) {
                                                holder.likes.setText(i + 1 + " like");
                                            } else {
                                                holder.likes.setText(i + 1 + " likes");
                                            }
                                        }

                                        @Override
                                        public void handleFault(BackendlessFault backendlessFault) {

                                        }
                                    });


                                }
                            });
                        }
                }
            }

            @Override
            public void handleFault(BackendlessFault backendlessFault) {

            }
        });

        holder.status.setText(feeds.getStatus());
        String thisString = "no";
        String myImageString = "no";
        Picasso.with(context).load(holder.profilePictureURL).placeholder(R.drawable.placeholder).into(holder.profilePicture);
        String image = feeds.getIsImageUrlEmpty();
        if (!image.equals(myImageString)) {
            holder.image.setVisibility(View.GONE);
            holder.tagStatusBottom.setVisibility(View.VISIBLE);
            holder.tagImageBottom.setVisibility(View.GONE);
        } else {
            holder.image.setVisibility(View.VISIBLE);
            holder.tagStatusBottom.setVisibility(View.GONE);
            holder.tagImageBottom.setVisibility(View.VISIBLE);
            Picasso.with(context).load(holder.imageURL).placeholder(R.drawable.placeholder).into(holder.image);
        }
        String myString = feeds.getIsTagEmpty();
        if (myString.equals(thisString)){
            holder.tagImageBottom.setVisibility(View.VISIBLE);
            if (!image.equals(myImageString)) {
                holder.image.setVisibility(View.GONE);
                holder.tagStatusBottom.setVisibility(View.VISIBLE);
                holder.tagImageBottom.setVisibility(View.GONE);
            } else {
                holder.image.setVisibility(View.VISIBLE);
                holder.tagStatusBottom.setVisibility(View.GONE);
                holder.tagImageBottom.setVisibility(View.VISIBLE);
                Picasso.with(context).load(holder.imageURL).placeholder(R.drawable.placeholder).into(holder.image);
            }
        } else {
            holder.tagImageBottom.setVisibility(View.GONE);
            holder.tagStatusBottom.setVisibility(View.GONE);
        }
        String str = feeds.getTag();
        ArrayList&lt;int[]&gt; hashtagSpans1 = getSpans(str, '#');

        SpannableString commentsContent1 =
                new SpannableString(str);

        setSpanComment(commentsContent1, hashtagSpans1) ;
        holder.tagImageBottom.setText(commentsContent1);
        holder.tagStatusBottom.setText(commentsContent1);
        holder.tagImageBottom.setMovementMethod(LinkMovementMethod.getInstance());
        int likes = feeds.getLikes();
        if (likes == 1) {
            holder.likes.setText(i +" like");
        } else {
            holder.likes.setText(i +" likes");
        }
    }

    public ArrayList&lt;int[]&gt; getSpans(String body, char prefix) {
        ArrayList&lt;int[]&gt; spans = new ArrayList&lt;int[]&gt;();

        Pattern pattern = Pattern.compile(prefix + "\\w+");
        Matcher matcher = pattern.matcher(body);

        // Check all occurrences
        while (matcher.find()) {
            int[] currentSpan = new int[2];
            currentSpan[0] = matcher.start();
            currentSpan[1] = matcher.end();
            spans.add(currentSpan);
        }

        return  spans;
    }

    private void setSpanComment(SpannableString commentsContent, ArrayList&lt;int[]&gt; hashtagSpans) {
        for(int i = 0; i < hashtagSpans.size(); i++) {
            int[] span = hashtagSpans.get(i);
            int hashTagStart = span[0];
            int hashTagEnd = span[1];

            commentsContent.setSpan(new Hashtag(context),
                    hashTagStart,
                    hashTagEnd, 0);

        }


    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    public class FeedsHolder extends RecyclerView.ViewHolder {
        //Setup Views
        CardView card;
        TextView name;
        TextView tagImageBottom;
        TextView tagStatusBottom;
        TextView timeAgo;
        TextView likes;
        TextView comments;
        ImageView profilePicture;
        ImageView image;
        TextView status;
        String profilePictureURL;
        String imageURL;
        Button like;
        RelativeLayout likeLayout;

        public FeedsHolder(View itemView) {
            super(itemView);

            //Assign views by ID
            card = (CardView) itemView.findViewById(R.id.cv);
            name = (TextView) itemView.findViewById(R.id.person_name);
            tagImageBottom = (TextView) itemView.findViewById(R.id.tagImageBottom);
            tagStatusBottom = (TextView) itemView.findViewById(R.id.tagStatusBottom);
            status = (TextView) itemView.findViewById(R.id.status);
            timeAgo = (TextView) itemView.findViewById(R.id.timeStamp);
            profilePicture = (ImageView) itemView.findViewById(R.id.profilePicture);
            image = (ImageView) itemView.findViewById(R.id.picture);
            likes = (TextView) itemView.findViewById(R.id.likesCounter);
            comments = (TextView) itemView.findViewById(R.id.commentsCounter);
            like = (Button) itemView.findViewById(R.id.like);
            likeLayout = (RelativeLayout) itemView.findViewById(R.id.likeButton);
        }
    }
}
public class Feeds
{
    private String owner;
    private String tag;
    private String profilePictureURL;
    private String imageURL;
    private Date created;
    private Date updated;
    private String status;
    private int likes;
    private String isTagEmpty;
    private String isImageUrlEmpty;
    private List&lt;BackendlessUser&gt; usersThatLike;

    public String getOwner()
    {
        return owner;
    }

    public void setOwner( String owner )
    {
        this.owner = owner;
    }

    public int getLikes()
    {
        return likes;
    }

    public void setLikes ( int likes )
    {
        this.likes = likes;
    }

    public String getIsTagEmpty()
    {
        return isTagEmpty;
    }

    public void setIsTagEmpty ( String isTagEmpty )
    {
        this.isTagEmpty = isTagEmpty;
    }

    public String getIsImageUrlEmpty()
    {
        return isImageUrlEmpty;
    }

    public void setIsImageUrlEmpty ( String isImageUrlEmpty )
    {
        this.isImageUrlEmpty = isImageUrlEmpty;
    }

    public String getStatus()
    {
        return status;
    }

    public void setStatus( String status )
    {
        this.status = status;
    }

    public String getTag()
    {
        return tag;
    }

    public void setTag( String tag )
    {
        this.tag = tag;
    }

    public String getProfilePictureURL()
    {
        return profilePictureURL;
    }

    public void setProfilePictureURL ( String profilePictureURL )
    {
        this.profilePictureURL = profilePictureURL;
    }

    public String getImageUrl()
    {
        return imageURL;
    }

    public void setImageUrl ( String imageURL )
    {
        this.imageURL = imageURL;
    }

    public Date getCreated()
    {
        return created;
    }

    public Date getUpdated()
    {
        return updated;
    }

    public List&lt;BackendlessUser&gt; getUsersThatLike() {
        return usersThatLike;
    }

    public void setUsersThatLike(List&lt;BackendlessUser&gt; usersThatLike) {
        this.usersThatLike = usersThatLike;
    }
}

So basically now the problem is that the code checks the current user and compare with the Backendless user:

String userId = Backendless.UserService.CurrentUser().getObjectId();
for (Feeds feed: response.getCurrentPage()) {
    List&lt;BackendlessUser&gt; likedUsers = feeds.getUsersThatLike();
    for (BackendlessUser user : likedUsers)
        if (user.getObjectId().equals(userId)) { //do something} else {//do something};

But it’s returning always that “user” equals “userId” so I’m unable to put like on the posts. But I’m able to see the toast if I click the pot I already liked. This means that it returning always true.
I tried to create new posts and than tried to click the like button but it is like disabled and as you can see in my code I didn’t disabled it…
Help please. It’s urgent

Have you tried debugging your code to find out what exactly goes wrong? Obviously, there is a bug in the logic, but it’s not easy to find it without running application.
I’ve looked it through and I can only guess that you should retrieve Feeds objects one by one, using findById method. It looks like you always get “true” because the same object is retrieved first in collection.

Asama,

Sorry, we cannot scroll through pages of code and search for a problem. This is not what our support does (certainly not for free). Try to debug your code and narrow it down to the problem area. Then (if the problem is not resolved) post here in the form of a question “how do I do [xxx] with Backendless” or “how does [xxx] work” or “I am having problem with [xxx]”. Posting pages of code does not help.

Also, if it is urgent, consider purchasing a support plan… Responses on this forum are not guaranteed (certainly not by us).

Regards,
Mark

I apologize for disturbance guys.
Will try to find the bug.
Thanks for the help

Hello,

I’m here again to ask for your help because even debugging didn’t work.
It seems that the code is working just okay but the click isn’t working.
If you look at the following code and at the screenshot I attached you can see that it’s working and the check for either the user is present in the list or nor is working.

if (user.getObjectId().equals(userId)) { 
 holder.like.setBackgroundResource(R.drawable.ic_star_rate_on); 
 holder.like.setOnClickListener(new View.OnClickListener() { 
 @Override 
 public void onClick(View v) { 
 showToast(); 
 } 
 }); 
} else { 
 holder.like.setBackgroundResource(R.drawable.ic_star_rate_off); 
 //onclick in another function: setLike(holder.like,holder.likes,feeds); 
}


As you can see from my screenshot the code is working and the first item (the only one which I didn’t put like on) has the heart icon empty which means that I’m not present in the “usersThatLike” list column.
But the problem is that the click isn’t working. I tried to create a toast to check if click works and the toast isn’t showing up.
But if I click on an item which I liked (with heart icon filled) it shows me the toast which I put to check if it listens to my click…
Can you help me with it?

This support forum is strictly for Backendless-related issues. Any general problems outside of our APIs and backend services are not covered by support. Please consider posting to stackoverflow.com and/or Android forums.

Mark

Hello guys,
Sorry but I didn’t find any solution for my problem. Can you please post an example of Feed.class and FeedAdpater with just the relation table set and get?
I will be grateful to you.
I will explain what I want to do:
Create a button and set it’s background let’s say green. Create a class at backendless console called Feeds. Create a relation column called usersThatLiked. Than in my app set click listener. When user clicks the button app will check if the user is already present in the usersThatLiked column. If user isn’t there than it will add user to that list and set button background to red otherwise (if it’s present) do nothing.
Can you please post code snippet for this. I’m asking for code because I have a lot of code and as Mark said it’s difficult to check code pages to find bug. So it will be really easy for backendless support members to make it possible (after all they have developed it).
Thanks

Asama,

Please understand that we in Backendless Support cannot create custom examples for individual developers. The same applies to debugging their code. There are more than 1000 developers on support and we get a lot of requests. As a result, we have to stay focused on problems and questions as they relate specifically to our APIs. Requests where developers ask to create something specific for their app are not handled by support. This is done by another team which we call Professional Services. if you would like to get a quote, please contact our Sales at sales@backendless.com. It is very important to understand that there are limits when it comes to using free product and getting free support.

Mark

I apologize for that Mark.