android parcelable

Android Parcelable example – Passing Objects via Bundle!

In this article, we are going to look at Android Parcelable example by passing objects via bundle between activities and fragments. Although there are no prerequisites for this tutorial, here I am going to take the Movie Board project that we’ve been building in our previous posts and implement Parcelable to it and pass the objects via bundle.

The completed project can be downloaded from the following github repository link:

Android Parcelable Example

So lets dive into the required steps to complete the Android Parcelable Example.

1. Making our Model Class implement Android Parcelable:

[widget id=”text-15″]

Our previous project of Movie Board consists of a Model class named Movie.java which consists of the following code previously:

package com.coderefer.firebasedatabaseexample.models;

/**
 * Created by vamsi tallapudi on 18-Jul-16 for Android Parcelable Eg.
 */

public class Movie {

    public String movieName;
    public String moviePoster;
    public float movieRating;

    public Movie(){

    }
    public Movie(String movieName,String moviePoster,float movieRating){
        this.movieName = movieName;
        this.moviePoster = moviePoster;
        this.movieRating  = movieRating;
    }

    public String getMovieName() {
        return movieName;
    }

    public void setMovieName(String movieName) {
        this.movieName = movieName;
    }

    public String getMoviePoster() {
        return moviePoster;
    }
 
    public void setMoviePoster(String moviePoster) {
        this.moviePoster = moviePoster;
    }

    public float getMovieRating() {
        return movieRating;
    }

    public void setMovieRating(float movieRating) {
        this.movieRating = movieRating;
    }
}

Now lets implement Android Parcelable class to the above class so that we can pass the Object for the Movie class via Bundle between activities/ fragments.

[widget id=”text-3″]

The above class after implementing Android parcelable will be as follows:

package com.coderefer.firebasedatabaseexample.models;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by vamsi on 18-Jul-16 for Android Parcelable Eg.
 */
//implementation of Android Parcelable
public class Movie implements Parcelable{

    public String movieName;
    public String moviePoster;
    public float movieRating;

    public Movie(){

    }
    public Movie(String movieName,String moviePoster,float movieRating){
        this.movieName = movieName;
        this.moviePoster = moviePoster;
        this.movieRating  = movieRating;
    }

    protected Movie(Parcel in) {
        movieName = in.readString();
        moviePoster = in.readString();
        movieRating = in.readFloat();
    }

    public static final Creator<Movie> CREATOR = new Creator<Movie>() {
        @Override
        public Movie createFromParcel(Parcel in) {
            return new Movie(in);
        }

        @Override
        public Movie[] newArray(int size) {
            return new Movie[size];
        }
    };

    public String getMovieName() {
        return movieName;
    }

    public void setMovieName(String movieName) {
        this.movieName = movieName;
    }

    public String getMoviePoster() {
        return moviePoster;
    }

    public void setMoviePoster(String moviePoster) {
        this.moviePoster = moviePoster;
    }

    public float getMovieRating() {
        return movieRating;
    }

    public void setMovieRating(float movieRating) {
        this.movieRating = movieRating;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(movieName);
        dest.writeString(moviePoster);
        dest.writeFloat(movieRating);
    }
}

2. Creating our second screen:

Now lets create our second screen for which we will pass our data into.

[widget id=”text-3″]

First, I am going to create a layout using our previous example on Android Collapsing Toolbar Layout. I am going to name the required layout files as content_collapsible_toolbar.xml and movie_detail_fragment.xml and write the following codes to them.

content_collapsible_toolbar.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?android:windowBackground">

    <TextView
        android:id="@+id/tv_detail_heading"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/com_facebook_likeboxcountview_caret_width"
        android:gravity="center"
        android:textColor="@android:color/holo_red_light"
        android:textColorLink="@color/colorPrimary"
        android:textSize="24sp"
        android:textStyle="bold"
        tools:text="Sample text Heading" />

    <RatingBar
        android:id="@+id/rating_detail"
        android:layout_marginTop="150dp"
        android:layout_width="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_height="wrap_content"
        android:numStars="5"
        tools:rating="2.5"
        android:isIndicator="true" />
</LinearLayout>

