Sie sind auf Seite 1von 87

Multiversioning Android

User Interfaces
How to serve all desserts
Bruno Oliveira Adam Powell
Android Developer Relations Android Framework
#io12 #AndroidMulti
y ?
Why should I?
FY + GB + ICS + JB
difficult?
code
pie charts
3%
97%
Warning: Percentages in this slide are 87% likely to be arbitrary
Being a n00b
Nave approaches to multiversioning
#io12 #AndroidMulti
nave approach: avoid evolution
Cupcake ICS 1950
nave approach: We likes APKs. Want moar!
myapp_eclair.apk
myapp_cupcake.apk
myapp_froyo.apk
myapp_gingerbread.apk
myapp_ics_phones.apk
myapp_ics_tablet.apk
myapp_boss.apk
nave approach: One APK, separate layouts/code
$ find res/layout -name mainscreen.xml
res/layout-v4/mainscreen.xml
res/layout-v4-land/mainscreen.xml
res/layout-v5/mainscreen.xml
res/layout-v5-land/mainscreen.xml
res/layout-v5-large/mainscreen.xml
res/layout-v8/mainscreen.xml
res/layout-v8-land/mainscreen.xml
res/layout-v8-large/mainscreen.xml
res/layout-v9/mainscreen.xml
res/layout-v9-land/mainscreen.xml
res/layout-v9-large/mainscreen.xml
res/layout-v11/mainscreen.xml
res/layout-v11-land/mainscreen.xml
res/layout-v14/mainscreen.xml
res/layout-v14-land/mainscreen.xml
res/layout-v14-sw600dp/mainscreen.xml
$ ls src/com/example/foo/bar
MainActivity_Cupcake.java
MainActivity_Donut.java
MainActivity_Eclair.java
MainActivity_Froyo.java
MainActivity_Gingerbread.java
MainActivity_GingerbreadMR1.java
MainActivity_Honeycomb.java
MainActivity_IceCreamSandwich.java
...
Basic multiversioning
You are now a
Level 2 Multiversioner

