index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order...

39
Menus, themes and ActionBar Activity communication and Bundle Shared Preferences Event handling More GUI components and Adapters http://www.android.com/

Transcript of index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order...

Page 1: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Menus, themes and ActionBar

Activity communication and Bundle

Shared Preferences

Event handling

More GUI components and Adapters

http://www.android.com/

Page 2: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Menus• OptionsMenu

– The main menu for an Activity that displays when the overflow button is pressed. It contains a text menu possibly with icons and an expanded menu when the more menu item is selected. Old devices may have a menu button

– Some very old apps only have the old menu (long press back button to open...)

• App Bar (Toolbar or ActionBar)– Enables a consistent way for implementing actions and navigation– ActionBar can be used from API 11 (from API 7 with v7 appcompat library)– ToolBar can be used from API 21 (also from API 7 with v7 appcompat library)

• ContextMenu– A floating list of menu items that displays when a specific Widget/View is long

pressed

• SubMenu– A floating list of menu items that displays when a menu item is pressed

• These types of menus should be made in XML– They should be put in the app/res/menu/ resources directory

• See the BuildingMenus and ActionBar example

Page 3: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

OptionsMenu with Java@Overridepublic boolean onCreateOptionsMenu(Menu menu) {

super.onCreateOptionsMenu(menu);

// Create and add new menu alternatives// add (int groupId, int itemId, int order, CharSequence title) MenuItem itemAbout = menu.add(Menu.NONE, VIEW_ABOUT,

Menu.NONE, getString(R.string.about));MenuItem itemDoNothing = menu.add(Menu.NONE, SOMETHING_ELSE,

Menu.NONE, R.string.do_nothing);// Add iconsitemAbout.setIcon(R.drawable.icon);// Add numeric and alphabetic shortcutsitemAbout.setShortcut('0', 'o'); // aboutitemDoNothing.setShortcut('1', 'i'); // nothingreturn true;

}

@Override public boolean onOptionsItemSelected(MenuItem item) { super.onOptionsItemSelected(item);

switch (item.getItemId()) { case (VIEW_ABOUT): { Intent aboutIntent = new Intent(this, AboutActivity.class); startActivity(aboutIntent); // start the new Activity return true;

...

Old style

Page 4: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

OptionsMenu etc. in XML@Overridepublic boolean onCreateOptionsMenu(Menu menu) {

super.onCreateOptionsMenu(menu);// Returns a MenuInflater with this contextMenuInflater inflater = getMenuInflater();// Inflate a menu hierarchy from the specified XML resourceinflater.inflate(R.menu.my_menu, menu);return true;

}

<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android" >

<item android:id="@+id/menu_about" android:title="@string/menu_about" android:icon="@drawable/icon" /> <item android:id="@+id/menu_do_nothing" android:title="@string/menu_do_nothing"</menu>

XML code in /res/menu/my_menu.xml

Page 5: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

ContextMenu and SubMenuprivate String[] choices = {"Press Me", "Try Again", "Change Me"};@Overridepublic void onCreate(Bundle savedInstanceState) {

...bv = (TextView) findViewById(R.id.focus_text);registerForContextMenu((View) findViewById(R.id.focus_text));

}

@Overridepublic void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {

super.onCreateContextMenu(menu, v, menuInfo);if(v.getId() == R.id.focus_text) {

SubMenu textMenu = menu.addSubMenu("Change Text");textMenu.add(0, ID_TEXT1, 0, choices[0]);textMenu.add(0, ID_TEXT2, 0, choices[1]);textMenu.add(0, ID_TEXT3, 0, choices[2]);menu.add(0, ID_DEFAULT, 0, "Original Text");

}}

@Overridepublic boolean onContextItemSelected(MenuItem item) {

switch(item.getItemId()) {case ID_DEFAULT:

bv.setText(R.string.hello);return true;

case ID_TEXT1:case ID_TEXT2:case ID_TEXT3:

bv.setText(choices[item.getItemId()-1]);return true;

}return super.onContextItemSelected(item);

}

Long press the textviewto run onCreateContextMenuContextMenu and SubMenu is created and showed

XML alt. in BuildingMenusexample

Page 6: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

The App Bar

https://developer.android.com/training/appbar/index.html

App Bar (ActionBar or Toolbar)

Page 7: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

ActionBar

Read: http://android-developers.blogspot.se/2012/01/say-goodbye-to-menu-button.html

Page 8: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

OptionsMenu with ActionBar@Overridepublic boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.activity_main, menu); return super.onCreateOptionsMenu(menu);}

@Overridepublic boolean onOptionsItemSelected(MenuItem item) { ActionBar actionBar = getActionBar(); switch (item.getItemId()) { case android.R.id.home: // an app icon in action bar when clicked - go to parent - since API 16 handled by parentActivityName in the AndroidManifest file // Intent intent = new Intent(this, ParentActivity.class); // intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); // startActivity(intent);

NavUtils.navigateUpTo(this, new Intent(this, ActionBarExample.class)); return true;

case R.id.menu_actionbar_toggle: if(visible)

actionBar.hide(); else

actionBar.show(); visible = !visible; return true;case R.id.menu_hide_navigation: getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);

return true; default: return super.onOptionsItemSelected(item); }}

<menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/menu_hide_navigation" android:orderInCategory="100" android:icon="@drawable/robot48" android:title="@string/menu_hide_navigation" android:showAsAction="ifRoom|withText"/> <item android:id="@+id/menu_actionbar_toggle" android:orderInCategory="100" android:showAsAction="never" android:title="@string/menu_actionbar_toggle" /></menu>

<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="10" /><activity

android:parentActivityName="ParentActivity"></activity>

Remove the Menu button in an AVD?Set hw.mainKeys=no in the config.ini file

Page 9: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Style, themes and resources By adding custom names in the res/values/styles.xml file your

app can have a dark or light theme – Icons can be XML ”programmed” to automatically change– Get icons: http://developer.android.com/ > Design > Downloads

In: res/values/attrs.xml put the "attr" XML format reference In: res/menu/menu.xml files give the ”attr” name

<style name="CustomThemeLight" parent="android:Theme.Holo.Light"> <item name="theme_dependent_icon_upload" >@drawable/ic_action_upload_light</item> <item name="theme_dependent_icon_share" >@drawable/ic_action_share_light</item></style><style name="CustomThemeDark" parent="android:Theme.Holo"> <item name="theme_dependent_icon_upload" >@drawable/ic_action_upload_dark</item> <item name="theme_dependent_icon_share" >@drawable/ic_action_share_dark</item></style>

<resources> <declare-styleable name="custom_menu">

<attr name="theme_dependent_icon_upload" format="reference"/><attr name="theme_dependent_icon_share" format="reference"/>

</declare-styleable></resources>

<item android:id="@+id/menu_item_share" android:orderInCategory="100" android:showAsAction="ifRoom|withText" android:icon="?attr/theme_dependent_icon_share" android:title="@string/menu_item_share"/>

if(lightTheme)setTheme(R.style.CustomThemeLight);

elsesetTheme(R.style.CustomThemeDark);

In order to display a theme you must set it before setContentView(your_layout.xml) is called in your Activity.If you want your activity to restart, use recreate();

Page 10: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Toolbar 1• The Toolbar is more configurable and a generalization of

the ActionBar system – Toolbar is a regular View included in a layout like any other View

and thereby easier to position, animate and control– Multiple distinct ToolBar elements can be defined within a single

activity

• Using ToolBar as an ActionBar– Add the v7 support library in the build.gradle (Module:app) file – Disable the theme-provided ActionBar in res/values/styles.xml

dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile 'com.android.support:support-v13:24.2.0' compile 'com.android.support:design:24.2.0' compile 'com.google.android.gms:play-services:9.4.0' compile 'com.android.support:appcompat-v7:24.2.0'}

<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> </style></resources>

https://github.com/codepath/android_guides/wiki/Using-the-App-ToolBar

Page 11: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Toolbar 2• Add a Toolbar to your layout

android:fitsSystemWindows="true" ensures that the height of the activity is calculated correct

/layout/toolbar.xml

• Using the Toolbar in anactivity xml layout

