The slides on this page are screen shots from Vivz slidenerd videos on youtube. Full video can be seen on the bottom of this page.
Below we have the modified communicator design pattern which is better than the previous example because out interface isn’t exposed (used as a separate class) and is only accessible to where it’s needed. In java, a general rule is ‘do not expose something more that it needs to be’. In our example, only FragmentA and MainActivity need use of the communicator so we place it WITHIN Fragment A. Since Fragment B doesn’t care about the communicator, we can hide it in Fragment A.
The full design pattern including the orientation switching.
MainActivity.java
package com.jamesfroggatt.fragments5.app; import android.app.Activity; import android.app.FragmentManager; import android.content.Intent; import android.os.Bundle; public class MainActivity extends Activity implements FragmentA.Communicator { // create references to the fragments FragmentA f1; FragmentB f2; FragmentManager manager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // initialise the fragment manager manager=getFragmentManager(); // initialise fragment A because this fragment will ALWAYS be there in // portrait and landscape mode f1 = (FragmentA) manager.findFragmentById(R.id.fragment); f1.setCommunicator(this); // this = we're passing an object of type MainActivity } // this method is generated from the Communicator interface (in Fragment A) as // we're implementing it here in MainActivity @Override public void respond(int position) { // we need to check, are we in portrait or landscape mode f2= (FragmentB) manager.findFragmentById(R.id.fragment2); if (f2!=null && f2.isVisible()) { // we are ˙in landscape mode f2.changeData(position); }else { // we are in portrait mode // start the new activity Intent intent= new Intent(this,AnotherActivity.class); intent.putExtra("index",position); startActivity(intent); } } }
FragmentA.java
package com.jamesfroggatt.fragments5.app; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; public class FragmentA extends Fragment implements AdapterView.OnItemClickListener { // create a reference to the ListView ListView list; // create a reference to the Communicator Communicator communicator; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { //return super.onCreateView(inflater, container, savedInstanceState); // link the layout to the view object View view=inflater.inflate(R.layout.fragment_a, container, false); // find the ListView object from the inflated view and attach it to list list= (ListView) view.findViewById(R.id.listView); // now we set an adapter which will contain our datasource ArrayAdapter adapter = ArrayAdapter.createFromResource(getActivity(),R.array.chapters,android.R.layout.simple_list_item_1); // set the adapter list.setAdapter(adapter); // set the on list.setOnItemClickListener(this); return view; } // this is the generated onItemClick listener for the listView @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { communicator.respond(position); } // COMMUNICATOR INTERFACE - method "respond" is responsible for carrying data from // fragment A to fragment B public interface Communicator{ public void respond(int position); // calls the respond method inside MainActivity } // method to set the communicator public void setCommunicator(Communicator communicator){ this.communicator=communicator; } }
FragmentB.java
package com.jamesfroggatt.fragments5.app; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class FragmentB extends Fragment { // get a reference to the textView TextView text; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { //return super.onCreateView(inflater, container, savedInstanceState); // link the layout to the view object View view=inflater.inflate(R.layout.fragment_b, container, false); // find the TextView object from the inflated view and attach it to text text= (TextView) view.findViewById(R.id.textView); return view; } // we need a method to change the contents of our TextView public void changeData(int index){ String[] descriptions=getResources().getStringArray(R.array.description); text.setText(descriptions[index]); } }
AnotherActivity.java
package com.jamesfroggatt.fragments5.app; import android.app.Activity; import android.content.Intent; import android.os.Bundle; public class AnotherActivity extends Activity{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_another); Intent intent=getIntent(); int index = intent.getIntExtra("index",0); // get a reference to fragment B FragmentB f2= (FragmentB) getFragmentManager().findFragmentById(R.id.fragment2); if (f2!=null){ f2.changeData(index); } } }
layout/activity_main.xml
<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" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" android:background="#FF3399" tools:context="com.jamesfroggatt.fragments5.app.MainActivity"> <fragment android:layout_width="wrap_content" android:layout_height="wrap_content" android:name="com.jamesfroggatt.fragments5.app.FragmentA" android:id="@+id/fragment" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_alignParentRight="true" /> </RelativeLayout>
layout/fragment_a.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#AA4499"> <ListView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/listView" android:layout_gravity="center_horizontal" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentRight="true" android:layout_alignParentBottom="true" /> </LinearLayout>
layout/fragment_b.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFBB00"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="New Text" android:id="@+id/textView" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentRight="true"/> </LinearLayout>
layout/activity_another.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"> <fragment android:layout_width="wrap_content" android:layout_height="wrap_content" android:name="com.jamesfroggatt.fragments5.app.FragmentB" android:id="@+id/fragment2" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentRight="true" tools:layout="@layout/fragment_b" /> </LinearLayout>
layout-land/activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:name="com.jamesfroggatt.fragments5.app.FragmentA" android:id="@+id/fragment" android:layout_gravity="left|center_vertical"/> <fragment android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:name="com.jamesfroggatt.fragments5.app.FragmentB" android:id="@+id/fragment2" android:layout_gravity="left|center_vertical" /> </LinearLayout>
values/strings.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Fragments5</string> <string name="hello_world">Hello world!</string> <string name="action_settings">Settings</string> <!-- used for populating the listView using the ArrayAdapter --> <string-array name="chapters"> <item>Washing Machines</item> <item>Computers</item> <item>Phones</item> <item>Countries</item> </string-array> <string-array name="description"> <item>Washing machines are quite popular and we\'ve got loads of them.</item> <item>Computers do quite alot of good stuff these days as they\'re powerful enough</item> <item>Most people have a phone. There are many models and types, many run Android</item> <item>How any are there, tonnes of them. France, Spain, Germany, loads of them</item> </string-array> </resources>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.jamesfroggatt.fragments5.app" > <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.jamesfroggatt.fragments5.app.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="com.jamesfroggatt.fragments5.app.AnotherActivity"></activity> </application> </manifest>
Final product.
This is the full tutorial on youtube