movie_detail_fragment.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    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:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.coderefer.firebasedatabaseexample.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/app_bar_layout"
        android:fitsSystemWindows="true"
        app:elevation="0dp"
        android:theme="@style/AppTheme.AppBarOverlay">


        <android.support.design.widget.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/collapsing_toolbar"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="350dp"
                android:scaleType="centerCrop"
                android:fitsSystemWindows="true"
                android:id="@+id/iv_detail"
                android:src="@drawable/placeholder"
                app:layout_collapseMode="parallax"/>

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"/>

        </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
        <include layout="@layout/content_collapsible_toolbar"/>
    </android.support.v4.widget.NestedScrollView>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        app:layout_anchor="@id/app_bar_layout"
        app:layout_anchorGravity="bottom|right|end"
        app:srcCompat="@android:drawable/ic_menu_share"/>
</android.support.design.widget.CoordinatorLayout>

Lets wire the above layout in java code by using a class extending Fragment, named MovieDetailFragment.java and write the following code:

package com.coderefer.firebasedatabaseexample.fragments;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RatingBar;
import android.widget.TextView;

import com.coderefer.firebasedatabaseexample.MainActivity;
import com.coderefer.firebasedatabaseexample.R;
import com.coderefer.firebasedatabaseexample.models.Movie;
import com.squareup.picasso.Picasso;

/**
 * Created by vamsitallapudi on 5/22/17 for Android Parcelable Eg.
 */

public class MovieDetailFragment extends Fragment {

    private Movie movie;
    private ImageView ivDetailBanner;
    private TextView tvDetailHeading;
    private RatingBar mRatingBar;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.movie_detail_fragment, container, false);
        if (getArguments() != null) {
            movie = getArguments().getParcelable(MainActivity.MOVIE_KEY);
        }
        if (movie != null) {
            initializeViews(view);
            Picasso.with(getActivity()).load(movie.getMoviePoster()).into(ivDetailBanner);
            tvDetailHeading.setText(movie.getMovieName());
            mRatingBar.setRating(movie.getMovieRating());
        }
        return view;
    }

    private void initializeViews(View view) {
        ivDetailBanner = (ImageView) view.findViewById(R.id.iv_detail);
        tvDetailHeading = (TextView) view.findViewById(R.id.tv_detail_heading);
        mRatingBar = (RatingBar) view.findViewById(R.id.rating_detail);
    }
}

3. Implementing Listener to go to second screen:

The only thing remaining is to implement a touch listener to our recyclerview so that we can navigate to second screen along with the bundle which consists Movie Object of the recycler item which was clicked.

[widget id=”text-15″]

Lets call the method addOnItemTouchListener of our RecyclerView in our MainActivity.java.

     mRecyclerView.addOnItemTouchListener(new RecyclerItemClickListener(this, new RecyclerItemClickListener.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(MainActivity.this, "Card at " + position + " is clicked", Toast.LENGTH_SHORT).show();
                Movie movie = adapter.getItem(position);
                //creating a bundle in order to pass data to other component
                Bundle bundle = new Bundle();
                bundle.putParcelable(MOVIE_KEY,movie);
                MovieDetailFragment fragment = new MovieDetailFragment();
                fragment.setArguments(bundle);//passing data to fragment
                getSupportFragmentManager().beginTransaction()
                        .replace(R.id.frame_container, fragment)
                        .addToBackStack(null)
                        .commit();

            }
        }));

Notice how bundle is created and is passed from activity to fragment. Now my Complete Activity will be as follows:

MainActivity.java:

[widget id=”text-3″]
package com.coderefer.firebasedatabaseexample;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
import android.widget.ImageView;
import android.widget.RatingBar;
import android.widget.TextView;
import android.widget.Toast;

import com.coderefer.firebasedatabaseexample.fragments.AddMovieFragment;
import com.coderefer.firebasedatabaseexample.fragments.MovieDetailFragment;
import com.coderefer.firebasedatabaseexample.models.Movie;
import com.coderefer.firebasedatabaseexample.util.RecyclerItemClickListener;
import com.firebase.ui.database.FirebaseRecyclerAdapter;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.squareup.picasso.Picasso;