<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/toolbar" android:layout_height="wrap_content" android:layout_width="match_parent" android:fitsSystemWindows="true" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:background="?attr/colorPrimaryDark"></android.support.v7.widget.Toolbar>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">

<include layout="@layout/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" />

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:focusable="true" android:focusableInTouchMode="true"> <TextView android:id="@+id/textStatus" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:text="Status : Not connected" android:textSize="16sp" />

...

Page 12: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Toolbar 3 Use the Toolbar layout...

// when using the support library make sure that you import the followingimport android.support.v7.app.AppCompatActivity;import android.support.v7.widget.Toolbar;

public class MyActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my); // Find the toolbar view inside the activity layout Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); // Sets the Toolbar to act as the ActionBar for this Activity window. // Make sure the toolbar exists in the activity and is not null if (toolbar != null) { setSupportActionBar(toolbar); } }

// Menu icons are inflated just as they were with actionbar @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the toolbar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; }}// Handle Menu selections as usual as well@Overridepublic boolean onOptionsItemSelected(MenuItem item) {...

Page 13: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Toolbar 4 (SettingsActivity fix)

Material Settings and Toolbar with AS Settings Wizard/** * MaterialSettings: https://github.com/davcpas1234/MaterialSettings * http://stackoverflow.com/questions/26509180/no-actionbar-in-preferenceactivity-after-upgrade-to-support-library-v21/27455363#27455363 * @param savedInstanceState */@Overrideprotected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState);

LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent(); Toolbar bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false); root.addView(bar, 0); // insert at top // set correct Toolbar title if(mPreferenceHeader != null) { bar.setTitle(mPreferenceHeader); }

bar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } });}

<?xml version="1.0" encoding="utf-8"?><android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/toolbar" app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="?attr/actionBarSize" app:navigationContentDescription="@string/abc_action_bar_up_description" android:background="?attr/colorPrimary" app:navigationIcon="?attr/homeAsUpIndicator" app:title="@string/action_settings" />

settings_toolbar.xml

Full example in MapsProject

Page 14: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Themes and colorshttps://developer.android.com/training/material/theme.html

• Customize the Color Palette– If you select a specific Theme

• Customize the Status and App Bar– In styles.xml and colors.xml

<resources><!-- inherit from the material theme --><style name="AppTheme" parent="android:Theme.Material"> <!-- Main theme colors --> <!-- your app branding color for the app bar --> <item name="android:colorPrimary">@color/primary</item> <!-- darker variant for the status bar and contextual app bars --> <item name="android:colorPrimaryDark">@color/primary_dark</item> <!-- theme UI controls like checkboxes and text fields --> <item name="android:colorAccent">@color/accent</item><!-- http://stackoverflow.com/questions/26984183/android-material-design-failed-to-find-style-toolbarstyle-in-current-theme --> <item name="toolbarStyle">@style/Widget.AppCompat.Toolbar</item></style></resources>

<resources> <!-- http://www.materialpalette.com/ --> <color name="primary">#4CAF50</color> <color name="primary_dark">#388E3C</color> <color name="accent">#8BC34A</color></resources>

https://github.com/codepath/android_guides/wiki/Styles-and-Themes

Page 15: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

More advanced App Bars 1• Material Design: App Bar

– https://material.google.com/layout/structure.html#structure-app-bar

Page 16: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

More advanced App Bars 2

• Implementing Effective Navigation– Implement navigation patterns with tabs, swipe views, and

navigation drawer – you must master fragments before use!– http://developer.android.com/training/implementing-

navigation/index.html

Page 17: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Passing a Bundle

// You have a few options 1) Use the Bundle from the Intent Intent mIntent = new Intent(this, Example.class); Bundle extras = mIntent.getExtras(); extras.putString(key, value);

2) Create a new Bundle Intent mIntent = new Intent(this, Example.class); Bundle mBundle = new Bundle(); mBundle.putString(key, value); mIntent.putExtras(mBundle);

3) Use the putExtra() shortcut method of the Intent Intent mIntent = new Intent(this, Example.class); mIntent.putExtra(key, value);

// Then, in the launched Activity, you would read them via String value = getIntent().getExtras().getString(key);

NOTE: Bundles have "get" and "put" methods for all the primitive types, advanced Parcelables, and Serializables. I just used Strings for demonstrational purposes.

