Android Application Model I CSE 5236: Mobile Application Development Instructor: Adam C. Champion, Ph.D. Course Coordinator: Dr. Rajiv Ramnath Reading: Big Nerd Ranch Guide, Chapters 3, 5 (Activities); Chapter 13 (menus) 1
Android Framework Support 2
Framework Capabilities and Add-Ons Built-In Services: GUI OS services (file I/O, threads, device management) Graphics Device access (GPS, camera, media players, sensors), Networking Standard language libraries Add-ons: Google Play services (e.g. Google Maps, Games, etc.) Database support (SQLite) WebKit/Chromium 3
Tooling Support IDE: Android Studio Testing tools: JUnit, Espresso Performance profiling tools: Android Profiler Source code management: Git, Subversion, CVS, etc. Software emulators: Android emulator, Intel HAXM, Genymotion Sensor injection via emulator 4
Android Studio Project Components 5
Types of Android Programs Applications Home app, Home screen Take over screen Services Run in the background without UI App widgets and home screen widgets View-only interface to a service Home screen widget if on Home screen All apps have Activities a key part of any Android app 6
Activities in Tic-Tac-Toe 7
Specifying Activities AndroidManifest.xml <activity android:name=".splashscreen" android:label="@string/app_name" android:screenorientation="portrait"> <intent-filter> <action android:name="android.intent.action.main"/> <category android:name="android.intent.category.launcher /> </intent-filter> </activity> <activity android:name=".login" android:label="@string/app_name" android:launchmode="singleinstance" android:screenorientation="portrait"> <intent-filter> <action android:name="com.wiley.fordummies.androidsdk.login"/> <category android:name="android.intent.category.default"/> </intent-filter> </activity> 8
Implementing Activities Java public class LoginActivity extends SingleFragmentActivity {......... public class GameSessionActivity extends SingleFragmentActivity {...... Kotlin class LoginActivity : SingleFragmentActivity() {......... class GameSessionActivity : SingleFragmentActivity() {...... 9 Note: SingleFragmentActivity extends FragmentActivity
Activity UI Widgets View and ViewGroup Package android.view Specified declaratively in layout files Always use Fragments 10
Sample Layout: Login Activity <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android android:background="@color/background" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="20dip"> <LinearLayout android:orientation="vertical <TextView android:text="@string/login_title /> <TextView /> <EditText /> <TextView /> <EditText /> <Button /> <Button /> <Button /> </LinearLayout> </ScrollView> 11 <project>/app/src/main/res/layout/fragment_login.xml
Views, ViewGroups, Layouts, Widgets Many types of views, layouts and widgets: ScrollView, HorizontalScrollView LinearLayout, AbsoluteLayout, FrameLayout, RelativeLayout TextView, EditText, Button, DatePicker, Spinner Nested nature of layout ViewGroup base class for composite elements View base class for terminal UI components Layout files compiled into resource R class in res subtree 12
Implement UI Logic: Listener Objects: Java public class LoginActivity extends SingleFragmentActivity { // Create LoginFragment in oncreate() method. (See SingleFragmentActivity) public class LoginFragment extends Fragment implements View.OnClickListener { private EditText musernameedittext; private EditText mpasswordedittext; @Override public View oncreateview() { // The real code has many null checks and screen rotation check (omitted for brevity) View v = inflater.inflate(r.layout.fragment_login, container, false); musernameedittext = v.findviewbyid(r.id.username_text); mpasswordedittext = v.findviewbyid(r.id.password_text); Button loginbutton = v.findviewbyid(r.id.login_button); loginbutton.setonclicklistener(this); Button cancelbutton = v.findviewbyid(r.id.cancel_button); cancelbutton.setonclicklistener(this); Button newuserbutton = v.findviewbyid(r.id.new_user_button); newuserbutton.setonclicklistener(this); return v; 13
Implement UI Logic: Listener Objects: Kotlin class LoginActivity : SingleFragmentActivity() { // Create LoginFragment in oncreate() method. (See SingleFragmentActivity) class LoginFragment : Fragment(), View.OnClickListener { private lateinit var musernameedittext: EditText private lateinit var mpasswordedittext: EditText override fun oncreateview( ): View? { // Similarly, real code has screen rotation check (omitted for brevity) val v = inflater.inflate(r.layout.fragment_login, container, false) musernameedittext = v.findviewbyid(r.id.username_text) mpasswordedittext = v.findviewbyid (R.id.password_text) val loginbutton = v.findviewbyid(r.id.login_button) loginbutton.setonclicklistener(this) val cancelbutton = v.findviewbyid(r.id.cancel_button) cancelbutton.setonclicklistener(this) val newuserbutton = v.findviewbyid(r.id.new_user_button) newuserbutton.setonclicklistener(this) return v // 14
The OnClick Handler Java public void onclick(view v) { switch (v.getid()) { case R.id.login_button: checklogin(); break; case R.id.cancel_button: finish(); break; case R.id.new_user_button: FragmentManager fm = getfragmentmanager(); Fragment fragment = new AccountFragment(); fm.begintransaction().replace(/* container */, fragment).addtobackstack("account_fragment").commit(); break; // Null check code omitted Kotlin override fun onclick(view: View) { when (view.id) { R.id.login_button -> checklogin() R.id.cancel_button -> activity?.finish() R.id.new_user_button -> val fm = fragmentmanager fm?.begintransaction()?.replace(/* container */, fragment)?.addtobackstack()?.commit() Kotlin s?. operator is short for: if (object!= null) { object.callmethod() 15
Embedding a View: GameSession Activity, Fragment: Java public class GameSessionActivity extends SingleFragmentActivity { public class GameSessionFragment extends Fragment { <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android.. > <LinearLayout... <com.wiley.fordummies.androidsdk.board android:id="@+id/board" android:layout_width="fill_parent" android:layout_height="fill_parent"/> </LinearLayout> <TextView... "/> <TextView... "/> </LinearLayout> 16
Embedding a View: GameSession Activity, Fragment: Kotlin class GameSessionActivity : SingleFragmentActivity() { class GameSessionFragment : Fragment() { <!-- Same XML as before --> 17
Embedding a View: Board Class Java // Board.java public class Board extends View {... public boolean ontouchevent( MotionEvent event) { switch (action) { case MotionEvent.ACTION_DOWN: break; return super.ontouchevent(event); Kotlin // Board.kt class Board : View { override fun ontouchevent( event: MotionEvent): Boolean { when (action) { MotionEvent.ACTION_DOWN -> { return super.ontouchevent(event) 18
Handling UI in the Activity Activity also a View Can handle UI without any widgets. Why? Handle non-widget-specific events (touch) Handle user interaction outside the boundaries of any UI components See ontouchevent method in SplashScreenFragment class. 19
Menus (Option menus) and Action Bars Declare the menu items Define oncreateoptionsmenu() and/or the oncreatecontextmenu() callback methods in Activity. Automatically called to create the menu (what if it doesn t exist?). Implement onoptionsitemselected() and/or oncontextitemselected() in activity. 20
Menu Layout File <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:title="settings" android:id="@+id/menu_settings" android:icon="@android:drawable/ic_menu_preferences" /> <item android:title="help" /> android:id="@+id/menu_help" android:icon="@android:drawable/ic_menu_info_details" <item android:title="exit" android:id="@+id/menu_exit" android:icon="@android:drawable/ic_menu_close_clear_cancel" /> <item android:title="contacts" /> </menu> android:id="@+id/menu_contacts" android:icon="@android:drawable/ic_menu_view" Action Bar: Declare menu item with additional attribute 21 android:showasaction ="ifroom","never","withtext" or "always".
Menu Creation: Java public class GameOptionsFragment {... public View oncreateview( ) { // sethasoptionsmenu(true);... public boolean oncreateoptionsmenu(menu menu) { super.oncreateoptionsmenu(menu, inflater); inflater.inflate(r.menu.menu, menu);... 22
Menu Creation: Kotlin class GameOptionsFragment { override fun oncreateview( ) { // sethasoptionsmenu(true); override fun oncreateoptionsmenu( menu: Menu, inflater: MenuInflater) { super.oncreateoptionsmenu(menu, inflater) inflater.inflate(r.menu.menu_ingame, menu) 23
Menu Handlers: Java public boolean onoptionsitemselected(menuitem item) { Activity activity = getactivity(); if (activity!= null) { switch (item.getitemid()) { case R.id.menu_settings: startactivity(new Intent(activity, SettingsActivity.class)); return true; case R.id.menu_help: startactivity(new Intent(activity, HelpActivity.class)); return true; case R.id.menu_exit: showquitappdialog(); return true; case R.id.menu_contacts: startactivity(new Intent(activity, return false; ContactsActivity.class)); return true; 24
Menu Handlers: Kotlin override fun onoptionsitemselected(item: MenuItem?): Boolean { when (item!!.itemid) { R.id.menu_settings -> { startactivity(intent(activity?.applicationcontext, SettingsActivity::class.java)) return true R.id.menu_help -> { startactivity(intent(activity?.applicationcontext, HelpActivity::class.java)) return true R.id.menu_exit -> { showquitappdialog() return true R.id.menu_contacts -> { startactivity(intent(activity?.applicationcontext, ContactsActivity::class.java)) return true Kotlin s!! operator asserts that return false calling object is not null 25
UI for Larger Screens - Fragments In Android 3.0 and up with compatibility library (ACL) for earlier versions Further decouples UI interactions from activity lifecycle Standard concept in frameworks Allows reuse of UI components Specialized activity class FragmentActivity We will cover it in a later class 26
Special Types of Activities: Preferences: Java public class SettingsActivity extends AppCompatActivity { protected Fragment createfragment() { return new SettingsFragment(); @Override protected void oncreate(bundle savedinstancestate) { FragmentManager fm = getsupportfragmentmanager(); Fragment fragment = fm.findfragmentbyid(r.id.fragment_container); Fragment preferencefragment = createfragment(); fm.begintransaction().replace(r.id.fragment_container, preferencefragment).commit(); PreferenceManager.setDefaultValues(this, R.xml.settings, false); public class SettingsFragment extends PreferenceFragmentCompat { @Override public void oncreatepreferences(bundle savedinstancestate, String rootkey) { // Load preferences from XML resource. addpreferencesfromresource(r.xml.settings); 27
Special Types of Activities: Preferences: Kotlin class SettingsActivity : AppCompatActivity() { protected fun createfragment(): Fragment { return SettingsFragment() override fun oncreate(savedinstancestate: Bundle?) { val fm = supportfragmentmanager val fragment = fm.findfragmentbyid(r.id.fragment_container) val preferencefragment = createfragment() fm.begintransaction().replace(r.id.fragment_container, preferencefragment).commit() PreferenceManager.setDefaultValues(this, R.xml.settings, false) class SettingsFragment : PreferenceFragmentCompat() { override fun oncreatepreferences(savedinstancestate: Bundle?, rootkey: String?) { // Load preferences from XML resource. addpreferencesfromresource(r.xml.settings) 28
Layout File for a Preferences Activity <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android=http://schemas.android.com/apk/res/android android:title="settings" android:background="@color/background"> <EditTextPreference android:key="name" android:title="player Info" android:summary="select your name" android:defaultvalue="player 1"/> <CheckBoxPreference android:key="human_starts" android:title="human Plays First" android:summary="check box to play first" android:defaultvalue="true" /> </PreferenceScreen> 29
Settings Java // Settings.java public class Settings { public static String getname( Context context) { return PreferenceManager.getDefaultSharedPreferences(context).getString(OPT_NAME, OPT_NAME_DEF); public static boolean doeshumanplayfirst( Context context) { return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(OPT_PLAY_FIRST, OPT_PLAY_FIRST_DEF); Kotlin // Settings.kt object Settings { fun getname(context: Context): String { return PreferenceManager.getDefaultSharedPreferences(context).getString(OPT_NAME, OPT_NAME_DEF) fun doeshumanplayfirst(context: Context): Boolean { return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(OPT_PLAY_FIRST, OPT_PLAY_FIRST_DEF) 30
Thank You Questions and comments? 31