ロード中…
テキスト

robust, mobile oriented

networking code

robust and simple

concurrency

Gradle is Groovy!

Apache HttpClient &

ConnectivityManager

AsyncTask

build scripts are code

High level abstractions

build.gradle

dependencies

extensibility

LocationManager

repositories {

mavenCentral()

mavenRepo urls: "http://my.repo.com"

flatDir dirs: "libs"

}

task releaseApk(dependsOn: assemble) << {

def proguardMappingFile = "$projectDir/..."

git("add", proguardMappingFile)

git("commit", "-m", "...")

if (project.hasProperty('copyTo')) {

copy {

from project.convention.plugins.android.apkPath

into copyTo

}

}

}

env = System.getenv()

dependsOnChildren()

apply from: ‘shared.gradle'

allprojects { apply plugin: 'java' }

task hello << { println ‘hello from Gradle‘ }

dependencies {

compile 'net.sf.opencsv:opencsv:2.3' {

exclude module: '...'

}

}

ViewPager,

SlidingDrawer

$gradle hello

$gradle release

Solutions

easier location detection

ready-to-use

standard widgets

Trajectory

...

reusable

components

Android support

Meet the gradle-android-plugin!

$gradle androidInstall

build.gradle

apply plugin: 'android'

$gradle assemble

:qype-app:androidProcessResources

:qype-app:compileJava

:qype-app:processResources UP-TO-DATE

:qype-app:classes

:qype-app:jar

:qype-app:androidPackage

:qype-app:assemble

$gradle andInstrTests

:qype-tests-instrumentation:androidInstrumentationTests

com.qype.radar.test.unit.activities.ActivityFeedActivityTest:..

com.qype.radar.test.unit.activities.AddFriendsActivityTest:.

com.qype.radar.test.unit.activities.AddPlaceActivityTest:.

com.qype.radar.test.unit.activities.BookmarksListActivityTest:..

com.qype.radar.test.unit.activities.ChangeLocationActivityTest:.

com.qype.radar.test.unit.activities.ContactRequestsActivityTest:.

com.qype.radar.test.unit.activities.CouponActivityTest:.

APK

. . . OK (66 tests)

@twoofour

dependency management

libs/ anyone?

think less about artifact retrieval

and version conflicts

Roboguice

easy syntax

It's Google Guice for robots

@Inject it!

Use events as runtime mixins

class LocationHandling {

public void onResume(@Observes OnResumeEvent event) {

// ... register a location listener here

}

public void onPause(@Observes OnPauseEvent event) {

// ... unregister a location listener here

}

}

public class Bar extends RoboActivity {

@Inject private Application application;

@InjectView(R.id.my_button) private Button button;

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

button.setOnClickListener(new OnClickListener() {

public void onClick(...) {

Intent intent = new Intent(Bar.this, Baz.class);

intent.putExtra("extra", "Hello there!");

startActivity(intent);

}

)};

}

}

@InjectExtra

extensibility

public class Baz extends RoboActivity {

@InjectExtra(value = "extra")

private String message;

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

System.out.println(message);

}

}

public class LocationActivity extends RoboActivity {

@Inject

protected LocationHandling listener;

@Override

protected void onResume() {

super.onResume();

// custom onResume logic here

}

@Override

protected void onPause() {

// custom onPause logic here

super.onPause();

}

}

prints "Hello there!"

think less about how

to accomplish X

print to standard out!

dependency injection

& inversion of control

Android is almost exclusively

"pull", encourages Singletons

IoC frameworks can help in creating code that's easier to maintain and reuse

No re-invented wheels

Contemporary Java

build management

Roboguice &

Android Annotations

Provide solutions to common, reoccurring Android development problems

testable code

ignition-core

ignition-support

ignition-location

IgnitedAsyncTask

RemoteImageLoader

Location updates

What's wrong with AsyncTask?

what's not wrong with it?

Load images asynchronously from the Web.

No context access.

No exception handling.

Balancing recency and efficiency is tricky.

Layout XML

<ImageView android:id="@+id/image" ... />

DRY code

Activity

private static class SampleTask extends

IgnitedAsyncTask<IgnitedAsyncTaskActivity, Void, Void, Hunk> {

@Override

protected void onStart(IgnitedAsyncTaskActivity context) {

}

@Override

protected Hunk run(Void... params) throws Exception {

return retrieveHunkFromInterwebs();

}

@Override

protected void onSuccess(IgnitedAsyncTaskActivity context, Hunk result) {

context.updateViews(result);

}

@Override

protected void onError(IgnitedAsyncTaskActivity context, Exception error) {

super.onError(context, error);

}

}

ImageView imageView = (ImageView) findViewById(R.id.image);