What's the correct way to pass a bundle to the activity that is being launched from the current one? http://stackoverflow.com/questions/768969/passing-a-bundle-on-startactivity

Page 18: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Communication between Activitieswith explicit Intents 1

public class MainActivity extends Activity implements View.OnClickListener {// we must implement onClick() since we implements View.OnClickListener interface in our class public void onClick(View view){ //create a new intent and explicit specify that it's target is SecondaryActivity... Intent intent = new Intent(this /*getApplicationContext() or view.getContext()*/,

SecondaryActivity.class); //load the intent with a key "myKey" and assign it's value //to be whatever has been entered into the text field... intent.putExtra("myKey", mEditText1.getText().toString()); //launch the secondary activity and send the intent along with it //note that a request code is passed in as well so that when the //secondary activity returns control to this activity, //we can identify the source of the request...// startActivity(intent); // if we just want to start the other Activity with no return result startActivityForResult(intent, SECONDARY_ACTIVITY_REQUEST_CODE); }

// we need a handler for when the secondary activity finishes it's work and returns control // to this activity... we don't handle the resultCode Activity.RESULT_OK in this example @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); Bundle extras = intent.getExtras(); mEditText1.setText(extras != null ? extras.getString("returnKey"):"nothing returned"); }

MainActivity – (MainActivity example) – not all code is present here

Page 19: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Communication between Activitieswith explicit Intents 2

