Android Broadcast Receiver Example with Parcelable

In this tutorial I will show you how to use Broadcast Receiver and how to use Parcelable too. To do this, we will create an ExpandableList which will have parents and children(they will contain only their names). The children will be an arrayList of strings and because we want to pass this array with an Intent we will have to implement Parcelable. But you will understand it better later :) So let’s start:

In order to use Broadcast you have to follow some steps:

Step 1: USE PARCELABLE to send complex data(e.g ArrayList)

Now, I want to tell you which are the general steps for implementing a Parcelable into the class where you have the data which must be sent:

  • The class that contains the data you want to send, MUST implement Parcelable. If you want to send via Intent a custom object you have to implement Parcelable.
  • Make a “Creator”. “Creator” is used to create new objects.
  • Override describeContents() method.
  • Write to Parcel(into a method).  The Parcel is the destination where the objects will be written. To write to Parcel you have to use a Parcel object, let’s call it “dest”:
dest.writeString("the string you want to send"); //for string objects
dest.writeInt(1); //for int variable
dest.writeTypedList(custom arrayList); //for your own arrayLists
  • Read from Parcel(into a constructor). To read from Parcel you have to make a constructor with a Parcel parameter. In this constructor you have to read the data with the help of a Parcel object again, we will call it “source” this time because from here we will get the data:
source.readString();
source.readInt();
source.readTypedList(yourArrayList, YourClass.CREATOR);
  • Create an empty constructor
NOTE 1: You have to read the data in the same order you wrote it, otherwise it will not work!
NOTE 2: When you use an arrayList you have to initialize the arrayList into the empty constructor and call this() method from the constructor where you make the reading from parcel. 


 
Step 2: Create the BROADCAST RECEIVER
  • You must create a class which extends BroadcastReceiver into the class where you want to receive the broadcast
  • You will have a class that sends the broadcast and a class that receives the broadcast.
  • The class that sends the broadcast will use an Intent
  • The class that receives the broadcast will use an IntentFilter ( because it has to receive only the message it wants to receive, it will filter the messages)
  • The broadcast must be registered and unregsitered
  • Usualy the broadcast is registered in the onResume()
  • Usualy the broadcast is unregistered in the onPause()
  • The broadcast must be sent only after the registration of the broadcast
  • All the work for data we want to send, must be done in the class which sends the broadcast
Now let’s make a practical example to understand the above theory better.
1. Create a new project and call your main activity class “MyActivity”
2. Go to res – layout – main.xml and create the ExpandableList:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
        >
    <ExpandableListView android:id="@+id/expandable_list"
                        android:layout_width="fill_parent"
                        android:layout_height="fill_parent"
                        android:transcriptMode="alwaysScroll"
                        android:cacheColorHint="#00000000"
                        android:listSelector="@android:color/transparent"/>
</LinearLayout>

3. Go to res – layout  and create a new xml file and call it “list_item_parent”

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/list_item"
        android:gravity="center_vertical">

    <TextView android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:id="@+id/list_item_text_view"
              android:textSize="20sp"
              android:padding="10dp"
              android:layout_marginLeft="35dp"/>

</LinearLayout>

4. Go to res – layout and create another xml file and call it “list_item_child”

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/list_item_child"
        android:gravity="center_vertical">

    <TextView android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:id="@+id/list_item_text_child"
              android:textSize="20sp"
              android:padding="10dp"
              android:layout_marginLeft="5dp"/>

</LinearLayout>

5. Create an ApplicationContextProvider class following the step 4 first point from this tutorial.

6. Create a new java class and call it “Child”

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

public class Child implements Parcelable{

    private String mName;

    public String getName() {
        return mName;
    }

    public void setName(String mName) {
        this.mName = mName;
    }

    //--------------------------------  METHODS FOR PARCELABLE -----------------------------------

    public static final Creator CREATOR = new Creator() {
        public Child createFromParcel(Parcel in) {
            return new Child(in);
        }

        public Child[] newArray(int size) {
            return new Child[size];
        }
    };

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(mName);
    }

    public Child(){

    }

    /**
     * This will be used only by the MyCreator
     *
     * @param source source where to read the parceled data
     */
    public Child(Parcel source) {
        // reconstruct from the parcel
        mName = source.readString();
    }
}

6. Create a new java class and call it “Parent”

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

import java.util.ArrayList;

public class Parent implements Parcelable{
    private String mTitle;
    private ArrayList<Child> mArrayChildren;
    public static final String PARENT_RECEIVER_KEY = "ParentReceiver";

    public String getTitle() {
        return mTitle;
    }

    public void setTitle(String mTitle) {
        this.mTitle = mTitle;
    }

    public ArrayList<Child> getArrayChildren() {
        return mArrayChildren;
    }

    public void setArrayChildren(ArrayList<Child> mArrayChildren) {
        this.mArrayChildren = mArrayChildren;
    }

    //--------------------------------  METHODS FOR PARCELABLE -----------------------------------

    public static final Creator CREATOR = new Creator() {
        public Parent createFromParcel(Parcel in) {
            return new Parent(in);
        }

        public Parent[] newArray(int size) {
            return new Parent[size];
        }
    };

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

    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(mTitle);
        dest.writeTypedList(mArrayChildren);

    }

    //write this constructor to initialize the arrayList
    public Parent(){
        mArrayChildren = new ArrayList<Child>();

    }

    /**
     * This will be used only by the MyCreator
     *
     * @param source source where to read the parceled data
     */
    public Parent(Parcel source) {

        //you have to call the other constructor to initialize the arrayList
        this();

        // reconstruct from the parcel
        mTitle = source.readString();
        source.readTypedList(mArrayChildren,Child.CREATOR);
    }

}

