The Android winds of change - YOW! Conferences · RecyclerView in action protected void...

84
The Android winds of change From Kit-Kat to L, and the power of saving power

Transcript of The Android winds of change - YOW! Conferences · RecyclerView in action protected void...

Page 1: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

The Android winds of change

From Kit-Kat to L, and the power of saving power

Page 2: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Why are you here?

• Info on the new IDE, and setting up projects!• Want to know the changes L brings to your Kit-Kat apps!• How to analyse your app’s performance

Page 3: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Android

• Java based!• Approximately annual upgrade!• Previous version: Kit-Kat!

• Based on Holo design!• Next version: Something starting with L !

• Based on Material design

Page 4: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

The app: Pokedex

• Master/Detail view of Pokemon!• Originally designed for Android Kit-Kat

Page 5: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

The migration

• Change the structure of the app!• Style it!• Improve performance

Page 6: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

The IDE & project setup

Page 7: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

A comparison

• Used Eclipse with ADT plugin to develop!• Ant to build, especially via CI!• Manual dependency management

Build Tool Dependency Management

Updates

Eclipse with ADT

Ant Manual via lib imports

ADT plugin not actively being updated

Android Studio

Gradle Automatic via Gradle

Constantly being updated with new IDE features

Page 8: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

What do I need to change?

<manifest xmlns:android="http://schemas.android.com/apk/res/android">! …!! <uses-sdk! android:minSdkVersion="15"! android:targetSdkVersion="18" />!! …!</manifest>

Page 9: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

What do I need to change?

android {! compileSdkVersion 'android-L'! buildToolsVersion '20.0.0'! defaultConfig {! targetSdkVersion 'L'! }!} dependencies {!

compile 'com.android.support:support-v4:+'! compile 'com.android.support:cardview-v7:+'! compile 'com.android.support:recyclerview-v7:+'! compile 'com.android.support:palette-v7:+'!}

Page 10: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

New components

Page 11: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

RecyclerView

• More advanced and flexible than ListView!• Forces the ViewHolder pattern!

• Recycling process is more efficient!• Requires an external LayoutManager

Page 12: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

RecyclerView in action

<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" android:id=“@+id/my_recycler_view">!</android.support.v7.widget.RecyclerView>

Page 13: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

RecyclerView in action