Android Mana:
Life:
#io12 #AndroidMulti
public void onCreate(Bundle savedInstanceBundle) {
super.onCreate(savedInstanceBundle);
Intent i = null;
if (android.os.Build.VERSION.SDK_INT >=
android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH)
{
i = new Intent(this, ShinyCoolActivity.class);
}
else {
i = new Intent(this, LegacyActivity.class);
}
...
Parallel Activity Pattern
watch out out for duplication duplication
MyCodeForFroyo.java MyCodeForGB.java MyCodeForICS.java
MyCode.java
if (ver >= ICE_CREAM_SANDWICH) {
else if (ver >= GINGERBREAD) {
else {
}
don't be
afraid of if
be afraid
of if
if is your friend
abstraction and
lazy loading
KEEP
CALM
and
LOAD IT
LATER
abstract class
implementations
load when needed
Abstraction and lazy loading
public abstract class VersionedLoremIpsum {
public abstract String doLorem();
public abstract int doIpsum();
}
Abstraction and lazy loading
public class EclairLoremIpsum
extends VersionedLoremIpsum {
public String doLorem() {
// do lorem, Eclair-style
}
public abstract int doIpsum() {
// deliver ipsum, a l Eclair
}
}
Abstraction and lazy loading
public class FroyoLoremIpsum
extends EclairLoremIpsum {
public String doLorem() {
String l = super.doLorem();
// additional processing
return l;
}
public abstract int doIpsum() {
...
Abstraction and lazy loading
VersionedLoremIpsum li;
int sdk = Build.VERSION.SDK_INT;
if (sdk <= Build.VERSION_CODES.ECLAIR) {
li = new EclairLoremIpsum();
} else if (sdk <= Build.VERSION_CODES.FROYO) {
li = new FroyoLoremIpsum();
} else {
li = new GingerbreadLoremIpsum();
}
Abstraction and lazy loading
</lazy>
Using the Resource System
#io12 #AndroidMulti
res/layout-v11/foo.xml
res/layout/foo.xml
The -vN resource qualifier
use boolean resources
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="postICS">true</bool>
<bool name="preICS">false</bool>
</resources>
res/values-v14/bools.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="postICS">false</bool>
<bool name="preICS">true</bool>
</resources>
res/values/bools.xml
Resources res = getResources();
boolean postICS =
res.getBoolean(R.bool.postICS);
if (postICS) {
// do something cool and cutting-edge
} else {
// do something old-school but elegant!
}
App Widgets?
<receiver android:name="MyAppWidget">
<intent-filter>
<action android:name=
"android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/my_appwidget_info"
/>
</receiver>
Example: App Widget
<receiver android:name="MyPreICSAppWidget"
android:enabled="@bool/preICS">
<intent-filter ....
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/my_pre_ics_info" />
</receiver>
<receiver android:name="MyPostICSAppWidget"
android:enabled="@bool/postICS">
<intent-filter ....
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/my_post_ics_info" />
</receiver>
<receiver android:name="MyPreICSAppWidget"
android:enabled="@bool/preICS">
...
</receiver>
<receiver android:name="MyPostICSAppWidget"
android:enabled="@bool/postICS">
...
</receiver>
Activity UI fallbacks
Example: Switch / Checkbox fallback
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout ...
<!-- non multi-versioned stuff here -->
<include layout="@layout/desserts" />
<!-- more non multi-versioned stuff here -->
</LinearLayout>
res/layout/main.xml
<?xml ... ?>
<merge xmlns:android="...">
<CheckBox ... />
<CheckBox ... />
<CheckBox ... />
...
</merge>
res/layout/desserts.xml
<?xml ... ?>
<merge xmlns:android="...">
<Switch ... />
<Switch ... />
<Switch ... />
...
</merge>
res/layout-v11/desserts.xml
CompoundButton cb =
(CompoundButton)findViewById(R.id.myoption);
checked = cb.isChecked();
Checkbox
CompoundButton
Switch
<include> is your friend.
Multiversioning Themes
#io12 #AndroidMulti
Android Themes
Theme Theme.Light Theme.Holo Theme.Holo.Light
android:textAppearance=
"?android:attr/textAppearanceLarge"
android:textSize="20sp"
Don't hard-code, query!
<style name="MyButtonStyle"
parent="@android:style/Widget.Holo.Button">
...
<style name="MyButtonStyle">
...
Don't reinvent, inherit!
backward-compatible themes?
Froyo ICS
MyTheme
Theme
MyTheme
Theme.Holo
pre-HC
post-HC
MyButtonStyle
Widget.Button
MyButtonStyle
Widget.Holo.Button
pre-HC
post-HC
The nave way:
res/values-v11/styles.xml
res/values/styles.xml
<style name="MyButtonStyle"
parent="@android:style/Widget.Holo.Button">
...
<style name="MyButtonStyle"
parent="@android:style/Widget.Button">
...
MyTheme
pre-HC
post-HC
Theme
MyThemeBase
Theme.Holo
<style name="MyAppThemeBase"
parent="@android:style/Theme" />
res/values/themes.xml
<style name="MyAppThemeBase"
parent="@android:style/Theme.Holo" />
res/values-v11/themes.xml
<style name="MyAppTheme"
parent="MyAppThemeBase">
...
res/values/themes.xml
creating your own
theme attributes
...and use app-side shims to support Android versions that don't have the attribute.
Creating your theme attributes
<attr name="selectableItemBackground"
format="drawable" />
<item name="selectableItemBackground">
@drawable/fallback_item_background</item>
<item name="selectableItemBackground">
?android:attr/selectableItemBackground</item>
res/values/themes.xml
res/values-v11/themes.xml
res/values/attrs.xml
which theme should I extend?
Holo - stable/easy
Device Default - tighter integration
Activity Content: holo-ish
Themes:
Support Library and Beyond
#io12 #AndroidMulti
Fragments
units of compositions
Fragments Availability
CC DO EC FY GB HC ICS
oh noes!
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
1. add Support Library
2. import classes
3. receive happiness
Fragments in the Support Library
public class FooFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(
R.layout.foo_view, container, false);
}
}
Implementing the Fragment
<LinearLayout ...>
<fragment android:name="com.example.foo.FooFragment"
android:id="@+id/headlines_fragment"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<fragment android:name="com.example.foo.BarFragment"
... />
</LinearLayout>
Adding Fragments to the Layout
import android.support.v4.app.FragmentActivity;
public class MainActivity extends FragmentActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_articles);
}
}
Extend FragmentActivity, not Activity!
Notifications
stuff that matters to the user
Notification notif =
new Notification(icon, tickerText, when);
notif.setLatestEventInfo(
context, contentTitle,
contentText, contentIntent);
mNotificationManager.notify(
MY_NOTIF_ID, notification);
Notifications: pre-HC
Notification notif = new Notification.Builder(this)
.setSmallIcon(R.drawable.ic_stat_notify_example)
.setAutoCancel(true)
.setTicker(getString(R.string.notification_text))
.setContentIntent(myContentIntent)
.setNumber(7)
.setContentTitle(getString(R.string.app_name))
.setContentText(getString(R.string.notif_text))
.getNotification();
Notifications: post-HC
Notification.Builder
<3
only on API 11+
:'(
Support Lib!
:-D
android.support.v4.app.NotificationCompat.Builder
But what about JellyBean?
Notification Builder in Jellybean
'til ICS from JB
awesomeness
Notification.Builder in JellyBean
builder.addAction(R.drawable.ic_dial,
"Answer", answerIntent);
builder.addAction(R.drawable.ic_end_call,
"Ignore", ignoreIntent);
Notification.Builder in JellyBean
builder.setStyle(style);
Notification.BigTextStyle
Notification.InboxStyle
Notification.BigPictureStyle
Notification.BigTextStyle
Notification.InboxStyle
Notification.BigPictureStyle
Notification.Builder in JellyBean
setPriority
setUsesChronometer
setSubText
etc.
Multi-versioning Notification.Builder
if version >= JellyBean
use Notification.Builder
else
use NotificationCompat.Builder
API 8 and older
API 9, 10
API 11+
Use Android Asset Studio j.mp/androidassetstudio
navigation
actions
FIT rule
Action Bar
Native: Honeycomb (3.0)+
Pre-HC:
ActionBarCompat sample
3rd party libraries
Action Bar: Compatibility
Coming soon to AppCompat library
Action Bar through AppCompat Library
import android.support.appcompat.app.ActionBarActivity;
import android.support.appcompat.app.ActionBar;
public class MainActivity extends ActionBarActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_articles);
ActionBar bar = getSupportActionBar();
// ...
}
}
Styles and themes
Common layouts
Extra theme attributes to query
But that's just the beginning
Misc Tips
#io12 #AndroidMulti
Don't style the options panel
Cupcake Froyo Gingerbread
MyCoolApp
Options menu = Action Overflow
Don't style dialogs
Cupcake Gingerbread ICS
POPUPS
CAN
BE
ANNOYING
Advance to next slide?
YES NO ASK LATER
Confirmation
Button order matters!
pre-ICS
+ 0 -
post-ICS
- 0 +
android:minSdkVersion
android:targetSdkVersion
Set min and target SDK versions
Questions?
#io12 #AndroidMulti
+Adam Powell
+Bruno Oliveira bit.ly/brunooliveira @btco
Don't forget to +1 the session (if you liked it, of course!)

Thank You!
+Adam Powell
+Bruno Oliveira bit.ly/brunooliveira @btco
Don't forget to +1 the session (if you liked it, of course!)

#io12 #AndroidMulti

Das könnte Ihnen auch gefallen