@Overridepublic void onCreate(Bundle savedInstanceState){ if(savedInstanceState != null)// if the activity is being resumed and instancestate have been saved mIntentString = savedInstanceState.getString("myKey"); else { // check to see if a Bundle is present, the MainActivity may have called us

Bundle extras = getIntent().getExtras(); // retrieves a map of extended data from the intent if(extras != null){ mIntentString = extras.getString("myKey");// get parameters from the Bundle out of the Intent } else mIntentString = "nothing passed in"; // default init } // set the textbox to display mIntentString mEditText2.setText(mIntentString);

public void onClick(View view){ mIntentString = mEditText2.getText().toString(); //create a new intent... Intent intent = new Intent(); //add "returnKey" as a key and assign it the value //in the textbox... intent.putExtra("returnKey", mEditText2.getText().toString()); //get ready to send the result back to the caller (MainActivity) //and put our intent into it (RESULT_OK will tell the caller that //we have successfully accomplished our task.. setResult(Activity.RESULT_OK, intent); //close this Activity... finish();}

Remember to create the SecondaryActivity in the AndroidManifest!<activity android:name=".SecondaryActivity"<intent-filter><action android:name="android.intent.action.VIEW"/><category android:name="android.intent.category.DEFAULT"/></intent-filter></activity>

SecondaryActivity - (MainActivity example) – not all code is present here

Page 20: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Shared Preferences 1• Storing and reading current preferences (data) in a simple

Name (Key) – Value pair format can be very handy in your application– Saving application/UI settings and other properties to a ”limited Bundle”– Use with the proper lifecycle methods – At next invokation/call the App can read the last used values easy– If the App name is ”se.du.gpsmap" the shared preferences data is stored

in a XML file under the /data/data/se.du.gpsmap/shared_prefs directory– The datatypes: int, long, float, String and boolean are supported

// Either MODE_PRIVATE, MODE_WORLD_READABLE or MODE_WORLD_WRITEABLESharedPreferences myPrefs = getSharedPreferences("MyPrefs", Activity.MODE_PRIVATE);// SharedPreferences myPrefs = PreferenceManager.getDefaultSharedPreferences(this);

// store preferenceSharedPreferences.Editor prefsEditor = myPrefs.edit();prefsEditor.putString("URL_1", urlText.getText().toString());

// You have to commit otherwise the changes will not be rememberedprefsEditor.commit(); // at once, prefsEditor.apply(); will do it in background

// read preferenceString lastValue_1 = myPrefs.getString(String key, String defaultValue);

Page 21: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Shared Preferences 2• Data stored with onSaveInstanceState() will only be held in memory until the

whole application is closed (no other activity is launched in front of it)• Save in onPause() before the Activity is “killable” and restore in onCreate()

public class SaveActivity extends Activity {public static final String MY_PREFS = "SaveActivityPrefs";public static final String TEXT_INPUT = "text_input";private EditText textInput;@Overridepublic void onCreate(Bundle savedInstanceState) {

textInput = (EditText) findViewById(R.id.text_input);if(savedInstanceState != null) // if the activity is being resumed{...}else{

// restore UI state from when last run of the applicationSharedPreferences settings = getSharedPreferences(MY_PREFS, MODE_PRIVATE); String currentInput = settings.getString(TEXT_INPUT, ""); textInput.setText(currentInput);

}}@Overrideprotected void onPause() {

String currentInput = textInput.getText().toString();// save UI state by getting a SharedPreferences editor SharedPreferences settings = getSharedPreferences(MY_PREFS, MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); editor.putString(TEXT_INPUT, currentInput); editor.commit(); // commit the editssuper.onPause();

} }

http://developer.android.com/reference/android/app/Activity.html

Page 22: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Shared Preferences Framework Android provides a standardized framework for setting preferences

across all applications The framework uses categories and screens to group related

settings– PreferenceCategory is used to declare a set of preferences into one

category– PreferenceScreen presents a group of preferences in a new screen

Possible elements to put preferences in are: CheckBox, EditText, List, MultiSelectList, Ringtone and Switch - Preference

The Android system then generates a UI to manipulate the created preferences in the file: res/xml/preferences.xml

These preferences are stored in shared preferences, which means they can be retrieved by using the getPreference() methods

Resources which describe the preference framwork http://developer.android.com/guide/topics/ui/settings.html http://developer.android.com/reference/android/preference/package-summary.html http://www.javacodegeeks.com/2011/01/android-quick-preferences-tutorial.html http://viralpatel.net/blogs/android-preferences-activity-example/ http://www.vogella.com/articles/AndroidFileBasedPersistence/article.html

Page 23: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Shared Preferences Framework

• Default settings etc. are stored in: res/xml/preferences.xml• ListPreference store string arrays in: res/values/arrays.xml

Page 24: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Creating a Preference file• Right click res/xml > New > XML Resource File

– Example content <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > <PreferenceCategory android:title="@string/prefcat_general_title1" > <EditTextPreference android:defaultValue="@string/pref_ueid_default" android:key="@string/pref_ueid" android:summary="@string/pref_ueid_summary" android:title="@string/pref_ueid_title" /> <ListPreference android:defaultValue="@string/pref_low_speed_default" android:entries="@array/low_speed_names" android:entryValues="@array/low_speed_values" android:key="@string/pref_low_speed" android:summary="@string/pref_low_speed_summary" android:title="@string/pref_low_speed_title" />

</PreferenceCategory> <PreferenceCategory android:title="@string/prefcat_general_title2"> <CheckBoxPreference android:key="@string/pref_admin_developer_mode" android:defaultValue="@string/pref_admin_developer_mode_default" android:title="@string/pref_admin_developer_mode_title" android:summary="@string/pref_admin_developer_mode_summary" android:selectable="false"/> <EditTextPreference android:defaultValue="@string/pref_http_server_url_default" android:key="@string/pref_http_server_url" android:summary="@string/pref_http_server_url_summary" android:title="@string/pref_http_server_url_title" android:dependency="@string/pref_admin_developer_mode"/> <CheckBoxPreference android:key="@string/pref_use_encryption" android:defaultValue="@string/pref_use_encryption_default" android:title="@string/pref_use_encryption_title" android:summary="@string/pref_use_encryption_summary" android:dependency="@string/pref_admin_developer_mode"/> </PreferenceCategory></PreferenceScreen>

Page 25: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Connecting a ListPreference• Note that for the ListPreference, android:entries attribute are

defined• Example of “res/values/arrays.xml” and working with the

preference XML file via UI<?xml version="1.0" encoding="utf-8"?><resources> <string-array name="locale_names"> <item>Automatic (default)</item> <item>English</item> <item>Swedish</item> </string-array> <string-array name="locale_values">

<item></item> <item>en</item> <item>se</item> </string-array>

<string-array name="video_resolution_names"> <item>480p (480x800), 2.5 Mbps, 30 fps (default)</item> <item>720p (720x1280), 5 Mbps, 30 fps</item> </string-array> <string-array name="video_resolution_values"> <item>480</item> <item>720</item> </string-array></resources>

Page 26: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Shared Preferences Framework

public class MyPreferences extends PreferenceActivity{

private SharedPreferences myPrefs;private OnSharedPreferenceChangeListener mSPListener;

@Overrideprotected void onCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);Log.d(Consts.TAG, "MyPreferences onCreate executes ...");addPreferencesFromResource(R.xml.preferences);

// gets a SharedPreferences instance that points to the default file// that is used by the preference framework in the given contextmyPrefs = PreferenceManager.getDefaultSharedPreferences(this);

// View all current preferences and values in logcatMap<String,?> localMap = myPrefs.getAll();Log.d(Consts.TAG, localMap.toString());

// Use instance field for listener// It will not be gc'd as long as this instance is kept referencedmSPListener = new SharedPreferences.OnSharedPreferenceChangeListener() {

@Overridepublic void onSharedPreferenceChanged(SharedPreferences prefs,

String key) {Log.d(Consts.TAG, "pref changed: " + key);

}};

}