7. Create a new java class and call it “MyCustomAdapter”. This class is the adapter that we will use for ExpandableList.

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;
import com.example.R;

import java.util.ArrayList;

public class MyCustomAdapter extends BaseExpandableListAdapter {

    private LayoutInflater inflater;
    private ArrayList<Parent> mParent;

    public MyCustomAdapter(Context context, ArrayList<Parent> parent){
        mParent = parent;
        inflater = LayoutInflater.from(context);
    }

    @Override
    //counts the number of group/parent items so the list knows how many times calls getGroupView() method
    public int getGroupCount() {
        return mParent.size();
    }

    @Override
    //counts the number of children items so the list knows how many times calls getChildView() method
    public int getChildrenCount(int i) {
        return mParent.get(i).getArrayChildren().size();
    }

    @Override
    //gets the title of each parent/group
    public Object getGroup(int i) {
        return mParent.get(i).getTitle();
    }

    @Override
    //gets the name of each item
    public Object getChild(int i, int i1) {
        return mParent.get(i).getArrayChildren().get(i1);
    }

    @Override
    public long getGroupId(int i) {
        return i;
    }

    @Override
    public long getChildId(int i, int i1) {
        return i1;
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    //in this method you must set the text to see the parent/group on the list
    public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {

        if (view == null) {
            view = inflater.inflate(R.layout.list_item_parent, viewGroup,false);
        }

        TextView textView = (TextView) view.findViewById(R.id.list_item_text_view);
        //"i" is the position of the parent/group in the list
        textView.setText(getGroup(i).toString());

        //return the entire view
        return view;
    }

    @Override
    //in this method you must set the text to see the children on the list
    public View getChildView(int i, int i1, boolean b, View view, ViewGroup viewGroup) {
        if (view == null) {
            view = inflater.inflate(R.layout.list_item_child, viewGroup,false);
        }

        TextView textView = (TextView) view.findViewById(R.id.list_item_text_child);
        //"i" is the position of the parent/group in the list and 
        //"i1" is the position of the child
        textView.setText(mParent.get(i).getArrayChildren().get(i1).getName());

        //return the entire view
        return view;
    }

    @Override
    public boolean isChildSelectable(int i, int i1) {
        return true;
    }
}

8. Create a new class and call it “BroadcastSender” . This class is the sender class, so here we will create the arrays of parents and children and then we will send them to MyActivity class with a broadcast via intent.

import android.content.Intent;

import java.util.ArrayList;

public class BroadcastSender {

    public void sendBroadcast(){
        ArrayList arrayParents = new ArrayList<Parent>();
        ArrayList<Child> arrayChildren = new ArrayList<Child>();

        //here we set the parents and the children
        for (int i = 0; i < 10; i++){
            //for each "i" create a new Parent object to set the title and the children
            Parent parent = new Parent();
            Child child = new Child();

            parent.setTitle("Parent " + i);
            child.setName("Child " + i);

            arrayChildren.add(child);
            parent.setArrayChildren(arrayChildren);

            //in this array we add the Parent object. We will use the arrayParents at the setAdapter
            arrayParents.add(parent);

        }

        //send the intent with the broadcast
        Intent intent = new Intent(Parent.PARENT_RECEIVER_KEY);

        //arrayLists have "special treatment" and we have to
        //send them particularly with the intent
        //"value" is a key. This key will be used in the receiver class
        intent.putParcelableArrayListExtra("value",arrayParents);

        //sends the broadcast
        ApplicationContextProvider.getContext().sendBroadcast(intent);

    }
}

9. Now go to MyActivity class (this is the receiver class) and put the following code:

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.widget.ExpandableListView;

import java.util.ArrayList;

public class MyActivity extends Activity {

    private ExpandableListView mExpandableList;
    private ListReceiver mListReceiver;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mExpandableList = (ExpandableListView)findViewById(R.id.expandable_list);

    }

    @Override
    protected void onResume() {
        super.onResume();

        //create an instance of ListReceiver
        mListReceiver = new ListReceiver();

        //create an intentFilter to get only the message that we need.
        //notice that the argument of the IntentFilter constructor
        //must be exactly like the one the we sent with the Intent from
        //BroadcastSender class
        IntentFilter intentFilter = new IntentFilter(Parent.PARENT_RECEIVER_KEY);
        registerReceiver(mListReceiver,intentFilter);

        //send the broadcast only AFTER the registration
        BroadcastSender broadcastSender = new BroadcastSender();
        broadcastSender.sendBroadcast();
    }

    @Override
    protected void onPause() {
        super.onPause();

        //unregister the receiver
        unregisterReceiver(mListReceiver);
        mListReceiver = null;
    }

    private class ListReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {

            //verify if the message we received is the one that we want
            if (intent.getAction().equals(Parent.PARENT_RECEIVER_KEY)){

                //get the arrayList we have sent with intent (the one from BroadcastSender)
                //notice that we needed the key "value"
                ArrayList<Parent> arrayParents = intent.getParcelableArrayListExtra("value");

                //sets the adapter that provides data to the list.
                mExpandableList.setAdapter(new MyCustomAdapter(MyActivity.this,arrayParents));

            }

        }
    }
}

Now the result should be like this:

Scroll to Top