Understanding MVVM on Android Tutorial 04 – Creating the View with RecyclerViews, CardViews and Picasso

We’ll display the results from our networking calls in a RecyclerView with CardViews and make use of the Picasso Image Library.

To use RecyclerView and CardView add the following lines to the app’s build.gradle

    compile 'com.android.support:recyclerview-v7:25.1.0'
    compile 'com.android.support:cardview-v7:25.1.0'

The Picasso Library is pulled in with the following line

    compile 'com.squareup.picasso:picasso:2.5.2'

The layout file for our Main Activity which includes the RecyclerView:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.kyubid.sample.mvvmtutorial.view.activities.MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/card_recycler_view"
        android:scrollbars="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
     </RelativeLayout>

The layout file for the CardView we’ll use with our RecyclerView:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cv"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="5dp"
    android:layout_marginRight="5dp"
    android:layout_marginTop="5dp"
    card_view:cardCornerRadius="5dp">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="10dp"
        android:orientation="vertical">


        <TextView
            android:id="@+id/textView_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            android:layout_marginTop="10dp"
            android:textSize="18sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/textView_id"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/textView_url"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <View
            android:layout_width="fill_parent"
            android:layout_height="1dp"
            android:layout_marginTop="10dp"
            android:background="#c0c0c0"/>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <android.support.v7.widget.AppCompatImageView
                android:id="@+id/imageView_Owner"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="5dp"
                android:orientation="vertical">

                <TextView
                    android:id="@+id/textView_Owner"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textSize="16sp" />

                <TextView
                    android:id="@+id/textView_OwnerUrl"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content" />


            </LinearLayout>

        </LinearLayout>

    </LinearLayout>


</android.support.v7.widget.CardView>

And our MainActivity, where we set the data received from the network response on our RecyclerView

    public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private List<Repo> data;
    private RecyclerAdapter adapter;

    String TAG = "MVVM Tutorial_MainActiv";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Initialise RecyclerView
        initViews();

        //Fetch results from GitHub API
        fetchGitHub();

    }

    private void initViews(){
        recyclerView = (RecyclerView)findViewById(R.id.card_recycler_view);
        recyclerView.setHasFixedSize(true);
        RecyclerView.LayoutManager layoutManager = new       
        LinearLayoutManager(getApplicationContext());
        recyclerView.setLayoutManager(layoutManager);
    }

    private void fetchGitHub() {
        Gson gson = new GsonBuilder()
                .create();
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(GithubService.ENDPOINT)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build();
        GithubService githubClient = retrofit.create(GithubService.class);

        // Fetch a list of the Github repositories.
        Call<List<Repo>> call = githubClient.reposForUser("square");

        // Execute the call asynchronously. 
        call.enqueue(new Callback<List<Repo>>() {
            @Override
            public void onResponse(Call<List<Repo>> call,    
            Response<List<Repo>> response) {
                // The network call was a success and we got a response
                data = response.body();
                adapter = new RecyclerAdapter(data);
                recyclerView.setAdapter(adapter);
            }

            @Override
            public void onFailure(Call<List<Repo>> call, Throwable t) {
                // the network call was a failure
                Log.d(TAG, "Error Occurred");
            }
        });
    }
}

Finally, the RecyclerAdapter we defined in the MainActivity that connects the RecyclerView , CardView and returned data together:

public class RecyclerAdapter extends RecyclerView.Adapter {
    private List<Repo> repos;
    private Context context;

    public  RecyclerAdapter(List repos) {
        this.repos = repos;
    }

    @Override
    public RecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        this.context = viewGroup.getContext();
        //Set our CardView here
        View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_row, 
        viewGroup, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final RecyclerAdapter.ViewHolder viewHolder, final  int i) {

        viewHolder.tvName.setText(repos.get(i).getName());
        viewHolder.tvId.setText("Id: " +String.valueOf(repos.get(i).getId()));
        viewHolder.tvUrl.setText(repos.get(i).getUrl());

        viewHolder.tvOwnerLogin.setText("Owner: " +repos.get(i).getOwner().getLogin());
        viewHolder.tvOwnerUrl.setText(repos.get(i).getOwner().getUrl());

        //Download image with Picasso
        Picasso.with(context)
                .load(repos.get(i).getOwner().getImageUrl())
                .resize(500, 500)
                .centerCrop()
                .into(viewHolder.ivOwner);

    }

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

    public class ViewHolder extends RecyclerView.ViewHolder{

        private TextView tvName,tvUrl,tvId, tvOwnerLogin, tvOwnerUrl;
        private ImageView ivOwner;

        public ViewHolder(View view) {
            super(view);

            tvName = (TextView)view.findViewById(R.id.textView_name);
            tvId = (TextView)view.findViewById(R.id.textView_id);
            tvUrl = (TextView)view.findViewById(R.id.textView_url);
            tvOwnerLogin = (TextView)view.findViewById(R.id.textView_Owner);
            tvOwnerUrl = (TextView)view.findViewById(R.id.textView_OwnerUrl);
            ivOwner = (ImageView) view.findViewById(R.id.imageView_Owner);

        }
    }
}

Our final result looks like this:

 

Upcoming posts in the series:
Understanding MVVM on Android Tutorial 05 – Creating the ViewModel with DataBinding
Understanding MVVM on Android Tutorial 06 – Going Reactive with RxJava

Leave a Reply