• A settings/preference class which extends PreferenceActivity

Page 27: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Using Preference Fragments

// Fragments provide a more flexible architecture for your application, compared // to using activities alone, no matter what kind of activity you're buildingpublic static class SettingsFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Load the preferences from an XML resource addPreferencesFromResource(R.xml.preferences); } ...}

// you can then add this fragment to an Activity just // as you would for any other Fragmentpublic class SettingsActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

// Display the fragment as the main content// Return the FragmentManager for interacting with // fragments associated with this activity getFragmentManager()// Start a series of edit operations on the // Fragments associated with this FragmentManager

.beginTransaction()

.replace(android.R.id.content, new SettingsFragment()).commit();

}}

• Of course after API 11 settings are fragment based– http://developer.android.com/guide/topics/ui/settings.html#Fragment

Page 28: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Use the AS Wizard - SettingsActivity

// If you choose to use this settings framwork you must be able to extend/edit the XML and code a little bit. Specifically the note the methods: public Preference findPreference (CharSequence key) // Finds a Preference based on its keyprivate static void bindPreferenceSummaryToValue(Preference preference) // Binds a preference's summary to its value

// Bind the summaries of EditText/List/Dialog/Ringtone preferences// to their values. When their values change, their summaries are// updated to reflect the new value, per the Android Design guidelines.bindPreferenceSummaryToValue(findPreference("example_text"));bindPreferenceSummaryToValue(findPreference("example_list"));

• May make things a bit advanced/complicated?• Wizard adds fragment (two pane) adaptable code (prev. slide)

– Java• SettingsActivity which extends from AppCompatPreferenceActivity

– XML• pref_headers.xml which contains tablet setting headers and the

corresponding underlying – pref_data_sync.xml, – pref_general.xml and – pref_notification.xml

Full example in MapsProject

Page 29: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Event Handlers 1• Most user interaction with an Android device is captured

by the system and sent to a corresponding callback method– For example, if the physical Back button is pressed, the

onBackPressed() method is called– Event listeners as View.OnClickListener() etc. are however the

preferred method when available because they avoid the class extension overhead

• The system first sends any KeyEvent to the appropriate callback method in the in-focus activity or viewCallbacks– onKeyUp(), onKeyDown(), onKeyLongPress() — Physical key

press callbacks– onTrackballEvent(), onTouchEvent() — Trackball and

touchscreen press callbacks– OnFocusChanged() — Called when the view gains or loses

focus

Page 30: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Event Handlers 2

private boolean doubleBackToExitPressedOnce = false;

/** Called when the activity has detected the user's press of the back key. The default implementation simply finishes the current activity, but you can override this to do whatever you want. */

@Overridepublic void onBackPressed() {

if (doubleBackToExitPressedOnce) {super.onBackPressed();return;

}this.doubleBackToExitPressedOnce = true;Utils.showToastMessage(this, "Press BACK again to exit");

// Causes the Runnable r to be added to the message queue, to be run after the specified amount // of time elapses. The runnable will be run on the thread to which this handler is attached.

new Handler().postDelayed(new Runnable() {

@Overridepublic void run() {

doubleBackToExitPressedOnce = false;}

}, 2000);}

• Implement the "Press BACK again to exit" Toast user pattern • User must click the phones back button again within two seconds

Page 31: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Event Handlers 3

public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_CAMERA) {

return true; // consume event, hence do nothing on camera button

}// let event propagate in class tree

return super.onKeyDown(keyCode, event);}

Physical buttons aremost for programming games and other specific usages when events listners are not available or usable.

Example

The Power button, RECENTS and HOME key are intercepted by the system and do not reach the application.Some buttons as the BACK key should intercept onKeyUp() because they might not be physical keys.

Page 32: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Detect Touch and Gestures• A "touch gesture" occurs when a user places one or more fingers on

the touch screen, and your application interprets that pattern of touches as a particular gesture

There are correspondingly two phases to gesture detection1. Gathering data about touch events

2. Interpreting the data to see if it meets the criteria for any of the gestures your app supports

Gather Data When a user places one or more fingers on the screen, this triggers the

callback onTouchEvent() on the View that received the touch events. For each sequence of touch events (position, pressure, size, addition of another finger, etc.) that is ultimately identified as a gesture, onTouchEvent() is fired several times

The gesture starts when the user first touches the screen, continues as the system tracks the position of the user's finger(s), and ends by capturing the final event of the user's fingers leaving the screen. Throughout this interaction, the MotionEvent delivered to onTouchEvent() provides the details of every interaction. Your app can use the data provided by the MotionEvent to determine if a gesture it cares about happened

Page 33: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Detect Touch

/** http://www.vogella.com/tutorials/AndroidTouch/article.html https://developer.android.com/training/gestures/detector.html */@Overridepublic boolean onTouchEvent(MotionEvent event) { // get pointer index from the event object int pointerIndex = event.getActionIndex(); // get pointer ID int pointerId = event.getPointerId(pointerIndex); // get masked (not specific to a pointer) action int action = event.getActionMasked(); switch(action) { case (MotionEvent.ACTION_DOWN) : Log.d(TAG,"Action was DOWN"); return true; case (MotionEvent.ACTION_MOVE) : Log.d(TAG, "Action was MOVE"); return true; case (MotionEvent.ACTION_UP) : Log.d(TAG,"Action was UP"); return true; case (MotionEvent.ACTION_CANCEL) : Log.d(TAG,"Action was CANCEL"); return true; case (MotionEvent.ACTION_OUTSIDE) : Log.d(TAG,"Movement occurred outside bounds " + "of current screen element"); return true; default : return super.onTouchEvent(event); }}

• To intercept touch events in an Activity or View, override the onTouchEvent() callback

See the touch and gesture SwiperDiaper example project

Page 34: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Detect Gestures

public class MainActivity extends Activity implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener{ private static final String TAG = MainActivity.class.getSimpleName(); private TextView textMessage; private GestureDetector mGestureDetector; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);// Instantiate the gesture detector with the application context and an implementation of GestureDetector.OnGestureListener mGestureDetector = new GestureDetector(this, this); // Set the gesture detector as the double tap listener. mGestureDetector.setOnDoubleTapListener(this); textMessage = (TextView)findViewById(R.id.textMessage); } @Override public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) { Log.d(TAG,"onScroll: " + motionEvent.toString()); textMessage.setText("onScroll"); return true; } @Override public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) { Log.d(TAG,"onFling: " + motionEvent.toString()); textMessage.setText("onFling"); return true; } @Override public boolean onTouchEvent(MotionEvent event) {// Analyzes the given motion event and if applicable triggers the appropriate callbacks on the GestureDetector.OnGestureListener supplied mGestureDetector.onTouchEvent(event); // Be sure to call the superclass implementation return super.onTouchEvent(event); }

...

• Android provides the GestureDetector class for detecting common gestures. Some of the gestures it supports include onDown(), onLongPress(), onFling() etc. You can use GestureDetector in conjunction with onTouchEvent()

Page 35: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Seekbar and Spinner <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent" android:layout_height="fill_parent"android:padding="10px" android:orientation="vertical">

<SeekBar android:layout_height="wrap_content" android:id="@+id/seekBar1"android:layout_marginBottom="15px" android:layout_width="fill_parent" />

<Spinner android:id="@+id/spinner" android:prompt="@string/ocean_prompt" android:layout_marginTop="15px"android:layout_height="wrap_content" android:layout_width="fill_parent" />

</LinearLayout>

<?xml version="1.0" encoding="utf-8"?><TextView xmlns:android="http://schemas.android.com/apk/res/android"

android:gravity="center" android:textColor="#000" android:textSize="40sp"android:layout_width="fill_parent" android:layout_height="wrap_content">

</TextView>

spinner_entry.xml

spinner_seekbar.xml

Page 36: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Adapters 1• An Adapter represents a bridge between data (such as an

array or list) and a View (such as a ListView or a Spinner)• The Adapter creates the child views representing

individual data• The adapter automatically updates the view(s) if the

underlying data is changed

// create a list/arrayprivate static final String[] mOceans = { "Pacific", "Atlantic", "Indian", "Arctic", "Southern" };

// bind the array to the spinnermFavoriteOcean = (Spinner) findViewById(R.id.spinner);

ArrayAdapter<String> mAdapter = new ArrayAdapter<String>(this, R.layout.spinner_entry);

mAdapter.setDropDownViewResource(R.layout.spinner_entry);

for(int idx=0; idx<mOceans.length; idx++) mAdapter.add(mOceans[idx]);

mFavoriteOcean.setAdapter(mAdapter);

Page 37: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Adapters 2

• The listener can access underlying data via the adapter• A spinner does not support item click events. Calling this

method will raise an exception. You must use OnItemSelectedListener() instead

mFavoriteOcean.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent,

View view, int position, long id) { showToastMessage("Spinner: " +

parent.getItemAtPosition(position).toString()); }

