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
- 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
<?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: