SlideShare ist ein Scribd-Unternehmen logo
1 von 50
Downloaden Sie, um offline zu lesen
Alex Yanchenko @ de.droidcon.com/2014
DroidParts Explained
●
SQL operations.
●
JSON (de)serialization.
●
HTTP interactions.
●
Loading, caching, displaying images.
●
Performing work in background.
●
Logging.
●
Dependency management.
●
Publish/subscribe (aka Event Bus).
●
Misc repeating tasks.
Common Tasks
Existing Solutions
Cursor query(boolean distinct, String table, String[]
columns, String selection, String[]
selectionArgs, String groupBy, String having,
String orderBy, String limit);
static final String TAG = InEvery.class.getSimpleName();
Log.wtf(TAG, "Y TAG?!");
Picasso.with(context).load(url).placeholder(R.drawable.ph)
.error(R.drawable.err).into(imageView);
Repetetive code:
Not using a builder when should:
Using a builder when shouldn't:
(Fluent kills inheritance)
Existing Solutions
Gson gson = new GsonBuilder().excludeFieldsWithModifiers(
Modifier.STATIC).create();
// By default, if you mark a field as transient, it will be
excluded.
The @DatabaseField annotation can have the following fields:
(27 ot them)
Entity user = schema.addEntity("User");
user.addIdProperty();
user.addStringProperty("name");
user.implementsSerializable();
// Then generate .java files & paste to your project.
A mess to maintain:
Abusing built-in language features:
Many features remain unused on mobile:
Existing Solutions
<com.android.volley.toolbox.NetworkImageView
android:id="@+id/pic" />
NetworkImageView pic = (NetworkImageView)view
.findViewById(R.id.pic);
pic.setImageUrl("http://example.com/pic.png",
mImageLoader); // OMG
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://example.com/timeline.json", new
JsonHttpResponseHandler() {
@Override
public void onSuccess(JSONArray response) {
System.out.println(
"Keep calm & process JSON on the UI thread.");
}
});
Ignoring separation of concerns #2:
Ignoring separation of concerns:
Existing Solutions
Coded past “Ballmer Peak”:
@Headers({
"Accept: application/vnd.github.v3.full+json",
"User-Agent: Retrofit-Sample-App"
})
@GET("/group/{id}/users")
List<User> groupList(@Path("id") int groupId,
@QueryMap Map<String, String> options);
©xkcd
●
Help handle most common tasks?
●
Uniform API?
●
Simple to make easy things easy?
●
Flexible to make hard things possible?
●
Won't reinvent Java, OO friendly?
●
Like Django, but for Android?
What If?
Yes.
What If?
●
Dependency Inection.
●
EventBus.
●
JSON (de)serialization.
●
Object-Relational Mapping.
●
AsyncTask, IntentService.
●
RESTClient.
●
ImageFetcher.
●
Logger.
●
Misc.
DroidParts Parts
250kB, 8kLOC (v.2.0.4)
App Blocks
HTTP/REST JSON SQL/ORM
IntentService
Activity
Fragment
View
AsyncTask
EventBus
Dependency
Injection
AndroidManifest.xml:
DI Setup
<meta-data
android:name="droidparts_dependency_provider"
android:value=".DependencyProvider" />
public class DependencyProvider extends
AbstractDependencyProvider {
public DependencyProvider(Context ctx) {
super(ctx);
}
}
DependencyProvider.java:
DependencyProvider
private final DBOpenHelper dbOpenHelper;
private PrefsManager prefsManager;
public DependencyProvider(Context ctx) {
super(ctx);
dbOpenHelper = new DBOpenHelper(ctx);
}
@Override
public AbstractDBOpenHelper getDBOpenHelper() {
return dbOpenHelper;
}
public PrefsManager getPrefsManager(Context ctx) {
if (prefsManager == null) {
prefsManager = new PrefsManager(ctx);
}
return prefsManager;
}
public DialogFactory getDialogFactory(Context ctx) {
return new DialogFactory(ctx);
}
Injection Annotations
@InjectDependency - from DependencyProvider
@InjectParentActivity - in a Fragment
@InjectView(int id, boolean click) - from layout
@InjectFragment(int id) - in an Activity
@InjectResource(int value) - strings, images...
@InjectSystemService - TelephonyManager, ...
@InjectBundleExtra(String key, boolean optional)
- from Intent in an Activity
or from args in a Fragment
Injection in an Activity
class MyActivity extends Activity implements OnClickListener {
@InjectSystemService
private LayoutInflater layoutInflater;
@InjectDependency
private DialogFactory dialogFactory;
@InjectView(id = R.id.button_add, click = true)
private Button addButton;
@Override
public void onPreInject() {
setContentView(R.layout.activity_my);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // <-- Injection
}
@Override
public void onClick(View v) {
if (v == addButton) { // TODO }
}
}
Base Activities
class MyActivity extends Activity {
@Override
public void onPreInject() {
setContentView(R.layout.activity_my);
}
}
package org.droidparts.activity;
class Activity extends android.app.Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
onPreInject();
Injector.inject(this); // <-- Magic
}
}
App Activity:
DroidParts Activity:
Base Activities & Fragments
DroidParts:
●
3.0+ with ActionBar features
●
Pre-3.0, no ActionBar
(.legacy.*)
DroidParts Support:
●
Pre-3.0 with Android Support Library
(.support.v4.*)
●
Pre-3.0 with ActionBarSherlock
(.sherlock.*)
●
Pre-3.0 with Android Support Library ActionBar
(.support.v7.*)
Base Activities & Fragments
No “DroidParts” or “DP” prefix.
Nice features:
→
SingleFragmentActivity
TabbedFragmentActivity
Activity Factory Methods
class PostListActivity extends Activity {
private static final String EXTRA_POSTS = "posts";
public static Intent getIntent(Context ctx,
ArrayList<Post> posts) {
Intent intent = new Intent(ctx, MyActivity.class);
intent.putExtra(EXTRA_POSTS, posts);
return intent;
}
@InjectBundleExtra(key = EXTRA_POSTS)
private ArrayList<Post> posts;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// TODO display posts.
}
}
Fragment Listener
class PostListActivity extends Activity
implements PostListFragment.Listener {
@InjectFragment
private PostListFragment fragment;
@Override
public void onPreInject() {
setContentView(R.layout.layout_with_fragments);
}
}
class PostListFragment extends ListFragment {
public interface Listener {
void doShowImageDetail(int position);
}
@InjectParentActivity
private Listener listener;
}
EventBus
(aka MessageBus)
●
Message: Name + optional payload Object.
(not a custom class)
●
Sent from any thread, delivered on the UI thread.
EventBus
interface EventReceiver<T> {
void onEvent(String name, T data);
}
EventBus.postEvent(String name)
// or
EventBus.postEventSticky(String name, Object data)
Send:
Receive:
EventBus.registerReceiver(EventReceiver<T> receiver,
String... eventNames)
// TODO Remember to unregister.
EventBus
@ReceiveEvents(name = { "MESSAGE_SENT", "MESSAGE_RECEIVED" })
private void onMessageEvent(String eventName) {
// TODO process 2 types of events without data
}
@ReceiveEvents
private void onAnyEvent(String eventName, Object eventData) {
// TODO process any event with optional data
}
EventBus.postEvent(String name)
// or
EventBus.postEventSticky(String name, Object data)
Send:
Receive in an injected class:
Data Layer
JSON ORM
IntentService AsyncTask
JSON, ORM
// JSON
class JSONSerializer<ModelType extends Model> {}
// ORM
class EntityManager<EntityType extends Entity> {}
// JSON
class Model implements Serializable {}
// ORM
class Entity extends Model {
@Column(name = "_id")
public long id;
}
Base Model Classes:
Managers:
JSON
@Key(Sting name, boolean optional)
Using org.json.* under the hood.
class JSONSerializer<ModelType extends Model> {
JSONObject serialize(ModelType item)
JSONArray serialize(Collection<ModelType> items)
ModelType deserialize(JSONObject obj)
ArrayList<ModelType> deserialize(JSONArray arr)
}
Annotation:
Manager:
JSON
{
"author": "Alex"
"address": "http://droidparts.org",
"posts": [{
"published": 1398970584375,
"title": "Title",
}],
}
class Blog extends Model {
@Key
public String author;
@Key(name="address")
public Uri uri;
@Key
public Post[] posts;
}
class Post extends Model {
@Key
public Date published;
@Key(name="title", optional=false)
public String title;
@Key(optional = true)
public String text = "";
}
JSON
{
"sub_obj": {
"str": "val"
}
}
@Key(name = "sub_obj" + Key.SUB + "str")
String str;
@Override
public Blog deserialize(JSONObject obj) throws JSONException {
Blog blog = super.deserialize(obj);
for (Post post : blog.posts) {
post.blog = blog;
}
return blog;
}
Override serialize()/deserialize() for tweaking:
Accessing nested object's property:
ORM
@Table(name = "posts")
public class Post extends Entity {
@Column
public Date published;
@Column(unique = true)
public String title;
@Column(nullable = true)
public String text = "";
@Column(eager = true)
public Blog blog;
}
@Table(String name)
@Column(String name, boolean nullable, boolean unique,
boolean eager)
Annotations:
Class example:
ORM
class Blog extends Entity {
List<Post> getPosts() {
EntityManager<Post> em = new EntityManager<Post>(
Post.class,
Injector.getApplicationContext());
Select<Post> select = em.select().where("blog_id",
Is.EQUAL, this.id);
return em.readAll(select);
}
}
Reading one-to-many:
EntityManager: C_UD
class Post extends Entity {}
EntityManager<Post> em =
new EntityManager<Post>(Post.class, ctx);
// Usually subclass & add helper methods.
Post post = new Post();
em.create(post);
assert(post.id != 0);
em.update(post);
em.createOrUpdate(post);
int postsDeleted = em.delete()
.where("year", Is.LESS, 2013)
.execute();
EntityManager: _R__
EntityManager<Post> em;
// 1
Select<Post> select = em.select().columns("_id", "name").
where("blog_id", Is.EQUAL, 10);
// 2
Where haveCoordinaltes = new Where("latitude", Is.NOT_EQUAL,
0).or("longitude", Is.NOT_EQUAL, 0);
em.select().where("country", Is.EQUAL, "us").where(
haveCoordinates);
// 3
Cursor cursor = em.select().where("author", Is.LIKE, "%%alex%%").
execute();
Select:
DB Contract
interface DB {
interface Table {
}
interface Column {
String ID = BaseColumns._ID;
}
}
@Table(name = DB.Table.BLOGS)
class Blog extends Entity {
@Column(name = DB.Column.NAME, unique = true)
String name;
}
import static org.exapmpe.app.DB.Column.*;
em.select().columns(ID, NAME).where(BLOG_ID, Is.EQUAL, 10);
DBOpenHelper
package org.droidparts.persist.sql;
class AbstractDBOpenHelper extends SQLiteOpenHelper { }
class DBOpenHelper extends AbstractDBOpenHelper {
@Override
protected void onCreateTables(SQLiteDatabase db) {
createTables(db, Blog.class, Post.class);
createIndex(db, "blogs", false, "title");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion,
int newVersion) {
addMissingColumns(db, Blog.class, Post.class)
}
}
EntityCursorAdapter
class PostListAdapter extends EntityCursorAdapter<Post> {
PostListAdapter(Context ctx, Select<Post> select) {
super(ctx, Post.class, select);
}
@Override
void bindView(Context context, View view, Post item) {
//TODO
}
}
Select object:
●
Has type information.
●
Can read an instance.
●
Wraps a Cursor.
●
Perfect data source for an Adapter.
ViewHolder
class ViewHolder {
public ViewHolder(View view) {
Injector.inject(view, this);
}
}
View view = layoutInflater.inflate(android.R.layout.
simple_list_item_1);
Text1Holder holder = new Text1Holder(view);
view.setTag(holder);
holder.text1.setText("Text 1");
class Text1Holder extends ViewHolder {
@InjectView(id = android.R.id.text1)
public TextView text1;
public Text1Holder(View view) {
super(view);
}
}
JSON, ORM
Supported types:
●
Primitives, wrapper classes.
●
Enums
●
JSONObject, JSONArray
●
Uri
●
UUID
●
Drawables
●
Models (JSON only), Entities
●
Arrays & collections
JSON, ORM
public class MyClassConverter extends Converter<MyClass> {
@Override
public boolean canHandle(Class<?> cls) { // TODO }
@Override
public String getDBColumnType() { // TODO }
@Override
public <V> MyClass readFromJSON(Class<MyClass> valType,
Class<V> componentType, JSONObject obj,
String key) throws JSONException { // TODO }
@Override
public <V> void putToContentValues(Class<MyClass> valueType,
Class<V> componentType, ContentValues cv,
String key, MyClass val) { // TODO }
// ...
}
ConverterRegistry.registerConverter(new MyClassConverter());
Adding new type support:
Background Work
AsyncTask:
●
Ad-hoc tasks, based on user input.
●
Important if succeeded.
●
Independent, non-cancellable.
●
Submitting a post.
IntentService:
●
Regular tasks, scheduled.
●
Not important if succeeded.
●
Sequential, cancellable.
●
Querying for new comments.
AsyncTask
class AsyncTask<Params, Progress, Result> extends
android.os.AsyncTask<...> {
abstract Result onExecute(Params... params) throws
Exception;
}
interface AsyncTaskResultListener<Result> {
void onAsyncTaskSuccess(Result result);
void onAsyncTaskFailure(Exception e);
}
AsyncTaskListener:
AsyncTask:
SimpleAsyncTask:
class SimpleAsyncTask<Result> extends
AsyncTask<Void, Integer, Result> {
abstract Result onExecute() throws Exception;
}
IntentService
abstract Bundle onExecute(String action, Bundle data)
throws Exception;
static Intent getIntent(Context ctx, Class<? extends
IntentService> cls, String action)
static Intent getIntent(Context ctx, Class<? extends
IntentService> cls, String action,
ResultReceiver resultReceiver)
public static final int RESULT_SUCCESS = Activity.RESULT_OK;
public static final int RESULT_FAILURE = Activity.
RESULT_CANCELED;
//
public static final String EXTRA_ACTION = "__action__";
public static final String EXTRA_EXCEPTION = "__exception__";
void removePendingIntents()
class IntentService extends android.app.IntentService {}
Networking Layer
RESTClient
ImageFetcher
RESTClient
●
GET, PUT, POST, DELETE
●
Uses gzip|deflate compression.
●
Supports in and out headers.
●
Transparent cookies support.
●
Http basic auth.
●
ETag & If-Modified-Since support.
●
Getting response as String or InputStream.
●
POST multipart file.
●
HttpURLConnection, Apache HTTP Client,
OkHttp workers.
RestClient
RESTClient(Context ctx)
RESTClient(Context ctx, String userAgent)
RESTClient(Context ctx, HTTPWorker worker)
RESTClient client = new RESTClient(ctx);
client.authenticateBasic("user", "pass");
client.setHeader("X-Header", "Val");
try {
HTTPResponse resp = client.get("http://example.
com/endpoint");
client.post("http://example.com/endpoint", "text/plain",
"txt");
} catch (HTTPException e) { // TODO }
class HTTPResponse {
public int code;
public Map<String, List<String>> headers;
public String body;
// or
public HTTPInputStream inputStream;
}
RestClient2
try {
RESTClient2 client = new RESTClient2(ctx);
JSONObject obj = client.getJSONObject("http://example.
com/endpoint");
JSONArray arr;
client.put("http://example.com/endpoint", arr);
} catch (HTTPException e) { // TODO }
Adds JSON support.
class HTTPException extends Exception {
public HTTPException(int respCode, String respBody) {
super(respBody);
this.respCode = respCode;
}
public int getResponseCode() {
return respCode;
}
}
Data + Network Layers
JSON ORM
IntentService AsyncTask
RESTClient
ImageFetcher
class ImageFetcher {
ImageFetcher(Context ctx) {
this(ctx,
new BackgroundThreadExecutor(2, "ImageFetcher-Fetch"),
new RESTClient(ctx),
BitmapMemoryCache.getDefaultInstance(ctx),
BitmapDiskCache.getDefaultInstance(ctx));
}
}
void attachImage(String imgUrl, ImageView imageView)
// ...
void attachImage(String imgUrl,
ImageView imageView,
ImageReshaper reshaper,
int crossFadeMillis,
ImageFetchListener listener,
Bitmap inBitmap)
ImageFetcher
interface ImageReshaper {
String getCacheId();
Pair<CompressFormat, Integer> getCacheFormat(String
mimeType);
Bitmap.Config getBitmapConfig();
int getImageWidthHint();
int getImageHeightHint();
Bitmap reshape(Bitmap bm);
}
abstract class AbstractImageReshaper implements ImageReshaper {
// TODO Check it out.
}
ImageFetcher
interface ImageFetchListener {
void onFetchAdded(ImageView imageView, String imgUrl);
void onFetchProgressChanged(ImageView imageView, String
imgUrl,
int kBTotal, int kBReceived);
void onFetchFailed(ImageView imageView, String imgUrl,
Exception e);
void onFetchCompleted(ImageView imageView, String imgUrl,
Bitmap bm);
}
L(ogger)
AndroidManifest.xml:
<meta-data
android:name="droidparts_log_level"
android:value="warn" />
Object anyObj;
L.w(anyObj);
long time = System.currentTimeMillis() - start;
L.wtf("Took %dms.", time);
DependencyProvider.<init>():39: Took 10ms.
DependencyProvider: Took 10ms.
Development mode:
Signed app:
See in action in
DroidPartsGram
droidparts-samples/
DroidPartsGram

Weitere ähnliche Inhalte

Was ist angesagt?

Managing parallelism using coroutines
Managing parallelism using coroutinesManaging parallelism using coroutines
Managing parallelism using coroutinesFabio Collini
 
Redux for ReactJS Programmers
Redux for ReactJS ProgrammersRedux for ReactJS Programmers
Redux for ReactJS ProgrammersDavid Rodenas
 
안드로이드 데이터 바인딩
안드로이드 데이터 바인딩안드로이드 데이터 바인딩
안드로이드 데이터 바인딩GDG Korea
 
Basic Tutorial of React for Programmers
Basic Tutorial of React for ProgrammersBasic Tutorial of React for Programmers
Basic Tutorial of React for ProgrammersDavid Rodenas
 
Testing Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJavaTesting Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJavaFabio Collini
 
Unit testing without Robolectric, Droidcon Berlin 2016
Unit testing without Robolectric, Droidcon Berlin 2016Unit testing without Robolectric, Droidcon Berlin 2016
Unit testing without Robolectric, Droidcon Berlin 2016Danny Preussler
 
Daggerate your code - Write your own annotation processor
Daggerate your code - Write your own annotation processorDaggerate your code - Write your own annotation processor
Daggerate your code - Write your own annotation processorBartosz Kosarzycki
 
Kotlin Delegates in practice - Kotlin community conf
Kotlin Delegates in practice - Kotlin community confKotlin Delegates in practice - Kotlin community conf
Kotlin Delegates in practice - Kotlin community confFabio Collini
 
Reactive, component 그리고 angular2
Reactive, component 그리고  angular2Reactive, component 그리고  angular2
Reactive, component 그리고 angular2Jeado Ko
 
Groovy Ecosystem - JFokus 2011 - Guillaume Laforge
Groovy Ecosystem - JFokus 2011 - Guillaume LaforgeGroovy Ecosystem - JFokus 2011 - Guillaume Laforge
Groovy Ecosystem - JFokus 2011 - Guillaume LaforgeGuillaume Laforge
 
How to build to do app using vue composition api and vuex 4 with typescript
How to build to do app using vue composition api and vuex 4 with typescriptHow to build to do app using vue composition api and vuex 4 with typescript
How to build to do app using vue composition api and vuex 4 with typescriptKaty Slemon
 
Anton Minashkin Dagger 2 light
Anton Minashkin Dagger 2 lightAnton Minashkin Dagger 2 light
Anton Minashkin Dagger 2 lightMichael Pustovit
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best PracticesYekmer Simsek
 
Kotlin delegates in practice - Kotlin Everywhere Stockholm
Kotlin delegates in practice - Kotlin Everywhere StockholmKotlin delegates in practice - Kotlin Everywhere Stockholm
Kotlin delegates in practice - Kotlin Everywhere StockholmFabio Collini
 
Angular 1 + es6
Angular 1 + es6Angular 1 + es6
Angular 1 + es6장현 한
 
A friend in need - A JS indeed
A friend in need - A JS indeedA friend in need - A JS indeed
A friend in need - A JS indeedYonatan Levin
 
Arquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com JetpackArquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com JetpackNelson Glauber Leal
 
50 new features of Java EE 7 in 50 minutes
50 new features of Java EE 7 in 50 minutes50 new features of Java EE 7 in 50 minutes
50 new features of Java EE 7 in 50 minutesAntonio Goncalves
 
Construire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleConstruire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleThierry Wasylczenko
 
Automated%20testing%20with%20Espresso2.x
Automated%20testing%20with%20Espresso2.xAutomated%20testing%20with%20Espresso2.x
Automated%20testing%20with%20Espresso2.xTatsuya Maki
 

Was ist angesagt? (20)

Managing parallelism using coroutines
Managing parallelism using coroutinesManaging parallelism using coroutines
Managing parallelism using coroutines
 
Redux for ReactJS Programmers
Redux for ReactJS ProgrammersRedux for ReactJS Programmers
Redux for ReactJS Programmers
 
안드로이드 데이터 바인딩
안드로이드 데이터 바인딩안드로이드 데이터 바인딩
안드로이드 데이터 바인딩
 
Basic Tutorial of React for Programmers
Basic Tutorial of React for ProgrammersBasic Tutorial of React for Programmers
Basic Tutorial of React for Programmers
 
Testing Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJavaTesting Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJava
 
Unit testing without Robolectric, Droidcon Berlin 2016
Unit testing without Robolectric, Droidcon Berlin 2016Unit testing without Robolectric, Droidcon Berlin 2016
Unit testing without Robolectric, Droidcon Berlin 2016
 
Daggerate your code - Write your own annotation processor
Daggerate your code - Write your own annotation processorDaggerate your code - Write your own annotation processor
Daggerate your code - Write your own annotation processor
 
Kotlin Delegates in practice - Kotlin community conf
Kotlin Delegates in practice - Kotlin community confKotlin Delegates in practice - Kotlin community conf
Kotlin Delegates in practice - Kotlin community conf
 
Reactive, component 그리고 angular2
Reactive, component 그리고  angular2Reactive, component 그리고  angular2
Reactive, component 그리고 angular2
 
Groovy Ecosystem - JFokus 2011 - Guillaume Laforge
Groovy Ecosystem - JFokus 2011 - Guillaume LaforgeGroovy Ecosystem - JFokus 2011 - Guillaume Laforge
Groovy Ecosystem - JFokus 2011 - Guillaume Laforge
 
How to build to do app using vue composition api and vuex 4 with typescript
How to build to do app using vue composition api and vuex 4 with typescriptHow to build to do app using vue composition api and vuex 4 with typescript
How to build to do app using vue composition api and vuex 4 with typescript
 
Anton Minashkin Dagger 2 light
Anton Minashkin Dagger 2 lightAnton Minashkin Dagger 2 light
Anton Minashkin Dagger 2 light
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best Practices
 
Kotlin delegates in practice - Kotlin Everywhere Stockholm
Kotlin delegates in practice - Kotlin Everywhere StockholmKotlin delegates in practice - Kotlin Everywhere Stockholm
Kotlin delegates in practice - Kotlin Everywhere Stockholm
 
Angular 1 + es6
Angular 1 + es6Angular 1 + es6
Angular 1 + es6
 
A friend in need - A JS indeed
A friend in need - A JS indeedA friend in need - A JS indeed
A friend in need - A JS indeed
 
Arquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com JetpackArquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com Jetpack
 
50 new features of Java EE 7 in 50 minutes
50 new features of Java EE 7 in 50 minutes50 new features of Java EE 7 in 50 minutes
50 new features of Java EE 7 in 50 minutes
 
Construire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleConstruire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradle
 
Automated%20testing%20with%20Espresso2.x
Automated%20testing%20with%20Espresso2.xAutomated%20testing%20with%20Espresso2.x
Automated%20testing%20with%20Espresso2.x
 

Ähnlich wie droidparts

Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android InfrastructureAlexey Buzdin
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android InfrastructureC.T.Co
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotationjavatwo2011
 
Oleksandr Tolstykh
Oleksandr TolstykhOleksandr Tolstykh
Oleksandr TolstykhCodeFest
 
Crossing platforms with JavaScript & React
Crossing platforms with JavaScript & React Crossing platforms with JavaScript & React
Crossing platforms with JavaScript & React Robert DeLuca
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on AndroidSven Haiges
 
Improving android experience for both users and developers
Improving android experience for both users and developersImproving android experience for both users and developers
Improving android experience for both users and developersPavel Lahoda
 
Droidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon Berlin
 
Thomas braun dependency-injection_with_robo_guice-presentation-final
Thomas braun dependency-injection_with_robo_guice-presentation-finalThomas braun dependency-injection_with_robo_guice-presentation-final
Thomas braun dependency-injection_with_robo_guice-presentation-finalDroidcon Berlin
 
Modern Android app library stack
Modern Android app library stackModern Android app library stack
Modern Android app library stackTomáš Kypta
 
Android Bootstrap
Android BootstrapAndroid Bootstrap
Android Bootstrapdonnfelker
 
Taming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, MacoscopeTaming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, MacoscopeMacoscope
 
Taming that client side mess with Backbone.js
Taming that client side mess with Backbone.jsTaming that client side mess with Backbone.js
Taming that client side mess with Backbone.jsJarod Ferguson
 
Jython: Python para la plataforma Java (JRSL 09)
Jython: Python para la plataforma Java (JRSL 09)Jython: Python para la plataforma Java (JRSL 09)
Jython: Python para la plataforma Java (JRSL 09)Leonardo Soto
 
Backbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserBackbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserHoward Lewis Ship
 

Ähnlich wie droidparts (20)

Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotation
 
Scala on Your Phone
Scala on Your PhoneScala on Your Phone
Scala on Your Phone
 
Oleksandr Tolstykh
Oleksandr TolstykhOleksandr Tolstykh
Oleksandr Tolstykh
 
Crossing platforms with JavaScript & React
Crossing platforms with JavaScript & React Crossing platforms with JavaScript & React
Crossing platforms with JavaScript & React
 
Javascript Design Patterns
Javascript Design PatternsJavascript Design Patterns
Javascript Design Patterns
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on Android
 
Improving android experience for both users and developers
Improving android experience for both users and developersImproving android experience for both users and developers
Improving android experience for both users and developers
 
Droidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon2013 android experience lahoda
Droidcon2013 android experience lahoda
 
Thomas braun dependency-injection_with_robo_guice-presentation-final
Thomas braun dependency-injection_with_robo_guice-presentation-finalThomas braun dependency-injection_with_robo_guice-presentation-final
Thomas braun dependency-injection_with_robo_guice-presentation-final
 
Griffon @ Svwjug
Griffon @ SvwjugGriffon @ Svwjug
Griffon @ Svwjug
 
Modern Android app library stack
Modern Android app library stackModern Android app library stack
Modern Android app library stack
 
Android Bootstrap
Android BootstrapAndroid Bootstrap
Android Bootstrap
 
Taming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, MacoscopeTaming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, Macoscope
 
Android 3
Android 3Android 3
Android 3
 
Android best practices
Android best practicesAndroid best practices
Android best practices
 
Taming that client side mess with Backbone.js
Taming that client side mess with Backbone.jsTaming that client side mess with Backbone.js
Taming that client side mess with Backbone.js
 
Jython: Python para la plataforma Java (JRSL 09)
Jython: Python para la plataforma Java (JRSL 09)Jython: Python para la plataforma Java (JRSL 09)
Jython: Python para la plataforma Java (JRSL 09)
 
Backbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserBackbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The Browser
 

Mehr von Droidcon Berlin

Droidcon de 2014 google cast
Droidcon de 2014   google castDroidcon de 2014   google cast
Droidcon de 2014 google castDroidcon Berlin
 
Android industrial mobility
Android industrial mobility Android industrial mobility
Android industrial mobility Droidcon Berlin
 
From sensor data_to_android_and_back
From sensor data_to_android_and_backFrom sensor data_to_android_and_back
From sensor data_to_android_and_backDroidcon Berlin
 
new_age_graphics_android_x86
new_age_graphics_android_x86new_age_graphics_android_x86
new_age_graphics_android_x86Droidcon Berlin
 
Testing and Building Android
Testing and Building AndroidTesting and Building Android
Testing and Building AndroidDroidcon Berlin
 
Matchinguu droidcon presentation
Matchinguu droidcon presentationMatchinguu droidcon presentation
Matchinguu droidcon presentationDroidcon Berlin
 
Cgm life sdk_droidcon_2014_v3
Cgm life sdk_droidcon_2014_v3Cgm life sdk_droidcon_2014_v3
Cgm life sdk_droidcon_2014_v3Droidcon Berlin
 
The artofcalabash peterkrauss
The artofcalabash peterkraussThe artofcalabash peterkrauss
The artofcalabash peterkraussDroidcon Berlin
 
Raesch, gries droidcon 2014
Raesch, gries   droidcon 2014Raesch, gries   droidcon 2014
Raesch, gries droidcon 2014Droidcon Berlin
 
Android open gl2_droidcon_2014
Android open gl2_droidcon_2014Android open gl2_droidcon_2014
Android open gl2_droidcon_2014Droidcon Berlin
 
20140508 quantified self droidcon
20140508 quantified self droidcon20140508 quantified self droidcon
20140508 quantified self droidconDroidcon Berlin
 
Tuning android for low ram devices
Tuning android for low ram devicesTuning android for low ram devices
Tuning android for low ram devicesDroidcon Berlin
 
Froyo to kit kat two years developing & maintaining deliradio
Froyo to kit kat   two years developing & maintaining deliradioFroyo to kit kat   two years developing & maintaining deliradio
Froyo to kit kat two years developing & maintaining deliradioDroidcon Berlin
 
Droidcon2013 security genes_trendmicro
Droidcon2013 security genes_trendmicroDroidcon2013 security genes_trendmicro
Droidcon2013 security genes_trendmicroDroidcon Berlin
 
Droidcon2013 commercialsuccess rannenberg
Droidcon2013 commercialsuccess rannenbergDroidcon2013 commercialsuccess rannenberg
Droidcon2013 commercialsuccess rannenbergDroidcon Berlin
 
Droidcon2013 bootstrap luedeke
Droidcon2013 bootstrap luedekeDroidcon2013 bootstrap luedeke
Droidcon2013 bootstrap luedekeDroidcon Berlin
 

Mehr von Droidcon Berlin (20)

Droidcon de 2014 google cast
Droidcon de 2014   google castDroidcon de 2014   google cast
Droidcon de 2014 google cast
 
crashing in style
crashing in stylecrashing in style
crashing in style
 
Raspberry Pi
Raspberry PiRaspberry Pi
Raspberry Pi
 
Android industrial mobility
Android industrial mobility Android industrial mobility
Android industrial mobility
 
Details matter in ux
Details matter in uxDetails matter in ux
Details matter in ux
 
From sensor data_to_android_and_back
From sensor data_to_android_and_backFrom sensor data_to_android_and_back
From sensor data_to_android_and_back
 
new_age_graphics_android_x86
new_age_graphics_android_x86new_age_graphics_android_x86
new_age_graphics_android_x86
 
5 tips of monetization
5 tips of monetization5 tips of monetization
5 tips of monetization
 
Testing and Building Android
Testing and Building AndroidTesting and Building Android
Testing and Building Android
 
Matchinguu droidcon presentation
Matchinguu droidcon presentationMatchinguu droidcon presentation
Matchinguu droidcon presentation
 
Cgm life sdk_droidcon_2014_v3
Cgm life sdk_droidcon_2014_v3Cgm life sdk_droidcon_2014_v3
Cgm life sdk_droidcon_2014_v3
 
The artofcalabash peterkrauss
The artofcalabash peterkraussThe artofcalabash peterkrauss
The artofcalabash peterkrauss
 
Raesch, gries droidcon 2014
Raesch, gries   droidcon 2014Raesch, gries   droidcon 2014
Raesch, gries droidcon 2014
 
Android open gl2_droidcon_2014
Android open gl2_droidcon_2014Android open gl2_droidcon_2014
Android open gl2_droidcon_2014
 
20140508 quantified self droidcon
20140508 quantified self droidcon20140508 quantified self droidcon
20140508 quantified self droidcon
 
Tuning android for low ram devices
Tuning android for low ram devicesTuning android for low ram devices
Tuning android for low ram devices
 
Froyo to kit kat two years developing & maintaining deliradio
Froyo to kit kat   two years developing & maintaining deliradioFroyo to kit kat   two years developing & maintaining deliradio
Froyo to kit kat two years developing & maintaining deliradio
 
Droidcon2013 security genes_trendmicro
Droidcon2013 security genes_trendmicroDroidcon2013 security genes_trendmicro
Droidcon2013 security genes_trendmicro
 
Droidcon2013 commercialsuccess rannenberg
Droidcon2013 commercialsuccess rannenbergDroidcon2013 commercialsuccess rannenberg
Droidcon2013 commercialsuccess rannenberg
 
Droidcon2013 bootstrap luedeke
Droidcon2013 bootstrap luedekeDroidcon2013 bootstrap luedeke
Droidcon2013 bootstrap luedeke
 

Kürzlich hochgeladen

GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdfChristopherTHyatt
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 

Kürzlich hochgeladen (20)

GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdf
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 

droidparts

  • 1. Alex Yanchenko @ de.droidcon.com/2014 DroidParts Explained
  • 2. ● SQL operations. ● JSON (de)serialization. ● HTTP interactions. ● Loading, caching, displaying images. ● Performing work in background. ● Logging. ● Dependency management. ● Publish/subscribe (aka Event Bus). ● Misc repeating tasks. Common Tasks
  • 3. Existing Solutions Cursor query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit); static final String TAG = InEvery.class.getSimpleName(); Log.wtf(TAG, "Y TAG?!"); Picasso.with(context).load(url).placeholder(R.drawable.ph) .error(R.drawable.err).into(imageView); Repetetive code: Not using a builder when should: Using a builder when shouldn't: (Fluent kills inheritance)
  • 4. Existing Solutions Gson gson = new GsonBuilder().excludeFieldsWithModifiers( Modifier.STATIC).create(); // By default, if you mark a field as transient, it will be excluded. The @DatabaseField annotation can have the following fields: (27 ot them) Entity user = schema.addEntity("User"); user.addIdProperty(); user.addStringProperty("name"); user.implementsSerializable(); // Then generate .java files & paste to your project. A mess to maintain: Abusing built-in language features: Many features remain unused on mobile:
  • 5. Existing Solutions <com.android.volley.toolbox.NetworkImageView android:id="@+id/pic" /> NetworkImageView pic = (NetworkImageView)view .findViewById(R.id.pic); pic.setImageUrl("http://example.com/pic.png", mImageLoader); // OMG AsyncHttpClient client = new AsyncHttpClient(); client.get("http://example.com/timeline.json", new JsonHttpResponseHandler() { @Override public void onSuccess(JSONArray response) { System.out.println( "Keep calm & process JSON on the UI thread."); } }); Ignoring separation of concerns #2: Ignoring separation of concerns:
  • 6. Existing Solutions Coded past “Ballmer Peak”: @Headers({ "Accept: application/vnd.github.v3.full+json", "User-Agent: Retrofit-Sample-App" }) @GET("/group/{id}/users") List<User> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options); ©xkcd
  • 7. ● Help handle most common tasks? ● Uniform API? ● Simple to make easy things easy? ● Flexible to make hard things possible? ● Won't reinvent Java, OO friendly? ● Like Django, but for Android? What If?
  • 9. ● Dependency Inection. ● EventBus. ● JSON (de)serialization. ● Object-Relational Mapping. ● AsyncTask, IntentService. ● RESTClient. ● ImageFetcher. ● Logger. ● Misc. DroidParts Parts 250kB, 8kLOC (v.2.0.4)
  • 10. App Blocks HTTP/REST JSON SQL/ORM IntentService Activity Fragment View AsyncTask EventBus Dependency Injection
  • 11. AndroidManifest.xml: DI Setup <meta-data android:name="droidparts_dependency_provider" android:value=".DependencyProvider" /> public class DependencyProvider extends AbstractDependencyProvider { public DependencyProvider(Context ctx) { super(ctx); } } DependencyProvider.java:
  • 12. DependencyProvider private final DBOpenHelper dbOpenHelper; private PrefsManager prefsManager; public DependencyProvider(Context ctx) { super(ctx); dbOpenHelper = new DBOpenHelper(ctx); } @Override public AbstractDBOpenHelper getDBOpenHelper() { return dbOpenHelper; } public PrefsManager getPrefsManager(Context ctx) { if (prefsManager == null) { prefsManager = new PrefsManager(ctx); } return prefsManager; } public DialogFactory getDialogFactory(Context ctx) { return new DialogFactory(ctx); }
  • 13. Injection Annotations @InjectDependency - from DependencyProvider @InjectParentActivity - in a Fragment @InjectView(int id, boolean click) - from layout @InjectFragment(int id) - in an Activity @InjectResource(int value) - strings, images... @InjectSystemService - TelephonyManager, ... @InjectBundleExtra(String key, boolean optional) - from Intent in an Activity or from args in a Fragment
  • 14. Injection in an Activity class MyActivity extends Activity implements OnClickListener { @InjectSystemService private LayoutInflater layoutInflater; @InjectDependency private DialogFactory dialogFactory; @InjectView(id = R.id.button_add, click = true) private Button addButton; @Override public void onPreInject() { setContentView(R.layout.activity_my); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // <-- Injection } @Override public void onClick(View v) { if (v == addButton) { // TODO } } }
  • 15. Base Activities class MyActivity extends Activity { @Override public void onPreInject() { setContentView(R.layout.activity_my); } } package org.droidparts.activity; class Activity extends android.app.Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); onPreInject(); Injector.inject(this); // <-- Magic } } App Activity: DroidParts Activity:
  • 16. Base Activities & Fragments DroidParts: ● 3.0+ with ActionBar features ● Pre-3.0, no ActionBar (.legacy.*) DroidParts Support: ● Pre-3.0 with Android Support Library (.support.v4.*) ● Pre-3.0 with ActionBarSherlock (.sherlock.*) ● Pre-3.0 with Android Support Library ActionBar (.support.v7.*)
  • 17. Base Activities & Fragments No “DroidParts” or “DP” prefix. Nice features: → SingleFragmentActivity TabbedFragmentActivity
  • 18. Activity Factory Methods class PostListActivity extends Activity { private static final String EXTRA_POSTS = "posts"; public static Intent getIntent(Context ctx, ArrayList<Post> posts) { Intent intent = new Intent(ctx, MyActivity.class); intent.putExtra(EXTRA_POSTS, posts); return intent; } @InjectBundleExtra(key = EXTRA_POSTS) private ArrayList<Post> posts; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // TODO display posts. } }
  • 19. Fragment Listener class PostListActivity extends Activity implements PostListFragment.Listener { @InjectFragment private PostListFragment fragment; @Override public void onPreInject() { setContentView(R.layout.layout_with_fragments); } } class PostListFragment extends ListFragment { public interface Listener { void doShowImageDetail(int position); } @InjectParentActivity private Listener listener; }
  • 20. EventBus (aka MessageBus) ● Message: Name + optional payload Object. (not a custom class) ● Sent from any thread, delivered on the UI thread.
  • 21. EventBus interface EventReceiver<T> { void onEvent(String name, T data); } EventBus.postEvent(String name) // or EventBus.postEventSticky(String name, Object data) Send: Receive: EventBus.registerReceiver(EventReceiver<T> receiver, String... eventNames) // TODO Remember to unregister.
  • 22. EventBus @ReceiveEvents(name = { "MESSAGE_SENT", "MESSAGE_RECEIVED" }) private void onMessageEvent(String eventName) { // TODO process 2 types of events without data } @ReceiveEvents private void onAnyEvent(String eventName, Object eventData) { // TODO process any event with optional data } EventBus.postEvent(String name) // or EventBus.postEventSticky(String name, Object data) Send: Receive in an injected class:
  • 24. JSON, ORM // JSON class JSONSerializer<ModelType extends Model> {} // ORM class EntityManager<EntityType extends Entity> {} // JSON class Model implements Serializable {} // ORM class Entity extends Model { @Column(name = "_id") public long id; } Base Model Classes: Managers:
  • 25. JSON @Key(Sting name, boolean optional) Using org.json.* under the hood. class JSONSerializer<ModelType extends Model> { JSONObject serialize(ModelType item) JSONArray serialize(Collection<ModelType> items) ModelType deserialize(JSONObject obj) ArrayList<ModelType> deserialize(JSONArray arr) } Annotation: Manager:
  • 26. JSON { "author": "Alex" "address": "http://droidparts.org", "posts": [{ "published": 1398970584375, "title": "Title", }], } class Blog extends Model { @Key public String author; @Key(name="address") public Uri uri; @Key public Post[] posts; } class Post extends Model { @Key public Date published; @Key(name="title", optional=false) public String title; @Key(optional = true) public String text = ""; }
  • 27. JSON { "sub_obj": { "str": "val" } } @Key(name = "sub_obj" + Key.SUB + "str") String str; @Override public Blog deserialize(JSONObject obj) throws JSONException { Blog blog = super.deserialize(obj); for (Post post : blog.posts) { post.blog = blog; } return blog; } Override serialize()/deserialize() for tweaking: Accessing nested object's property:
  • 28. ORM @Table(name = "posts") public class Post extends Entity { @Column public Date published; @Column(unique = true) public String title; @Column(nullable = true) public String text = ""; @Column(eager = true) public Blog blog; } @Table(String name) @Column(String name, boolean nullable, boolean unique, boolean eager) Annotations: Class example:
  • 29. ORM class Blog extends Entity { List<Post> getPosts() { EntityManager<Post> em = new EntityManager<Post>( Post.class, Injector.getApplicationContext()); Select<Post> select = em.select().where("blog_id", Is.EQUAL, this.id); return em.readAll(select); } } Reading one-to-many:
  • 30. EntityManager: C_UD class Post extends Entity {} EntityManager<Post> em = new EntityManager<Post>(Post.class, ctx); // Usually subclass & add helper methods. Post post = new Post(); em.create(post); assert(post.id != 0); em.update(post); em.createOrUpdate(post); int postsDeleted = em.delete() .where("year", Is.LESS, 2013) .execute();
  • 31. EntityManager: _R__ EntityManager<Post> em; // 1 Select<Post> select = em.select().columns("_id", "name"). where("blog_id", Is.EQUAL, 10); // 2 Where haveCoordinaltes = new Where("latitude", Is.NOT_EQUAL, 0).or("longitude", Is.NOT_EQUAL, 0); em.select().where("country", Is.EQUAL, "us").where( haveCoordinates); // 3 Cursor cursor = em.select().where("author", Is.LIKE, "%%alex%%"). execute(); Select:
  • 32. DB Contract interface DB { interface Table { } interface Column { String ID = BaseColumns._ID; } } @Table(name = DB.Table.BLOGS) class Blog extends Entity { @Column(name = DB.Column.NAME, unique = true) String name; } import static org.exapmpe.app.DB.Column.*; em.select().columns(ID, NAME).where(BLOG_ID, Is.EQUAL, 10);
  • 33. DBOpenHelper package org.droidparts.persist.sql; class AbstractDBOpenHelper extends SQLiteOpenHelper { } class DBOpenHelper extends AbstractDBOpenHelper { @Override protected void onCreateTables(SQLiteDatabase db) { createTables(db, Blog.class, Post.class); createIndex(db, "blogs", false, "title"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { addMissingColumns(db, Blog.class, Post.class) } }
  • 34. EntityCursorAdapter class PostListAdapter extends EntityCursorAdapter<Post> { PostListAdapter(Context ctx, Select<Post> select) { super(ctx, Post.class, select); } @Override void bindView(Context context, View view, Post item) { //TODO } } Select object: ● Has type information. ● Can read an instance. ● Wraps a Cursor. ● Perfect data source for an Adapter.
  • 35. ViewHolder class ViewHolder { public ViewHolder(View view) { Injector.inject(view, this); } } View view = layoutInflater.inflate(android.R.layout. simple_list_item_1); Text1Holder holder = new Text1Holder(view); view.setTag(holder); holder.text1.setText("Text 1"); class Text1Holder extends ViewHolder { @InjectView(id = android.R.id.text1) public TextView text1; public Text1Holder(View view) { super(view); } }
  • 36. JSON, ORM Supported types: ● Primitives, wrapper classes. ● Enums ● JSONObject, JSONArray ● Uri ● UUID ● Drawables ● Models (JSON only), Entities ● Arrays & collections
  • 37. JSON, ORM public class MyClassConverter extends Converter<MyClass> { @Override public boolean canHandle(Class<?> cls) { // TODO } @Override public String getDBColumnType() { // TODO } @Override public <V> MyClass readFromJSON(Class<MyClass> valType, Class<V> componentType, JSONObject obj, String key) throws JSONException { // TODO } @Override public <V> void putToContentValues(Class<MyClass> valueType, Class<V> componentType, ContentValues cv, String key, MyClass val) { // TODO } // ... } ConverterRegistry.registerConverter(new MyClassConverter()); Adding new type support:
  • 38. Background Work AsyncTask: ● Ad-hoc tasks, based on user input. ● Important if succeeded. ● Independent, non-cancellable. ● Submitting a post. IntentService: ● Regular tasks, scheduled. ● Not important if succeeded. ● Sequential, cancellable. ● Querying for new comments.
  • 39. AsyncTask class AsyncTask<Params, Progress, Result> extends android.os.AsyncTask<...> { abstract Result onExecute(Params... params) throws Exception; } interface AsyncTaskResultListener<Result> { void onAsyncTaskSuccess(Result result); void onAsyncTaskFailure(Exception e); } AsyncTaskListener: AsyncTask: SimpleAsyncTask: class SimpleAsyncTask<Result> extends AsyncTask<Void, Integer, Result> { abstract Result onExecute() throws Exception; }
  • 40. IntentService abstract Bundle onExecute(String action, Bundle data) throws Exception; static Intent getIntent(Context ctx, Class<? extends IntentService> cls, String action) static Intent getIntent(Context ctx, Class<? extends IntentService> cls, String action, ResultReceiver resultReceiver) public static final int RESULT_SUCCESS = Activity.RESULT_OK; public static final int RESULT_FAILURE = Activity. RESULT_CANCELED; // public static final String EXTRA_ACTION = "__action__"; public static final String EXTRA_EXCEPTION = "__exception__"; void removePendingIntents() class IntentService extends android.app.IntentService {}
  • 42. RESTClient ● GET, PUT, POST, DELETE ● Uses gzip|deflate compression. ● Supports in and out headers. ● Transparent cookies support. ● Http basic auth. ● ETag & If-Modified-Since support. ● Getting response as String or InputStream. ● POST multipart file. ● HttpURLConnection, Apache HTTP Client, OkHttp workers.
  • 43. RestClient RESTClient(Context ctx) RESTClient(Context ctx, String userAgent) RESTClient(Context ctx, HTTPWorker worker) RESTClient client = new RESTClient(ctx); client.authenticateBasic("user", "pass"); client.setHeader("X-Header", "Val"); try { HTTPResponse resp = client.get("http://example. com/endpoint"); client.post("http://example.com/endpoint", "text/plain", "txt"); } catch (HTTPException e) { // TODO } class HTTPResponse { public int code; public Map<String, List<String>> headers; public String body; // or public HTTPInputStream inputStream; }
  • 44. RestClient2 try { RESTClient2 client = new RESTClient2(ctx); JSONObject obj = client.getJSONObject("http://example. com/endpoint"); JSONArray arr; client.put("http://example.com/endpoint", arr); } catch (HTTPException e) { // TODO } Adds JSON support. class HTTPException extends Exception { public HTTPException(int respCode, String respBody) { super(respBody); this.respCode = respCode; } public int getResponseCode() { return respCode; } }
  • 45. Data + Network Layers JSON ORM IntentService AsyncTask RESTClient
  • 46. ImageFetcher class ImageFetcher { ImageFetcher(Context ctx) { this(ctx, new BackgroundThreadExecutor(2, "ImageFetcher-Fetch"), new RESTClient(ctx), BitmapMemoryCache.getDefaultInstance(ctx), BitmapDiskCache.getDefaultInstance(ctx)); } } void attachImage(String imgUrl, ImageView imageView) // ... void attachImage(String imgUrl, ImageView imageView, ImageReshaper reshaper, int crossFadeMillis, ImageFetchListener listener, Bitmap inBitmap)
  • 47. ImageFetcher interface ImageReshaper { String getCacheId(); Pair<CompressFormat, Integer> getCacheFormat(String mimeType); Bitmap.Config getBitmapConfig(); int getImageWidthHint(); int getImageHeightHint(); Bitmap reshape(Bitmap bm); } abstract class AbstractImageReshaper implements ImageReshaper { // TODO Check it out. }
  • 48. ImageFetcher interface ImageFetchListener { void onFetchAdded(ImageView imageView, String imgUrl); void onFetchProgressChanged(ImageView imageView, String imgUrl, int kBTotal, int kBReceived); void onFetchFailed(ImageView imageView, String imgUrl, Exception e); void onFetchCompleted(ImageView imageView, String imgUrl, Bitmap bm); }
  • 49. L(ogger) AndroidManifest.xml: <meta-data android:name="droidparts_log_level" android:value="warn" /> Object anyObj; L.w(anyObj); long time = System.currentTimeMillis() - start; L.wtf("Took %dms.", time); DependencyProvider.<init>():39: Took 10ms. DependencyProvider: Took 10ms. Development mode: Signed app:
  • 50. See in action in DroidPartsGram droidparts-samples/ DroidPartsGram