TheMovieDb API – Part 9 – Details awake!

Alrighty mighty! Welcome back to this series on implementing TheMovieDb API. As always remember all the code for this series will be in this GitHub repo today we are finishing up the movie details view and make it all show up:

Let’s go!

First create a MovieDetailsFragment and make it implement your previously created MovieDetailsContract interface:

public class MoviesFragment extends Fragment implements MovieItemClickListener,
        MoviesContract.View {

    public static final String TAG = "MoviesFragment";

    private ProgressBar progressBar;
    private MoviesAdapter moviesAdapter;
    private MoviesContract.UserActionsListener mActionsListener;

    public MoviesFragment() {
        // Required empty public constructor
    }

    public static MoviesFragment newInstance() {
        return new MoviesFragment();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
        moviesAdapter = new MoviesAdapter(getContext(), this);
        mActionsListener = new MoviesPresenter(ApiClient.createService(MovieServiceInterface.class), this);

        if (savedInstanceState == null) {
            mActionsListener.loadMovies();
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View root = inflater.inflate(R.layout.fragment_movies, container, false);
        progressBar = (ProgressBar) root.findViewById(R.id.progress_bar);
        RecyclerView recyclerView = (RecyclerView) root.findViewById(R.id.movies_recycler_view);
        recyclerView.setAdapter(moviesAdapter);
        recyclerView.setHasFixedSize(true);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.addItemDecoration(new MovieItemDecorator(getContext()));

        LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
        recyclerView.setLayoutManager(layoutManager);

        return root;
    }

    @Override
    public void onResume() {
        if (mActionsListener != null) {
            mActionsListener.setProgressBar(false);
            mActionsListener.loadMovies();
        }
        super.onResume();
    }

    @Override
    public void onMovieActionClick(View v, int position) {
        if (v.getId() == R.id.details) {
            //show details view
            Bundle args = new Bundle();
            args.putParcelable(Movie.PARCELABLE_KEY, moviesAdapter.get(position));
            getFragmentManager().beginTransaction()
                    .addToBackStack(MoviesFragment.TAG)
                    .replace(R.id.main_container, MovieDetailsFragment.newInstance(args))
                    .commit();
        }
    }

    @Override
    public void showProgressBar(boolean active) {
        if (active)
            progressBar.setVisibility(View.VISIBLE);
        else
            progressBar.setVisibility(View.INVISIBLE);
    }

    @Override
    public void showMovieDetailUi(Bundle movieArgs) {
        //nothing for now.
    }

    @Override
    public void setMovies(List<Movie> movies) {
        moviesAdapter.addAll(movies);
    }

    @Override
    public void clearMovies() {
        moviesAdapter.clear();
    }

    @Override
    public void showMessage(String msg, int duration) {
        if (getView() != null)
            Snackbar.make(getView(), msg, duration).show();
    }
}

See how clean is our fragment? That is thanks to our interface and its simple methods. Now how about the layout? Well mine is simply enough as you can see it only shows the backdrop image, poster image, title, release year and a overview of the movie, but hey does it look awesome!

<ScrollView 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"
    tools:context="com.jrosa.moviezone.details.MovieDetailsFragment">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ImageView
            android:id="@+id/movie_backdrop_image_view"
            android:layout_width="match_parent"
            android:layout_height="250dp"
            android:contentDescription="@string/content.desc.movie.details.backdrop.image"
            android:scaleType="centerCrop"
            tools:background="@drawable/test_movie_poster2" />

        <android.support.v7.widget.CardView
            android:layout_width="90dp"
            android:layout_height="120dp"
            android:layout_marginLeft="18dp"
            android:layout_marginRight="18dp"
            android:layout_marginTop="100dp"
            app:cardCornerRadius="4dp"
            app:cardElevation="8dp">

            <ImageView
                android:id="@+id/movie_poster_image_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:contentDescription="@string/content.desc.movie.details.poster.image"
                android:scaleType="centerCrop"
                tools:background="@drawable/test_movie2" />

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

        <TextView
            android:id="@+id/title"
            style="@style/TextAppearance.AppCompat.Title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/movie_backdrop_image_view"
            android:layout_marginTop="16dp"
            android:gravity="center"
            android:textColor="@color/colorAccent"
            tools:text="Star Wars - The force awakens" />


        <TextView
            android:id="@+id/release_date"
            style="@style/TextAppearance.AppCompat.Caption"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/title"
            android:gravity="center"
            tools:text="2015" />

        <android.support.v7.widget.AppCompatRatingBar
            android:id="@+id/popularity"
            style="?ratingBarStyleSmall"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/release_date"
            android:layout_centerHorizontal="true"
            android:isIndicator="true"
            android:numStars="10"
            tools:rating="8" />

        <TextView
            android:id="@+id/overview"
            style="@style/TextAppearance.AppCompat.Small"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/popularity"
            android:fontFamily="sans-serif-condensed"
            android:padding="16dp"
            tools:text="@string/movie.details.overview.base" />


    </RelativeLayout>
</ScrollView>

As you can observe, only a few components were used, the scrollview in my case is if the overview text is too long then users can swipe down to continue reading.

Finally let’s make the MoviesFragment show this awesome view! Go the current onMovieActionClick interface implementation that you previously placed and edit it to the following:

@Override
public void onMovieActionClick(View v, int position) {
    if (v.getId() == R.id.details) {
        //show details view
        Bundle args = new Bundle();
        args.putParcelable(Movie.PARCELABLE_KEY, moviesAdapter.get(position));
        getFragmentManager().beginTransaction()
                .addToBackStack(MoviesFragment.TAG)
                .replace(R.id.main_container, MovieDetailsFragment.newInstance(args))
                .commit();
    }
}

Notice how simple it is to pass a serialized version of our movie using the putParcelable() method. Remember also to .addToBackStack(fragmentName/Tag) the current fragment so we can have backwards navigation. Run it and delight with the result!

Final movie details
Final movie details

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Next time we are visiting the Reviews action button, stay tuned we are almost over!

Joel

TheMovieDb API – Part 8 – Show me more info!

Quickly open android studio! Welcome back to this series on implementing TheMovieDb API. As always remember all the code for this series will be in this GitHub repo today we are setting base to show off movie details!

Let’s begin! First since we are doing test driven development we want to keep our implementation separate, in other words, business logic outside of the UI. Create a MovieDetailsContract interface with the following:

public interface MovieDetailsContract {

    interface View {

        void setMoviePoster(String moviePoster);

        void setMovieBackdropImage(String backdropImage);

        void setTitle(String title);

        void setOverview(String overview);

        void setPopularity(Double popularity);

        void setReleaseDate(String releaseDate);
    }

    interface UserActionsListener {
        void showMovieDetails();
    }
}

Continue reading “TheMovieDb API – Part 8 – Show me more info!”

TheMovieDb API – Part 7 – Load and show

It’s finally time! Welcome back to this series on implementing TheMovieDb API. As always remember all the code for this series will be in this GitHub repo today we are taking all the building blocks created in previous posts and finally begin to show up the good stuff. Let’s get started!

First let’s create the fragment that will implement our MoviesContract.View that we created previously. Go ahead and use, if possible, the built in Fragment template leave the create resource/layout view option marked so Android Studio automatically generates it for you. Now you will have two new things one class representing your Fragment and a new layout.xml file for it. Here are mine:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.jrosa.moviezone.MoviesFragment">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/movies_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        tools:listitem="@layout/movie_view" />

    <ProgressBar
        android:id="@+id/progress_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center" />

</FrameLayout>

Continue reading “TheMovieDb API – Part 7 – Load and show”

TheMovieDb API – Part 6 – The Movies Adapter

Hey! welcome back to this series on implementing TheMovieDb API. As always remember all the code for this series will be in this GitHub repo today we are jumping straight to Java once more, last week post was all about the design of the Movie view today we are building the bridge that connects it all, the movies adapter.

Let’s go! First keep in mind this is 2016 and beyond we need to re-use our views and who better than the RecyclerView for that job? We are going to create something called a ‘ViewHolder’ which it’s only job is to hold a reference of the views within our movie_view.xml and give it to the RecyclerView each time a new Movie object is given to him and reuse it. This view holder should also implement an interface to handle clicks on our actions buttons, remember RecyclerView is a decoupled version of ListView meaning all of these does not come out of the box. Tricky right? Let’s see how this looks in action:

Let’s create our interface responsible for the action clicks, I called it MovieItemClickListener:

First the movie viewholder, mine I called it MovieSingleRowViewHolder:

public interface MovieItemClickListener {
    void onMovieActionClick(View v, int position);
}

Continue reading “TheMovieDb API – Part 6 – The Movies Adapter”

TheMovieDb API – Part 5 – Movie Layouts

Hey there! welcome back to this series on implementing TheMovieDb API. As always remember all the code for this series will be in this GitHub repo today we are getting away from Java code for a while and jumping to layout creation and xml files. We are going to set up a toolbar layout file so it can be reused, then prepare the activity_main needed views and finally a layout representation of a Movie item that later on our adapter will use to display sample movie information.

Let’s get started! Under app/src/main/res/layout create the following toolbar layout:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    android:elevation="6dp"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    app:layout_collapseMode="pin"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

Continue reading “TheMovieDb API – Part 5 – Movie Layouts”

TheMovieDb API – Part 4 – The Movie Presenter

Welcome back to this series on implementing TheMovieDb API. As always remember all the code for this series will be in this GitHub repo today we are going to setup and test our Movie Presenter, remember the MVP pattern? Awesome so let’s get right to it!

First let’s define what we want to do with a simple interface. We need to be able from the View to: show the progress bar, show details of the movie later on, set the movie lists to our adapter, clear movies out and show messages. So it should look something like:

public interface MoviesContract {
    /**
     * Represents the methods that our view (Activity or Fragment)
     * will implement.
     */
    interface View {

        void showProgressBar(boolean active);

        void showMovieDetailUi(Bundle movieArgs);

        void setMovies(List<Movie> movies);

        void clearMovies();

        void showMessage(String msg, int duration);
    }
...

Continue reading “TheMovieDb API – Part 4 – The Movie Presenter”

TheMovieDb API – Part 3 – Helper, helpers

Welcome back to this series on implementing TheMovieDb API. As always remember all the code for this series will be in this GitHub repo today we are going to set up what I like to call “tool chain” classes, just popped out of my mind, this classes contain methods that will make checking things like network status a breeze. Don’t worry today post is shorter o you can recap on the previous parts. Let’s begin! Continue reading “TheMovieDb API – Part 3 – Helper, helpers”

TheMovieDb API – Part 2 – Setting up Retrofit

Welcome back to implementing TheMovieDb API. As always remember all the code for this series will be in this GitHub repo today we are covering the popular type safe http client for Android called Retrofit. Retrofit allows us to turn out HTTP APIs into Java interfaces easy.

Now the first thing we need to make sure is that, since we are connecting to a web service, is that we have the INTERNET permission under our AndroidManifest.xml go ahead a place it like this:

<uses-permission android:name="android.permission.INTERNET" />

Once you have that cover let’s start by creating an ApiClient class that will serve as our “service generator” for the various endpoint options available from the API. Under app/src/main/java/your.package/ create a new class and place the following: Continue reading “TheMovieDb API – Part 2 – Setting up Retrofit”

TheMovieDb API – Part 1

It’s API time and TheMovieDb api is one of the best for learning and building an android application that connects to a REST service, saves offline through a Content Provider and can be unit tested thoroughly.

We will do it by parts so everyone can enjoy the full ride. I will assume you have already install Android Studio 2.0 from the official website. The code will be on this GitHub repo so you can view/download/doItYourself on the go.

First we will do a super refresh and create our android project, go ahead and launch Android Studio and click “Start a new Android Studio Project”

Android Studio
Android Studio

Continue reading “TheMovieDb API – Part 1”

This blog and why now

Hey there,

So it’s 2016 and Android is over 8 years old now since its first release 1.0. One can say that many APIs (Application Package Interfaces) have come and go in it and even that lots of blogs have arisen with the basics on this exciting and dominating mobile platform.

Android currently stands, in my opinion, mature where we don’t need guides about the basics, rather how to implement the more advanced stuff, this being Fused Location API, Advance Content Providers, Continuous Integration, Unit Testing and all that that implies and more.

Hopefully though the days to come you fill find such guide within this blog and bookmark/share with your friends and colleagues.  The content here will be very varied from Intents all the way to Location APIs and even encryption to continuous integration tools like Jenkins.

From now on you can expect daily content from Monday through Friday that will help you build your next android application and go beyond the limits with it.

Happy Coding,

Joel