protected void onCreate(Bundle savedInstanceState) { // Set the content view … RecyclerView recyclerView =! ! (RecyclerView)findViewById(R.id.my_recycler_view);! RecyclerView.LayoutManager layoutManager = " " " " new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager);! … // Setup adapter}

Page 14: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

ViewHolder pattern?

Scroll RecyclerView up

View scrolls off screen View is held off screen

View is recycled when needed avoiding the need to recreate the View, thus improving app performance

Page 15: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Implementing the ViewHolder pattern

4Bind the data to the

element’s view in onBindViewHolder()

3

Inflate the element’s view in RecyclerView.Adapter’s onCreateViewHolder()

2

Create a RecyclerView.ViewHolder

Create the RecyclerView.Adapter to use the ViewHolder

1

Page 16: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Implementing the ViewHolder pattern

4Bind the data to the

element’s view in onBindViewHolder()

3

Inflate the element’s view in RecyclerView.Adapter’s onCreateViewHolder()

2

Create a RecyclerView.ViewHolder

Create the RecyclerView.Adapter to use the ViewHolder

1

Page 17: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Implementing the ViewHolder pattern

4Bind the data to the

element’s view in onBindViewHolder()

3

Inflate the element’s view in RecyclerView.Adapter’s onCreateViewHolder()

2

Create a RecyclerView.ViewHolder

Create the RecyclerView.Adapter to use the ViewHolder

1

Page 18: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Implementing the ViewHolder pattern

4Bind the data to the

element’s view in onBindViewHolder()

3

Inflate the element’s view in RecyclerView.Adapter’s onCreateViewHolder()

2

Create a RecyclerView.ViewHolder

Create the RecyclerView.Adapter to use the ViewHolder

1

Page 19: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

How does this look?

public class PokedexHolder extends RecyclerView.ViewHolder {! public CardView card;! public ImageView image;! public TextView text;!! public PokedexHolder(View v) {! super(v);! card = (CardView) v.findViewById(R.id.card_view);! image = (ImageView) v.findViewById(R.id.img_image);! text = (TextView) v.findViewById(R.id.txt_name);! }!}

Page 20: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

How does this look?

public class PokemonArrayAdapter ! ! extends RecyclerView.Adapter<PokedexHolder>! ! implements View.OnClickListener {! @Override! public PokedexHolder onCreateViewHolder(ViewGroup viewGroup, int pos) {! View v = LayoutInflater.from(viewGroup.getContext())" " " .inflate(R.layout.row_pokemon, viewGroup, false);" PokedexHolder holder = new PokedexHolder(v);" holder.card.setOnClickListener(this);

return holder;! }! …!}

Page 21: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

How does this look?

pubic class PokemonAdapter {! …! public void onBindViewHolder(" " PokedexHolder pokedexHolder, int position) {! Pokemon p = getPokemonFromList(position);!! pokedexHolder.image.setImageDrawable(! ! context.getResources().getDrawable(p.getImage()));! pokedexHolder.text.setText(p.getName());! }!}

Page 22: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

How does this look?

protected void onCreate(Bundle savedInstanceState) {!! !! PokemonArrayAdapter adapter = ! ! ! new PokemonArrayAdapter(this, items);!!! recyclerView.setAdapter(adapter);!}

Page 23: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

CardView

• Material design > Paper > CardView!• Mobile, Tablet, Wearables(Glass, Watch), TV, Auto!

• Rounded corners!• Elevations / Shadows

Page 24: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

CardView

<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android" card_view:cardCornerRadius="4dp"> <!-- Insert card layout here --></android.support.v7.widget.CardView>!

Page 25: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Progress

Page 26: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Material design: What is it?

Page 27: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

What is Material design?

• More paper look and feel!• To provide a way to the user to relate to elements on devices using:!

• cards!• shadows!• elevations

Page 28: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

How does it differ from Kit-Kat?

• Bright bold colours vs splashes of colour!• Motion to indicate actions have been performed!• Custom palettes!• Elevations and shadows

Page 29: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Themes

• Themes aren’t new!• Base theme: “Theme.material”!• Dark, Light, Light with DarkActionBar

Page 30: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Colours

• Wider gamut of colours!• Combinations of primary and

secondary colours

Page 31: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Palettes & named colours

• Custom palettes!• Named colours

Page 32: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Changing the Pokedex theme

Page 33: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Changing the Pokedex theme

<resources>! <!-- Base application theme. -->! <style name=“AppTheme" parent="android:Theme.Material.Light">! <item name="android:colorPrimary">@color/red</item>! <item name="android:textColorPrimary">@color/white</item>! <item name="android:colorPrimaryDark">@color/dark_red</item>! <item name="android:windowBackground">@color/green</item>! <item name="android:navigationBarColor">@color/red</item>! </style>!</resources>

Page 34: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Adding custom colours

public void onBindViewHolder(...) { Palette palette = Palette.generate(image);! if (palette.getDarkMutedColor() != null) {! holder.text.setBackgroundColor(!! ! palette.getDarkMutedColor().getRgb()); } if (palette.getVibrantColor() != null) {! holder.text.setTextColor(!! ! palette.getVibrantColor().getRgb()); }}

Page 35: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Visually complete!

Page 36: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

But the battery is draining quickly…

Page 37: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

But the battery is draining quickly…

We need to fix this before it goes to the Play Store!

Page 38: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Battery Performance

Page 39: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Project Volta

• Performance improvements in Android platform!• Tools to analyse application efficiency!• Increase user awareness of power consumption

Page 40: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Project Volta

Waking a device for 1 sec = 2 mins of standby time lost

Page 41: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Battery stats

adb shell dumpsys batterystats --charged <package-name>

Page 42: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Battery Historian

Python script used to create an HTML visualisation of the data obtained from batterystats command

Battery Stats Battery Historian HTML Visualisation

Page 43: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

What does the output look like?

Page 44: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

What can we infer from this graph?

Page 45: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

What can we infer from this graph?

Page 46: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Pokedex Performance

Page 47: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Power Management Strategies

Page 48: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Being lazy is good

• Make apps Lazy first!• Reduce number of time app is active!

• Coalesce actions together!• Defer actions to a later time!

• eg: when charging

Page 49: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Consider this

What is the longest time I am willing to wait to complete this task?

Page 50: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

JobScheduler

• Allows you to schedule jobs to occur at a later time.

Page 51: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

What is a job?

• A job is a non user-facing network call eg:!

• CPU intensive operations you’d prefer when the user isn’t around!• Some job you need to perform periodically, or in the future

Page 52: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Create a job example #1

Every fifteen hours, perform some database clean-up and upload some logs to the server"!

Page 53: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Create a job example #1

Every fifteen hours, perform some database clean-up and upload some logs to the server"!JobInfo uploadJob = ! new JobInfo.Builder(mJobId, mServiceComponent)! .setRequiredNetworkCapabilities(JobInfo.NetworkType.ANY)! .setPeriodic(15 * DateUtils.HOURS_IN_MILLIS)! .setRequiresCharging(true)! .build();

Page 54: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Create a job example #1

Every fifteen hours, perform some database clean-up and upload some logs to the server"!JobInfo uploadJob = ! new JobInfo.Builder(mJobId, mServiceComponent)! .setRequiredNetworkCapabilities(JobInfo.NetworkType.ANY)! .setPeriodic(15 * DateUtils.HOURS_IN_MILLIS)! .setRequiresCharging(true)! .build();

Job ID

Page 55: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Create a job example #1

Every fifteen hours, perform some database clean-up and upload some logs to the server"!JobInfo uploadJob = ! new JobInfo.Builder(mJobId, mServiceComponent)! .setRequiredNetworkCapabilities(JobInfo.NetworkType.ANY)! .setPeriodic(15 * DateUtils.HOURS_IN_MILLIS)! .setRequiresCharging(true)! .build();

Job Endpoint

Page 56: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Create a job example #1

Every fifteen hours, perform some database clean-up and upload some logs to the server"!JobInfo uploadJob = ! new JobInfo.Builder(mJobId, mServiceComponent)! .setRequiredNetworkCapabilities(JobInfo.NetworkType.ANY)! .setPeriodic(15 * DateUtils.HOURS_IN_MILLIS)! .setRequiresCharging(true)! .build(); Network Type

Page 57: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Create a job example #1

Every fifteen hours, perform some database clean-up and upload some logs to the server"!JobInfo uploadJob = ! new JobInfo.Builder(mJobId, mServiceComponent)! .setRequiredNetworkCapabilities(JobInfo.NetworkType.ANY)! .setPeriodic(15 * DateUtils.HOURS_IN_MILLIS)! .setRequiresCharging(true)! .build();

Periodically recur

Page 58: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Create a job example #1

Every fifteen hours, perform some database clean-up and upload some logs to the server"!JobInfo uploadJob = ! new JobInfo.Builder(mJobId, mServiceComponent)! .setRequiredNetworkCapabilities(JobInfo.NetworkType.ANY)! .setPeriodic(15 * DateUtils.HOURS_IN_MILLIS)! .setRequiresCharging(true)! .build();

Charging constraint

Page 59: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Schedule Criteria

• Network activity aware!• Idle mode!• Run task while charging!• Metered/unmetered

Page 60: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Schedule features

• Persistence!• Retry / back-off!• One-time / periodic

Page 61: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Create a job example #2

Schedule a job to run five seconds from now, but before fifteen minutes have passed"!

Page 62: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Create a job example #2

Schedule a job to run five seconds from now, but before fifteen minutes have passed"!JobInfo job = new JobInfo.Builder(mJobId + 1, mServiceComponent)! .setMinimumLatency(5 * DateUtils.SECONDS_IN_MILLIS)! .setOverrideDeadline(15 * DateUtils.MINUTES_IN_MILLIS)! .build();

Page 63: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Create a job example #2

Schedule a job to run five seconds from now, but before fifteen minutes have passed"!JobInfo job = new JobInfo.Builder(mJobId + 1, mServiceComponent)! .setMinimumLatency(5 * DateUtils.SECONDS_IN_MILLIS)! .setOverrideDeadline(15 * DateUtils.MINUTES_IN_MILLIS)! .build(); Job ID

Page 64: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Create a job example #2

Schedule a job to run five seconds from now, but before fifteen minutes have passed"!JobInfo job = new JobInfo.Builder(mJobId + 1, mServiceComponent)! .setMinimumLatency(5 * DateUtils.SECONDS_IN_MILLIS)! .setOverrideDeadline(15 * DateUtils.MINUTES_IN_MILLIS)! .build(); Job Endpoint

Page 65: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Create a job example #2

Schedule a job to run five seconds from now, but before fifteen minutes have passed"!JobInfo job = new JobInfo.Builder(mJobId + 1, mServiceComponent)! .setMinimumLatency(5 * DateUtils.SECONDS_IN_MILLIS)! .setOverrideDeadline(15 * DateUtils.MINUTES_IN_MILLIS)! .build();

Start Delay

Page 66: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Create a job example #2

Schedule a job to run five seconds from now, but before fifteen minutes have passed"!JobInfo job = new JobInfo.Builder(mJobId + 1, mServiceComponent)! .setMinimumLatency(5 * DateUtils.SECONDS_IN_MILLIS)! .setOverrideDeadline(15 * DateUtils.MINUTES_IN_MILLIS)! .build();

Deadline

Page 67: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Creating an endpoint

• System calls the onStartJob() of your service!!

System

Service !!!!!onStartJob()

Page 68: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Creating an endpoint

• System calls the onStartJob() of your service!!

System

Service !!!!!onStartJob() { }

Page 69: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Creating an endpoint

• System calls the onStartJob() of your service!• Perform logic!

System

Service !!!!!onStartJob() { … }

Page 70: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Creating an endpoint

• System calls the onStartJob() of your service!• Perform logic!• Call jobFinished() when job is complete

System

Service !!!!!onStartJob() { … jobFinished(); }

Page 71: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Creating an endpoint

• System calls the onStartJob() of your service!• Perform logic!• Call jobFinished() when job is complete

System

Service !!!!!onStartJob() { … jobFinished(); }

Page 72: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Criteria has changed and not valid

System

Service !!!!!onStartJob()

Page 73: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Criteria has changed and not valid

• System calls the onStopJob()!!

System

Service !!!!!onStartJob()

onStopJob()

Page 74: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Criteria has changed and not valid

• System calls the onStopJob()!!

System

Service !!!!!onStartJob()

onStopJob()

Page 75: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Criteria has changed and not valid

• System calls the onStopJob()!!

System

Service !!!!!onStopJob() { !}

Page 76: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Criteria has changed and not valid

• System calls the onStopJob()!• Perform logic!

System

Service !!!!!onStopJob() { … !}

Page 77: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Criteria has changed and not valid

• System calls the onStopJob()!• Perform logic!• Call jobFinished() when job is complete

System

Service !!!!!onStopJob() { … jobFinished(); }

Page 78: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Criteria has changed and not valid

• System calls the onStopJob()!• Perform logic!• Call jobFinished() when job is complete

System

Service !!!!!onStopJob() { … jobFinished(); }

Page 79: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Pokedex Performance

Before

After

Page 80: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Battery Historian

http://github.com/google/battery-historian

Page 81: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

What just happened

• Changed structure of app!• New IDE!• RecyclerView, CardView!

• Applied colour!• Themes!• Custom colour palettes!

• Improved performance!• JobScheduler!• Battery Historian

Page 82: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Where to from here?

• Download latest Android Studio with Android L-Preview API!• Read the Google docs on Material and Android L-Preview!• Start coding!!!

Page 83: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Final thoughts…

Page 84: The Android winds of change - YOW! Conferences · RecyclerView in action protected void onCreate(Bundle savedInstanceState) ...

Questions?

www.outware.com.au !

OMPodcast