1.27k likes | 1.49k Views
Mobile Programming Lecture 6. Fragments, Permissions, BroadcastReceivers. Agenda. Dynamic UI LayoutInflater Fragments Permissions BroadcastReceiver. Building the UI Dynamically. So far we've been creating UIs that are defined before runtime
E N D
Mobile Programming Lecture 6 Fragments, Permissions, BroadcastReceivers
Agenda • Dynamic UI • LayoutInflater • Fragments • Permissions • BroadcastReceiver
Building the UI Dynamically So far we've been creating UIs that are defined before runtime There are some cases where you will need to build the UI dynamically Consider this XML layout file
Building the UI Dynamically <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <TableRow android:layout_width="wrap_content" android:layout_height="wrap_content" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Medium Text" android:textAppearance="?android:attr/textAppearanceMedium" /> </TableRow> <TableRow android:layout_width="wrap_content" android:layout_height="wrap_content" > </TableRow> </TableLayout>
Building the UI Dynamically Now let's look at Java code that can build a similar UI at runtime
Building the UI Dynamically <TableLayout android:layout_width="match_parent" android:layout_height="match_parent" > <TableRow android:layout_width="wrap_content" android:layout_height="wrap_content" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Medium Text"/> </TableRow> <TableRow android:layout_width="wrap_content" android:layout_height="wrap_content" > </TableRow> </TableLayout> public void onCreate(Bundle state) { super.onCreate(savedInstanceState); TableLayout layout = new TableLayout(this); TableRow row = new TableRow(this); TextView tv = new TextView(this); tv.setText("Medium Text"); row.addView(tv); layout.addView(row); row = new TableRow(this); layout.addView(row); setContentView(layout); }
Building the UI Dynamically This argument asks for a Context, e.g. this or getApplicationContext() <TableLayout android:layout_width="match_parent" android:layout_height="match_parent" > <TableRow android:layout_width="wrap_content" android:layout_height="wrap_content" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Medium Text"/> </TableRow> <TableRow android:layout_width="wrap_content" android:layout_height="wrap_content" > </TableRow> </TableLayout> public void onCreate(Bundle state) { super.onCreate(savedInstanceState); TableLayout layout = new TableLayout(this); TableRow row = new TableRow(this); TextView tv = new TextView(this); tv.setText("Medium Text"); row.addView(tv); layout.addView(row); row = new TableRow(this); layout.addView(row); setContentView(layout); }
Building the UI Dynamically "this" refers to the instance of whichever class the code is currently in! <TableLayout android:layout_width="match_parent" android:layout_height="match_parent" > <TableRow android:layout_width="wrap_content" android:layout_height="wrap_content" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Medium Text"/> </TableRow> <TableRow android:layout_width="wrap_content" android:layout_height="wrap_content" > </TableRow> </TableLayout> public void onCreate(Bundle state) { super.onCreate(savedInstanceState); TableLayout layout = new TableLayout(this); TableRow row = new TableRow(this); TextView tv = new TextView(this); tv.setText("Medium Text"); row.addView(tv); layout.addView(row); row = new TableRow(this); layout.addView(row); setContentView(layout); }
Building the UI Dynamically In this case, it would refer to your Activity (since you know that onCreate() is a method of an Activity) <TableLayout android:layout_width="match_parent" android:layout_height="match_parent" > <TableRow android:layout_width="wrap_content" android:layout_height="wrap_content" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Medium Text"/> </TableRow> <TableRow android:layout_width="wrap_content" android:layout_height="wrap_content" > </TableRow> </TableLayout> public void onCreate(Bundle state) { super.onCreate(savedInstanceState); TableLayout layout = new TableLayout(this); TableRow row = new TableRow(this); TextView tv = new TextView(this); tv.setText("Medium Text"); row.addView(tv); layout.addView(row); row = new TableRow(this); layout.addView(row); setContentView(layout); }
Building the UI Dynamically You can't add the same child element twice! This is an easy way to get a Force Close
LayoutInflater • instantiates a layout XML file into its corresponding View objects • use getLayoutInflater()
LayoutInflater @Override public void onCreate(Bundle state) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override public void onCreate(Bundle state) { super.onCreate(savedInstanceState); LayoutInflater inflater = getLayoutInflater(); setContentView( inflater.inflate(R.layout.main, null)); }
LayoutInflater @Override public void onCreate(Bundle state) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override public void onCreate(Bundle state) { super.onCreate(savedInstanceState); LayoutInflater inflater = getLayoutInflater(); setContentView( inflater.inflate(R.layout.main, null)); } Gives you the same result
LayoutInflater @Override public void onCreate(Bundle state) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override public void onCreate(Bundle state) { super.onCreate(savedInstanceState); LayoutInflater inflater = getLayoutInflater(); setContentView( inflater.inflate(R.layout.main, null)); } Second argument is of type ViewGroup
LayoutInflater @Override public void onCreate(Bundle state) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override public void onCreate(Bundle state) { super.onCreate(savedInstanceState); LayoutInflater inflater = getLayoutInflater(); setContentView( inflater.inflate(R.layout.main, null)); } Use it if you want to embed the first argument into the second argument
Fragments • A Fragment represents a behavior or a portion of user interface in an Activity. • Add multiple fragments to a screen to avoid switching activities • Fragments have their own lifecycle, state, and back stack • Fragments require API Level 11 or greater
Fragments - Lifecycle A fragment must always be embedded in an activity and the fragment's lifecycle is directly affected by the host activity's lifecycle. • http://developer.android.com/guide/components/fragments.html onCreateView() is the one we'll be focusing on for now ...
Fragments - Steps for Creating One • You must create a subclass of Fragment • Fragment, ListFragment, etc • You must implement onCreateView() • onCreateView() must return a View i.e. @Override public ViewonCreateView( /* required args */)
Fragments - onCreateView() There are two ways to return a view in your implementation of onCreateView()
Fragments - onCreateView() 1. Use the LayoutInflater argument to instantiate a predefined layout XML file e.g. public class MyFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) { return inflater.inflate(R.layout.example_fragment, container, false); } }
Fragments - onCreateView() 1. Use the LayoutInflater argument to instantiate a predefined layout XML file e.g. public class MyFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) { return inflater.inflate(R.layout.example_fragment, container, false); } } extend Fragment, not Activity
Fragments - onCreateView() 1. Use the LayoutInflater argument to instantiate a predefined layout XML file e.g. public class MyFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) { return inflater.inflate(R.layout.example_fragment, container, false); } } The XML layout file to instantiate
Fragments - onCreateView() 1. Use the LayoutInflater argument to instantiate a predefined layout XML file e.g. public class MyFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) { return inflater.inflate(R.layout.example_fragment, container, false); } } The ViewGroup to insert it into
Fragments - onCreateView() 1. Use the LayoutInflater argument to instantiate a predefined layout XML file e.g. public class MyFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) { return inflater.inflate(R.layout.example_fragment, container, false); } } Passing true would create a redundant ViewGroup, so pass false for now
Fragments - onCreateView() 2. Build a UI dynamically and return the root View public class MyFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) { ScrollView scroller = new ScrollView(getActivity()); TextView text = new TextView(getActivity()); scroller.addView(text); text.setText("Sample Text"); return scroller; } }
Fragments - onCreateView() 2. Build a UI dynamically and return the root View public class MyFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) { ScrollView scroller = new ScrollView(getActivity()); TextView text = new TextView(getActivity()); scroller.addView(text); text.setText("Sample Text"); return scroller; } } You've seen most of this before!
Fragments - onCreateView() 2. Build a UI dynamically and return the root View public class MyFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) { ScrollView scroller = new ScrollView(getActivity()); TextView text = new TextView(getActivity()); scroller.addView(text); text.setText("Sample Text"); return scroller; } } Last time we used the keyword this to get the Context
Fragments - onCreateView() 2. Build a UI dynamically and return the root View public class MyFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) { ScrollView scroller = new ScrollView(getActivity()); TextView text = new TextView(getActivity()); scroller.addView(text); text.setText("Sample Text"); return scroller; } } Since we're in a Fragment here, and not an Activity ...
Fragments - onCreateView() 2. Build a UI dynamically and return the root View public class MyFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) { ScrollView scroller = new ScrollView(getActivity()); TextView text = new TextView(getActivity()); scroller.addView(text); text.setText("Sample Text"); return scroller; } } We can get the controlling Activity from within the Fragment using getActivity()
Fragments - onCreateView() 2. Build a UI dynamically and return the root View public class MyFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) { ScrollView scroller = new ScrollView(getActivity()); TextView text = new TextView(getActivity()); scroller.addView(text); text.setText("Sample Text"); return scroller; } } This is how we get the Context. Alternatively, we can say getActivity().getApplicationContext()
Fragments - Adding a Fragment There are 2 ways to add a Fragment
Fragments - Adding a Fragment 1. Declare the Fragment inside of the Activity's layout file <?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:name="edu.fsu.cs.mobile.example.MyFragment" android:id="@+id/list" android:tag="list_fragment" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="match_parent" /> <fragment android:name="edu.fsu.cs.mobile.example.MyOtherFragment" android:id="@+id/viewer" android:tag="viewer_fragment" android:layout_weight="2" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
Fragments - Adding a Fragment 1. Declare the Fragment inside of the Activity's layout file <?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:name="edu.fsu.cs.mobile.example.MyFragment" android:id="@+id/list" android:tag="list_fragment" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="match_parent" /> <fragment android:name="edu.fsu.cs.mobile.example.MyOtherFragment" android:id="@+id/viewer" android:tag="viewer_fragment" android:layout_weight="2" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> <fragment>
Fragments - Adding a Fragment 1. Declare the Fragment inside of the Activity's layout file <?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:name="edu.fsu.cs.mobile.example.MyFragment" android:id="@+id/list" android:tag="list_fragment" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="match_parent" /> <fragment android:name="edu.fsu.cs.mobile.example.MyOtherFragment" android:id="@+id/viewer" android:tag="viewer_fragment" android:layout_weight="2" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> absolute reference to your Fragment class, which includes the package name
Fragments - Adding a Fragment 1. Declare the Fragment inside of the Activity's layout file <?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:name="edu.fsu.cs.mobile.example.MyFragment" android:id="@+id/list" android:tag="list_fragment" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="match_parent" /> <fragment android:name="edu.fsu.cs.mobile.example.MyOtherFragment" android:id="@+id/viewer" android:tag="viewer_fragment" android:layout_weight="2" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> Fragment id
Fragments - Adding a Fragment 1. Declare the Fragment inside of the Activity's layout file <?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:name="edu.fsu.cs.mobile.example.MyFragment" android:id="@+id/list" android:tag="list_fragment" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="match_parent" /> <fragment android:name="edu.fsu.cs.mobile.example.MyOtherFragment" android:id="@+id/viewer" android:tag="viewer_fragment" android:layout_weight="2" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> Fragment TAG
Fragments - Adding a Fragment 1. Declare the Fragment inside of the Activity's layout file This works because you return a View object in your onCreateView() method for the specified Fragment The View then gets embedded into the UI
Fragments - Adding a Fragment 2. Programmatically add the Fragment to an existing ViewGroup <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" /> <FrameLayout android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="match_parent" > </FrameLayout> </LinearLayout> Use a FrameLayout as a container for your Fragment
Fragments - Adding a Fragment 2. Programmatically add the Fragment to an existing ViewGroup <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" /> <FrameLayout android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="match_parent" > </FrameLayout> </LinearLayout> Remember the id of the container ...
Fragments - Adding a Fragment 2. Programmatically add the Fragment to an existing ViewGroup <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" /> <FrameLayout android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="match_parent" > </FrameLayout> </LinearLayout> This is main.xml layout file
Fragments - Adding a Fragment 2. Programmatically add the Fragment to an existing ViewGroup public class MyActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); FragmentManager manager = getFragmentManager(); FragmentTransaction trans = manager.beginTransaction(); MyFragment fragment = new MyFragment(); trans.add(R.id.fragment_container, fragment, "my_fragment"); trans.commit(); } }
Fragments - Adding a Fragment 2. Programmatically add the Fragment to an existing ViewGroup public class MyActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); FragmentManager manager = getFragmentManager(); FragmentTransaction trans = manager.beginTransaction(); MyFragment fragment = new MyFragment(); trans.add(R.id.fragment_container, fragment, "my_fragment"); trans.commit(); } } This XML layout file contains the FrameLayout container
Fragments - Adding a Fragment 2. Programmatically add the Fragment to an existing ViewGroup public class MyActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); FragmentManager manager = getFragmentManager(); FragmentTransaction trans = manager.beginTransaction(); MyFragment fragment = new MyFragment(); trans.add(R.id.fragment_container, fragment, "my_fragment"); trans.commit(); } } FragmentManager allows you to interact with Fragments that are in an Activity
Fragments - Adding a Fragment 2. Programmatically add the Fragment to an existing ViewGroup public class MyActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); FragmentManager manager = getFragmentManager(); FragmentTransaction trans = manager.beginTransaction(); MyFragment fragment = new MyFragment(); trans.add(R.id.fragment_container, fragment, "my_fragment"); trans.commit(); } } FragmentTransaction allows you to perform operations on Fragments (add, remove, replace)
Fragments - Adding a Fragment 2. Programmatically add the Fragment to an existing ViewGroup public class MyActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); FragmentManager manager = getFragmentManager(); FragmentTransaction trans = manager.beginTransaction(); MyFragment fragment = new MyFragment(); trans.add(R.id.fragment_container, fragment, "my_fragment"); trans.commit(); } } Our Fragment doesn't exist at this point (was not specified in XML), let's create an instance of it
Fragments - Adding a Fragment 2. Programmatically add the Fragment to an existing ViewGroup public class MyActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); FragmentManager manager = getFragmentManager(); FragmentTransaction trans = manager.beginTransaction(); MyFragment fragment = new MyFragment(); trans.add(R.id.fragment_container, fragment, "my_fragment"); trans.commit(); } } Add our Fragment to the FrameLayout container
Fragments - Adding a Fragment 2. Programmatically add the Fragment to an existing ViewGroup public class MyActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); FragmentManager manager = getFragmentManager(); FragmentTransaction trans = manager.beginTransaction(); MyFragment fragment = new MyFragment(); trans.add(R.id.fragment_container, fragment, "my_fragment"); trans.commit(); } } The unique TAG for your Fragment, so that you can reference it later
Fragments - Adding a Fragment 2. Programmatically add the Fragment to an existing ViewGroup public class MyActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); FragmentManager manager = getFragmentManager(); FragmentTransaction trans = manager.beginTransaction(); MyFragment fragment = new MyFragment(); trans.add(R.id.fragment_container, fragment, "my_fragment"); trans.commit(); } } Update the UI
Fragments - Passing data to You will often want to pass data from your Activity to your Fragment. You can do this several ways. From within the Activity ... public class MyActivity extends Activity { @Override public void onCreate(Bundle savedInstance) { super.onCreate(savedInstance); setContentView(R.layout.main); MyFragment fragment = new MyFragment(); fragment.my_custom_field = value; fragment.setMyCustomField(value); FragmentManager manager = getFragmentManager(); FragmentTransaction trans = manager.beginTransaction(); trans.add(R.id.fragment_container, fragment, "my_fragment"); trans.commit(); } }