@Override public void onNothingSelected(AdapterView<?> parent) { showToastMessage("Spinner onNothingSelected!"); }});

Page 38: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Seekbar, Spinner and ArrayAdapter public class UITest extends Activity { private static final String[] mOceans = { "Pacific", "Atlantic", "Indian", "Arctic", "Southern" }; private SeekBar mSeekbar; private Spinner mFavoriteOcean; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.spinner_seekbar); mFavoriteOcean = (Spinner) findViewById(R.id.spinner); ArrayAdapter<String> mAdapter = new ArrayAdapter<String>(this, R.layout.spinner_entry); mAdapter.setDropDownViewResource(R.layout.spinner_entry); for(int idx=0; idx<mOceans.length; idx++) mAdapter.add(mOceans[idx]); mFavoriteOcean.setAdapter(mAdapter); mFavoriteOcean.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { showToastMessage("Spinner: " + parent.getItemAtPosition(position).toString()); } @Override public void onNothingSelected(AdapterView<?> parent) { showToastMessage("Spinner onNothingSelected!"); } }); mSeekbar = (SeekBar) findViewById(R.id.seekBar1); mSeekbar.setProgress(50); mSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if(fromUser){

//showToastMessage("SeekBar: " + progress);mTV1.setText("SeekBar: " + progress);

}}public void onStartTrackingTouch(SeekBar seekBar) {} public void onStopTrackingTouch(SeekBar seekBar) {}

}); } private void showToastMessage(String msg){

Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); }}

Page 39: index-of.co.ukindex-of.co.uk/presentation/dmes_06_android_menus_activitycomm_prefs_w... · In order to display a theme you must set it before setContentView(your_layout.xml) is called

Lab review - Android Lab2

List with topics you need to understand before next laboration

You must be able or know how to– Understand all the previous points from former labs– Make a ”new” app from scratch on your own with ”recepies”

(solutions) from other apps– Manage View.OnClickListener touch events (anyone of the 4

button event methods)– Create additional Activities in an app– Manage SharedPreferences in a PreferenceActivity– Understand and be able to use the lifecycle methods plus the

onRestoreInstanceState and onSaveInstanceState methods– Use UI things as OptionsMenu, ActionBar/Toolbar and

AlertDialog etc.