RemoteImageLoader imageLoader = new RemoteImageLoader(this, false);

It's cached!

"A Deep Dive Into Location"

by Reto Meier

For view/URL

imageLoder.loadImage(url, view)

  • Make location available as quickly as possible

  • Refine to more accurate fixes as they drop in

  • Leverage synergies with other location-aware apps

  • Disable location listeners while application is in background

use connect() and disconnect()

to not leak Context!

(bad language removed.)

boiler plate

code designed for testability implies code that's easy to replace

IgnitedHttp

Widgets & Adapters

@IgnitedLocationActivity

Kick-starting Android

application development

Help us create an extensive widget library!

Enables easier and more robust HTTP.

So as to bring common UX patterns together.

Eliminate boiler plate with annotations and AOP

Simplified HTTP

EndlessListAdapter

RemoteImageView

registers broadcast receiver,

creates thread-safe HTTP(S) client

enables response caching

class MyListAdapter extends EndlessListAdapter<Hunk> {

protected View doGetView(int position, ...) {

...

}

}

<com.github.ignition.core.widgets.RemoteImageView

xmlns:ignition="http://github.com/ignition/schema"

android:layout_width="..." android:layout_height="..."

ignition:imageUrl="http://..."

ignition:autoLoad="true"

ignition:progressDrawable="@drawable/progress_spinner" />

It's cached!

AOP Magic

declare expected error code

IgnitedHttp http = new IgnitedHttp(this, true);

IgnitedHttpResponse resp = http.get("http://example.com")

.expecting( 401 ).retries( 3 ).send()

if (resp.getStatusCode() == 401) {

// e.g. trigger login screen

}

System.out.println(resp.getResponseBodyAsString());

retry request

adapter.setIsLoadingData(true)

always up-to-date

response helpers

@IgnitedLocationActivity(useGps = true, ...)

public class LocationActivity extends Activity {

@IgnitedLocation

private Location currentLocation;

@Override protected void onResume() { ... }

@Override protected void onPause() { ... }

@Override

public void onIgnitedLocationChanged(Location newLocation) {

// e.g. refresh data

}

}

findViewById anyone?

getting rid of boilerplate and duplicated code saves maintenance time

Accomplish how?

"build scripts are code"

Android Annotations

dynamic languages

and DSLs

Gradle

task buildApplication << {

println "building..."

}

SBT

task buildApplication {

println("building...")

}

code management

plugin support and infrastructure

Compile time injection of Android objects

easy plugin authoring and distribution

Threading

Gradle

@EActivity

class MyPlugin implements Plugin<Project> {

def apply(project) {

// define custom tasks

}

}

apply plugin: 'MyPlugin'

SBT

sbtPlugin := true

object MyPlugin extends Plugin {

// define custom tasks

}

addSbtPlugin("org.example" % "my-plugin" % "1.0")

@EActivity(R.layout.main)

public class AnnotatedActivity extends Activity {

@StringRes(R.string.hello) String hello;

@ViewById Button myButton;

@Click void myButton(View theButton) { ... }

@AfterViews setupViews() { ... }

}

@EActivity

public class MyActivity extends Activity {

@Background void doInBackground() {

publishProgress(0);

// ...

publishProgress(10);

// ...

publishProgress(100);

}

@UiThread void publishProgress(int progress) {

// update progress views

}

}

AndroidManifest.xml

<activity android:name=".AnnotatedActivity_" />

Java code

Intent intent = new Intent(this, AnnotatedActivity_.class)

startActivity(intent);

dependency management

leverage Apache

Ivy or Maven

Gradle

repositories { ... }

dependencies { ... }

Droid-Fu /

ignition

SBT

resolvers += <name> at <location>

libraryDependencies +=

<group> % <name> % <version>

object and life-cycle management

@mg_england

Reflection and Introspection, Annotations

but ain't that slow??

not necessarily.

@mod3rn0

  • Leverage annotation processing (apt) to do things at compile time

  • Lazy evaluation vs. confinement to "expected" point

be moderate!

class MyActivity {

@ManageMe

private Hunk hunk;

}

@g0nzaga

Accomplish how?

@didigoose

@twoofour

unobtrusiveness, DRYness, and cross-cutting concerns

Avoid inheritance,

mix-in code via AOP

but ain't that slow??

not necessarily.

  • Code is woven in at compile time.

  • The dexer will assume it's code you've written yourself.

aspect ActivityTracker {

pointcut created(Activity a) :

this(a) &&

execution(* onCreate(..))

}

Goal

Community to the rescue!

The Android development community has been

busy, and has put forth solutions to common

Android development problems:

build management

code management

reusable components