robust, mobile oriented
networking code
robust and simple
concurrency
Apache HttpClient &
ConnectivityManager
AsyncTask
build scripts are code
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
easier location detection
ready-to-use
standard widgets
...
Meet the gradle-android-plugin!
apply plugin: 'android'
:qype-app:androidProcessResources
:qype-app:compileJava
:qype-app:processResources UP-TO-DATE
:qype-app:classes
:qype-app:jar
:qype-app:androidPackage
:qype-app:assemble
: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:.
. . . OK (66 tests)
dependency management
libs/ anyone?
think less about artifact retrieval
and version conflicts
It's Google Guice for robots
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);
}
)};
}
}
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();
}
}
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
Provide solutions to common, reoccurring Android development problems
testable code
what's not wrong with it?
Load images asynchronously from the Web.
No context access.
No exception handling.
Balancing recency and efficiency is tricky.
<ImageView android:id="@+id/image" ... />
DRY code
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);
imageLoder.loadImage(url, view)
(bad language removed.)
boiler plate
code designed for testability implies code that's easy to replace
Enables easier and more robust HTTP.
So as to bring common UX patterns together.
Eliminate boiler plate with annotations and AOP
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" />
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());
adapter.setIsLoadingData(true)
@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
"build scripts are code"
dynamic languages
and DSLs
task buildApplication << {
println "building..."
}
task buildApplication {
println("building...")
}
plugin support and infrastructure
Compile time injection of Android objects
easy plugin authoring and distribution
class MyPlugin implements Plugin<Project> {
def apply(project) {
// define custom tasks
}
}
sbtPlugin := true
object MyPlugin extends Plugin {
// define custom tasks
}
@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
}
}
<activity android:name=".AnnotatedActivity_" />
Intent intent = new Intent(this, AnnotatedActivity_.class)
startActivity(intent);
dependency management
leverage Apache
Ivy or Maven
repositories { ... }
dependencies { ... }
resolvers += <name> at <location>
libraryDependencies +=
<group> % <name> % <version>
object and life-cycle management
Reflection and Introspection, Annotations
but ain't that slow??
not necessarily.
class MyActivity {
@ManageMe
private Hunk hunk;
}
unobtrusiveness, DRYness, and cross-cutting concerns
Avoid inheritance,
mix-in code via AOP
but ain't that slow??
not necessarily.
aspect ActivityTracker {
pointcut created(Activity a) :
this(a) &&
execution(* onCreate(..))
}
build management
code management
reusable components