public class MainActivity extends AppCompatActivity {

    private FloatingActionButton fab;

    ScaleAnimation shrinkAnim;
    private RecyclerView mRecyclerView;
    private StaggeredGridLayoutManager mLayoutManager;
    private TextView tvNoMovies;

    //Getting reference to Firebase Database
    FirebaseDatabase database = FirebaseDatabase.getInstance();
    DatabaseReference mDatabaseReference = database.getReference();

    private static final String USER_ID = "53";
    public static final String MOVIE_KEY = "movie_key";

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

        //Initializing our Recyclerview
        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
        tvNoMovies = (TextView) findViewById(R.id.tv_no_movies);

        //scale animation to shrink floating actionbar
        shrinkAnim = new ScaleAnimation(1.15f, 0f, 1.15f, 0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);

        if (mRecyclerView != null) {
            //to enable optimization of recyclerview
            mRecyclerView.setHasFixedSize(true);
        }
        //using staggered grid pattern in recyclerview
        mLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
        mRecyclerView.setLayoutManager(mLayoutManager);


        //Say Hello to our new Firebase UI Element, i.e., FirebaseRecyclerAdapter
        final FirebaseRecyclerAdapter<Movie,MovieViewHolder> adapter = new FirebaseRecyclerAdapter<Movie, MovieViewHolder>(
                Movie.class,
                R.layout.movie_board_item,
                MovieViewHolder.class,
                //referencing the node where we want the database to store the data from our Object
                mDatabaseReference.child("users").child(USER_ID).child("movies").getRef()
        ) {
            @Override
            protected void populateViewHolder(MovieViewHolder viewHolder, Movie model, int position) {
                if(tvNoMovies.getVisibility()== View.VISIBLE){
                    tvNoMovies.setVisibility(View.GONE);
                }
                viewHolder.tvMovieName.setText(model.getMovieName());
                viewHolder.ratingBar.setRating(model.getMovieRating());
                Picasso.with(MainActivity.this).load(model.getMoviePoster()).into(viewHolder.ivMoviePoster);
            }
        };

        mRecyclerView.setAdapter(adapter);

        mRecyclerView.addOnItemTouchListener(new RecyclerItemClickListener(this, new RecyclerItemClickListener.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(MainActivity.this, "Card at " + position + " is clicked", Toast.LENGTH_SHORT).show();
                Movie movie = adapter.getItem(position);
                //creating a bundle in order to pass data to other component using Android Parcelable.
                Bundle bundle = new Bundle();
                bundle.putParcelable(MOVIE_KEY,movie);
                MovieDetailFragment fragment = new MovieDetailFragment();
                fragment.setArguments(bundle);//passing data to fragment
                getSupportFragmentManager().beginTransaction()
                        .replace(R.id.frame_container, fragment)
                        .addToBackStack(null)
                        .commit();

            }
        }));

        fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                getSupportFragmentManager().beginTransaction()
                        .replace(R.id.frame_container, new AddMovieFragment())
                        .addToBackStack(null)
                        .commit();
                //animation being used to make floating actionbar disappear
                shrinkAnim.setDuration(400);
                fab.setAnimation(shrinkAnim);
                shrinkAnim.start();
                shrinkAnim.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {

                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {
                        //changing floating actionbar visibility to gone on animation end
                        fab.setVisibility(View.GONE);
                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {


                    }
                });

            }
        });

    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        if (fab.getVisibility() == View.GONE)
            fab.setVisibility(View.VISIBLE);
    }

    public static class MovieViewHolder extends RecyclerView.ViewHolder{

        TextView tvMovieName;
        RatingBar ratingBar;
        ImageView ivMoviePoster;

        public MovieViewHolder(View v) {
            super(v);
            tvMovieName = (TextView) v.findViewById(R.id.tv_name);
            ratingBar = (RatingBar) v.findViewById(R.id.rating_bar);
            ivMoviePoster = (ImageView) v.findViewById(R.id.iv_movie_poster);
        }
    }
}

Run the app now to see that the object is passed from Activity to Fragment using Android Parcelable!

[widget id=”text-15″]

Leave a Reply

avatar

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  Subscribe  
Notify of