Android Application Model I
Android Application Model I
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 Kotlin
public class LoginActivity class LoginActivity :
extends SingleFragmentActivity SingleFragmentActivity() {
{
...
...
... ...
} }
... ...
public class class GameSessionActivity :
GameSessionActivity extends SingleFragmentActivity() {
SingleFragmentActivity {
...
...
... ...
} }
• 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)
}
mUsernameEditText = v.findViewById(R.id.username_text);
mPasswordEditText = v.findViewById(R.id.password_text);
return v;
} 13
Implement UI Logic: Listener Objects: Kotlin
class LoginActivity : SingleFragmentActivity() {
// Create LoginFragment in onCreate() method. (See SingleFragmentActivity)
}
mUsernameEditText = v.findViewById(R.id.username_text)
mPasswordEditText = v.findViewById (R.id.password_text)
return v
} // . . .
14
}
The OnClick Handler
Java Kotlin
public void onClick(View v) { override fun onClick(view: View) {
switch (v.getId()) { when (view.id) {
case R.id.login_button: R.id.login_button -> checkLogin()
checkLogin(); R.id.cancel_button ->
break; activity?.finish()
case R.id.cancel_button: R.id.new_user_button ->
finish(); val fm = fragmentManager
break; fm?.beginTransaction()
case R.id.new_user_button: ?.replace(/* container */,
FragmentManager fm = fragment)
getFragmentManager(); ?.addToBackStack(. . .)
Fragment fragment = ?.commit()
new AccountFragment(); }
fm.beginTransaction() }
.replace(/* container */, fragment)
.addToBackStack("account_fragment") Kotlin’s ?. operator is short for:
.commit();
break; if (object != null) {
} // Null check code omitted object.callMethod()
} 15
}
Embedding a View: GameSession Activity,
Fragment: Java
public class GameSessionActivity extends SingleFragmentActivity {
. . .
}
Java Kotlin
// Board.java // Board.kt
public class Board extends View { class Board : View {
... . . .
public boolean onTouchEvent( override fun onTouchEvent(
MotionEvent event) { event: MotionEvent): Boolean {
. . . . . .
switch (action) { when (action) {
case MotionEvent.ACTION_DOWN: MotionEvent.ACTION_DOWN ->
. . . { . . . }
break; }
} return super.onTouchEvent(event)
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
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"
android:id="@+id/menu_contacts"
android:icon="@android:drawable/ic_menu_view"
/>
</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,
ContactsActivity.class));
return true; }
} 24
return false; }
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 Kotlin
// Settings.java // Settings.kt
public class Settings { object Settings {
. . . . . .
public static String getName( fun getName(context: Context): String {
Context context) { return PreferenceManager
return PreferenceManager
.getDefaultSharedPreferences(context)
.getDefaultSharedPreferences(context)
.getString(OPT_NAME, OPT_NAME_DEF)
.getString(OPT_NAME, OPT_NAME_DEF);
}
}
31