# Display latest posts in Parstagram feed In this guide we will show step-by-step process of displaying last 20 items of your Parstagram feed using a `RecyclerView`. By this time you should be already familiar with `RecyclerView` and we encourage you to try to implement this task independently. You can refer to this guide when you run into issues to unblock yourself. In the end your app will look something like this: ![](https://i.imgur.com/Z3atqpt.gif) ## 1) Create a FeedActivity Let's create a new activity to show a RecyclerView of everyone's posts. Also create a button from your MainActivity to navigate to your FeedActivity. ## 2) Add RecyclerView to FeedActivity First let's add RecyclerView dependency to your app by modifying `build.gradle` file in the `app` folder: ```groovy= implementation "androidx.recyclerview:recyclerview:1.1.0" ``` Next, we will be adding `RecyclerView` to our `FeedActivity` layout file. Open `activity_main.xml` and add `androidx.recyclerview.widget.RecyclerView`. Give it a meaningful id, say `rvPosts`. You `activity_main.xml` might look like this: ```xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_margin="16dp" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".FeedActivity"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/rvPosts" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true" android:padding="8dp" /> </RelativeLayout> ``` Now, let's navigate to `FeedActivity` and create a variable for `RecyclerView`: ```java private RecyclerView rvPosts; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); rvPosts = findViewById(R.id.rvPosts); } ``` ## 3) Create layout for list item Go ahead and create a new layout file `item_post.xml`. This will be our model for every post in the feed. It needs to hold: * Author's name * Image * Description text ![](https://i.imgur.com/2xU86n1.png) Let's use `LinearLayout` with **vertical** orientation. We will add `TextView` for author's name, `ImageView` for the image, and another `TextView` for description. The image should take whole width of the layout. In the end your layout xml might look like this: ```xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="8dp" android:orientation="vertical"> <TextView android:id="@+id/tvUsername" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="TextView" android:textAppearance="@style/TextAppearance.AppCompat.Large" tools:text="rahul" /> <ImageView android:id="@+id/ivImage" android:layout_width="match_parent" android:layout_height="300dp" android:scaleType="centerCrop" tools:srcCompat="@tools:sample/avatars" /> <TextView android:id="@+id/tvDescription" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="8dp" tools:text="trying to look hipster" /> </LinearLayout> ``` Notice that we modify `android:textApperance` attribute for author's name to make it stand out. Also, we use `android:scaleType="centerCrop"` to imitate Parstagram crop and make sure the image aspect ratio is not affected when stretching image to match parent width. ## 4) Create RecyclerView Adapter As you might remember from previous assignments, Adapter connects `RecyclerView` to the data we want to display by providing `ViewHolder` and binding methods. Let's start by creating a new class `PostsAdapter` with and empty `ViewHolder`: ```java public class PostsAdapter extends RecyclerView.Adapter<PostsAdapter.ViewHolder> { @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return null; } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { } @Override public int getItemCount() { return 0; } class ViewHolder extends RecyclerView.ViewHolder { public ViewHolder(@NonNull View itemView) { super(itemView); } } } ``` Similar to our previous implementations we want to pass the `Context` and feed data into adapter. Create constructor and pass the parameters to store in member variables: ```java public class PostsAdapter extends RecyclerView.Adapter<PostsAdapter.ViewHolder> { private Context context; private List<Post> posts; public PostsAdapter(Context context, List<Post> posts) { this.context = context; this.posts = posts; } @Override public int getItemCount() { return posts.size(); } } ``` Next we will implement Adapter methods. For every visible item on the screen we want to inflate (create) a view. We use `LayoutInflater` and pass it a "blueprint" of the view (reference to XML layout file). Remember, that we want to wrap a view in a `ViewHolder` for easy access: ```java @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(context).inflate(R.layout.item_post, parent, false); return new ViewHolder(view); } ``` Whenever `RecyclerView` has to show an item to a user it will call `onBindViewHolder` with this item's position and `ViewHolder`. Here we should first get the post at this position. Then we can delegate binding to `ViewHolder`. ```java @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { Post post = posts.get(position); holder.bind(post); } ``` For ViewHolder we first need to find views and store references to them, so we can later access those views easily when binding data. In our case we have 2 `TextView`s and one `ImageView`: ```java class ViewHolder extends RecyclerView.ViewHolder { private TextView tvUsername; private ImageView ivImage; private TextView tvDescription; public ViewHolder(@NonNull View itemView) { super(itemView); tvUsername = itemView.findViewById(R.id.tvUsername); ivImage = itemView.findViewById(R.id.ivImage); tvDescription = itemView.findViewById(R.id.tvDescription); } } ``` Lastly we need to implement the `bind()` method that will update views to display a given post. We will load images using Glide library (refer to [this guide](https://guides.codepath.com/android/Displaying-Images-with-the-Glide-Library) if you need a refresher on using Glide): ```java public void bind(Post post) { // Bind the post data to the view elements tvDescription.setText(post.getDescription()); tvUsername.setText(post.getUser().getUsername()); ParseFile image = post.getImage(); if (image != null) { Glide.with(context).load(image.getUrl()).into(ivImage); } } ``` Now you should have a working `PostsAdapter` and `ViewHolder`. Let's switch back to `FeedActivity` and connect adapter to the Activity code: ```java public class FeedActivity extends AppCompatActivity { protected PostsAdapter adapter; protected List<Post> allPosts; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); rvPosts = findViewById(R.id.rvPosts); // initialize the array that will hold posts and create a PostsAdapter allPosts = new ArrayList<>(); adapter = new PostsAdapter(this, allPosts); } } ``` Next we need to get data to display by querying posts from your Parstagram feed. ## 5) Query Posts You should already have `Post` class from previous stories. Now, we want to query the Parstagram backend (our Parse server) to retrieve a list of the latest 20 posts in our feed. In your `FeedActivity` add `queryPosts()` method like this: ```java private void queryPosts() { // specify what type of data we want to query - Post.class ParseQuery<Post> query = ParseQuery.getQuery(Post.class); // include data referred by user key query.include(Post.KEY_USER); // limit query to latest 20 items query.setLimit(20); // order posts by creation date (newest first) query.addDescendingOrder("createdAt"); // start an asynchronous call for posts query.findInBackground(new FindCallback<Post>() { @Override public void done(List<Post> posts, ParseException e) { // check for errors if (e != null) { Log.e(TAG, "Issue with getting posts", e); return; } // for debugging purposes let's print every post description to logcat for (Post post : posts) { Log.i(TAG, "Post: " + post.getDescription() + ", username: " + post.getUser().getUsername()); } // save received posts to list and notify adapter of new data allPosts.addAll(posts); adapter.notifyDataSetChanged(); } }); } ``` In the snippet above we form request and set options such as order, max number of posts and additional data to include. Notice how we store received posts in the array we prepared before - `allPosts.addAll(posts);`. We also make a call to notify the Adapter of new data. It will force to invalidate existing items and re-bind data to `ViewHolder`s. ## 6) Putting it all together In your `FeedActivity` modify `onCreate()` method to set adapter for `RecyclerView`, add `LayoutManager` and finally query posts from Parstagram feed: ```java public class FeedActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); rvPosts = findViewById(R.id.rvPosts); allPosts = new ArrayList<>(); adapter = new PostsAdapter(this, allPosts); // set the adapter on the recycler view rvPosts.setAdapter(adapter); // set the layout manager on the recycler view rvPosts.setLayoutManager(new LinearLayoutManager(this)); // query posts from Parstagram queryPosts(); } } ``` Compile and run your application. You should see the list of the latests posts. ## Troubleshooting If you see no posts: - Make sure that your Parstagram account has Posts. - Check Logcat output for Exceptions or Errors. Verify that the posts are printed in logcat. - Open XML layout files and check that `RecyclerView` and `item_layout` has properly set `width` and `height` attributes. - See if `PostsAdapter` returns correct size of the items. - Ensure that you pass `allPosts` into adapter and not changing its reference later.