In Android, objects references cannot be just passed to/from Activities or Fragments simply. To pass or transfer objects from one activity(or fragment) to another activity Intent/Bundle can be used.
To put the objects in Intent/Bundle first our objects should be either one of the below
- Serializable
- Parcelable
Serializable
Serializable is a marker interface, meaning that there is no method to implement, Java will simply do its best effort to serialize it efficiently.
Problem with Serializable in Android
- The problem with Serializable approach is that reflection is used and it is a slow process. This mechanism also tends to create a lot of temporary objects and cause quite a bit of garbage collection.
- Serialization is an expensive operation.
- Performance of the App gets affected.
An alternative solution is to use Parcelable approach.
Parcelable
It is an Interface for classes whose instances can be written to and restored from a Parcel.
A Parcel is a container for a message (data and object references) that can be sent from one component to another component in android.
Advantages of Parcelable over Serializable
- The Parcelable interface will run the code significantly faster as we are being explicit about the serialization process instead of using reflection to infer it.
- The code has been heavily optimized which in turn improves app performance.
Parcelable Implementation example
Now we will create a simple app to transfer data from one activity to another activity.
- In Android Studio, go to File -> New Project and fill all the details required to create a new project.
- Open the layout file your main activity activity_main.xml and add below code. Here the layout contains two TextViews and a Button.
<?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:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <android.support.design.widget.TextInputLayout android:id="@+id/input_layout_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" > <EditText android:id="@+id/input_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="true" android:hint="Enter Name" /> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout android:id="@+id/input_layout_country" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" > <EditText android:id="@+id/input_country" android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="true" android:hint="Enter Country" /> </android.support.design.widget.TextInputLayout> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/button_send" android:text="Send to ReceiverActivity" android:onClick="sendToReceiverActivity"/> </LinearLayout>
Note: Here Material Design TextInputLayout is used. Check the Design support Library TextInputLayout tutorial to know more.
- First we need to create a UserDetails bean class which implements Parcelable interface. The UserDetails class will carry the name and country details.
public class UserDetails implements Parcelable { String name; String country; public String getName() { return name; } public String getCountry() { return country; } public UserDetails(String name, String country){ this.name = name; this.country = country; } public UserDetails(Parcel in){ this.name = in.readString(); this.country = in.readString(); } @Override public void writeToParcel(Parcel dest, int flags){ dest.writeString(name); dest.writeString(country); } @Override public int describeContents(){ return 0; } public static final Parcelable.Creator<UserDetails> CREATOR = new Parcelable.Creator<UserDetails>(){ public UserDetails createFromParcel(Parcel in){ return new UserDetails(in); } public UserDetails[] newArray(int size){ return new UserDetails[size]; } }; }
Parcelable Interface Explanation:
- First a parameterized constructor with a parameter of type Parcel should be passed which will be used to read the Parcel data in a particular order.
public UserDetails(Parcel in){ this.name = in.readString(); this.country = in.readString(); }
- Second, the writeToParcel method need to be overridden. The writeToParcel method writes the fields to a parcel in a particular order.
public void writeToParcel(Parcel dest, int flags){ dest.writeString(name); dest.writeString(country); }
- Third, the describeContents method also need to be overridden and it should return zero. This method is generally not used. Use this link to know more.
public int describeContents(){ return 0; }
- Finally, provide the Parcelable.Creator which is used to create an instance of the class from the Parcel data. The static CREATOR class creates the object from a Parcel via the createFromParcel method that takes in a parcel and passes it to a constructor in the class. The newArray method allows an array of the objects to be parcelled.
public static final Parcelable.Creator<UserDetails> CREATOR = new Parcelable.Creator<UserDetails>(){ public UserDetails createFromParcel(Parcel in){ return new UserDetails(in); } public UserDetails[] newArray(int size){ return new UserDetails[size]; } };
- Now open MainActivity.java and make the changes as mentioned below. This activity contains a textbox and button. When the button is clicked then data from textbox will be sent to the ReceiverActivity.java.
public class MainActivity extends AppCompatActivity { EditText inputName; EditText inputCountry; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); inputName = (EditText)findViewById(R.id.input_name); inputCountry =(EditText)findViewById(R.id.input_country); } public void sendToReceiverActivity(){ String name = inputName.getText().toString(); String country = inputCountry.getText().toString(); UserDetails userDetails = new UserDetails(name, country); Bundle b = new Bundle(); b.putParcelable("user_details", userDetails); Intent i = new Intent(getApplicationContext(), ReceiverActivity.class); i.putExtras(b); startActivity(i); } }
Here,when the Button is clicked then the UserDetails object is created with the input texts. A Bundle is created and the UserDetails object is put in the Bundle and sent to ReceiverActivity through intents.
- The ReceiverActivity.java class will receive the intent and fetches the User details.
public class ReceiverActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_receiver); UserDetails userDetails= getIntent().getExtras().getParcelable("user_details"); TextView receivedText = (TextView)findViewById(R.id.text_received); receivedText.setText("Name: " + userDetails.getName() + " Country: " + userDetails.getCountry()); }
- Following is the activity_receiver.xml layout.
<?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:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.techkt.parcelableexample.ReceiverActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/text_received"/> </RelativeLayout>
- Finally, run and test the app.