Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Day1 Keynote in DroidKaigi 2016
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Daichi Furiya (Wasabeef)
February 17, 2016
Programming
6
12k
Day1 Keynote in DroidKaigi 2016
Day1 Keynote in DroidKaigi 2016
Daichi Furiya (Wasabeef)
February 17, 2016
Tweet
Share
More Decks by Daichi Furiya (Wasabeef)
See All by Daichi Furiya (Wasabeef)
DevFest Tokyo 2025 - Flutter のアプリアーキテクチャ現在地点
wasabeef
6
2.6k
About Flutter Architecture
wasabeef
1
300
2023 Flutter/Dart Summary
wasabeef
0
120
I/O Extended 2023 - Dart と Flutter の新機能
wasabeef
0
220
I/O Extended 2023 - Flutter 活用事例
wasabeef
10
3.1k
What it Takes to be a Flutter Developer
wasabeef
0
230
FlutterKaigi 2022 Keynote
wasabeef
1
670
Flutter Hooks を使ったアプリ開発 / App Development with the Flutter Hooks
wasabeef
2
1.5k
Flutter 2021 の振り返りと今後のアプリ開発に向けて / Looking back on Flutter 2021 and for future app development.
wasabeef
4
2.2k
Other Decks in Programming
See All in Programming
20260228_JAWS_Beginner_Kansai
takuyay0ne
5
440
社内規程RAGの精度を73.3% → 100%に改善した話
oharu121
13
7.5k
ふつうの Rubyist、ちいさなデバイス、大きな一年
bash0c7
0
110
受け入れテスト駆動開発(ATDD)×AI駆動開発 AI時代のATDDの取り組み方を考える
kztakasaki
2
520
AHC061解説
shun_pi
0
310
エージェント開発初心者の僕がエージェントを作った話と今後やりたいこと
thasu0123
0
230
今更考える「単一責任原則」 / Thinking about the Single Responsibility Principle
tooppoo
3
1.4k
24時間止められないシステムを守る-医療ITにおけるランサムウェア対策の実際
koukimiura
2
180
Head of Engineeringが現場で回した生産性向上施策 2025→2026
gessy0129
0
210
CDIの誤解しがちな仕様とその対処TIPS
futokiyo
0
160
ご飯食べながらエージェントが開発できる。そう、Agentic Engineeringならね。
yokomachi
1
280
Premier Disciplin for Micro Frontends Multi Version/ Framework Scenarios @OOP 2026, Munic
manfredsteyer
PRO
0
200
Featured
See All Featured
The Mindset for Success: Future Career Progression
greggifford
PRO
0
270
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
122
21k
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
0
430
Building a Scalable Design System with Sketch
lauravandoore
463
34k
What the history of the web can teach us about the future of AI
inesmontani
PRO
1
450
Crafting Experiences
bethany
1
75
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
63
53k
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
2.4k
Deep Space Network (abreviated)
tonyrice
0
86
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
A designer walks into a library…
pauljervisheath
210
24k
KATA
mclloyd
PRO
35
15k
Transcript
OSSの動向を捉えた実装方針 wasabeef DroidKaigi 2016
About me Daichi Furiya wasabeef @wasabeef_jp CyberAgent, Inc.
OSSの動向を捉えた実装方針?
Research
GitHub/trending Android Weekly Android Arsenal Twitter Research
Introduction
Languages
Kotlin Java • RetroLambda • Lightweight-Stream-API • ThreeTen Android Languages
Kotlin by JetBrains
Kotlin 1.0 Java連携 …more Kotlin
RetroLambda by Esko Luontola
Lambda Method Reference RetroLambda view.setOnClickListener(v -> { finish(); }); view.setOnClickListener(this::something);
Lightweight-Stream-API by Victor Melnik
Stream API Lightweight-Stream-API Stream.of(lines) .map(str -> str.split(t)) .filter(arr -> arr.length
== 2) .map(arr -> new Word(arr[0], arr[1])) .collect(Collectors.toList());
Optional Lightweight-Stream-API Optional.ofNullable(getSupportActionBar()) .ifPresent(ab -> { ab.setDisplayHomeAsUpEnabled(true); ab.setHomeButtonEnabled(true); }); Optional.ofNullable(i.getStringExtra(EXTRA_URI))
.map(Uri::parse) .orElse(null);
ThreeTen Android by Jake Wharton
JSR-310 ThreeTen Android // Now LocalDateTime.now(); // 2016.2.18 10:30:40 LocalDateTime.of(2016,
2, 18, 10, 30, 40); // +1 truncated second LocalDateTime.now() .plusHours(1).truncatedTo(ChronoUnit.HOURS); // Epoch LocalDateTime.now() .toInstant(ZoneOffset.UTC).toEpochMilli();
Views
Support Library Android-ObservableScrollView Calligraphy florent37/ViewAnimator View
Support Library by Google
View (RecyclerView...etc ) RenderScript MultiDex Annotations Support Library
Sample... Support Library compile 'com.android.support:support-v4:+' compile 'com.android.support:appcompat-v7:+' compile 'com.android.support:design:+' compile
'com.android.support:recyclerview-v7:+' compile 'com.android.support:cardview-v7:+' compile 'com.android.support:support-annotations:+' compile ‘com.android.support:percent:+'
Android ObservableScrollView by ksoichiro
ScrollView , ListView, RecyclerViewなどのスクロー ル制御を監視 Android-ObservableScrollView https://github.com/ksoichiro/Android-ObservableScrollView
Calligraphy by Christopher Jenkins
Calligraphy アプリ全体にFont適用 xmlでもjavaでも可 簡単 https://github.com/chrisjenx/Calligraphy
CalligraphyConfig Calligraphy CalligraphyConfig.initDefault(new CalligraphyConfig.Builder() .setDefaultFontPath("fonts/mplus-2p-regular.ttf") .setFontAttrId(R.attr.fontPath) .build();
ViewAnimator by Florent CHAMPIGNY
ViewAnimator AnimatorSet animSet = new AnimatorSet(); animSet.playTogether( ObjectAnimator.ofFloat(image, View.TRANSLATION_Y, -1000,0),
ObjectAnimator.ofFloat(image, View.ALPHA, 0,1), ObjectAnimator.ofFloat(text, View.TRANSLATION_X, -200,0) ); animSet.setInterpolator(new DescelerateInterpolator()); animSet.setDuration(2000); animSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { AnimatorSet anim = new AnimatorSet(); anim.playTogether( ObjectAnimator.ofFloat(image, View.SCALE_X, 1f, 0.5f, 1f), ObjectAnimator.ofFloat(image, View.SCALE_Y, 1f, 0.5f, 1f) ); anim.setInterpolator(new AccelerateInterpolator()); anim.setDuration(1000); anim.start(); } }); animSet.start();
ViewAnimator ViewAnimator .animate(image) .translationY(-1000, 0) .alpha(0, 1) .andAnimate(text) .dp().translationX(-200, 0)
.descelerate() .duration(2000) .thenAnimate(image) .scale(1f, 0.5f, 1f) .accelerate() .duration(1000) .start();
DataBinding
Android Data Binding by Google
xmlとjavaのBinding Annotation Processing たまにビルドエラーが出る.. Android Data Binding
Android Data Binding <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id=“@+id/user_name“
android:layout_width="wrap_content" android:layout_height="wrap_content"/> <ImageView android:id=“@+id/user_thumbnail“ android:layout_width="160dp" android:layout_height="120dp"/> </LinearLayout>
Android Data Binding <layout xmlns:android="http://schemas.android.com/apk/res/android"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView
android:id=“@+id/user_name“ android:layout_width="wrap_content" android:layout_height="wrap_content"/> <ImageView android:id=“@+id/user_thumbnail“ android:layout_width="160dp" android:layout_height="120dp"/> </LinearLayout> </layout>
Android Data Binding <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data name="MainBinding"> <variable name="user" type="com.example.User"/>
</data> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id=“@+id/user_name“ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.name}" android:textColor="@{user.isWomen? @color/pink : @color:blue}"/> <ImageView android:id=“@+id/user_thumbnail“ android:layout_width="160dp" android:layout_height="120dp" bind:imageUrl="@{user.thumbnail}"/> </LinearLayout> </layout>
Custom Setters Android Data Binding public final class ImageBindingAdapters {
@BindingAdapter({ "bind:image" }) public static void loadImage(ImageView view, String url) { Glide.with(view.getContext().getApplicationContext()) .load(url) .into(view); } } <ImageView android:layout_width="160dp" android:layout_height="120dp" bind:imageUrl="@{user.thumbnail}"/>
DataBindingUtil Android Data Binding @Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); MainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); binding.userName.setOnClickListener(v -> ...); } <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data name="MainBinding"> <variable name="user" type="com.example.User"/> </data> <!-- ... -- </layout>
Networking
(Volley) Retrofit + OkHttp Networking
Retrofit+OkHttp by Square
REST RxJava support Pluggable client Converters(Gson, Wire...) Retrofit+OkHttp
Retrofit Retrofit retrofit = new Retrofit.Builder() .client(okHttpClient) .baseUrl("https://api.github.com") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build(); GitHubService service = retrofit.create(GitHubService.class); service.repos("wasabeef") .subscribe(repo -> { // ... }, e -> { Timber.w(e); }); public interface GitHubService { @GET(/users/{user}/repos) Observable<List<Repo>> repos(@Path(user) String user); }
JSON & ProtoBuf
(Gson) (Jackson) (Moshi) Wire Serialisations
Wire by Square
Protocol Buffers okioを利用 Server/Clientで定義を共通化 Webからは扱いづらい Wire
Wire syntax = "proto3"; package helloworld; message HelloRequest { string
name = 1; } message HelloReply { string message = 1; } hello.proto
Wire Build # java -jar wire-compiler-2.0.1-jar-with-dependencies.jar \ —proto_path=. \ —java_out=.
hello.proto Writing helloworld.HelloRequest to . Writing helloworld.HelloReply to .
Parcelables
(android-parcelable-intellij-plugin) Parceler (Auto-Value-Parcel) Icepick Parcelables
Parceler by John Ericksen
Annotation Processing AutoValue Parceler
Parceler @Parcel public class User { public String name; public
String thumbnail; User() { } } // Wrap Bundle bundle = new Bundle(); bundle.putParcelable("user", Parcels.wrap(user)); // Unwrap User user = Parcels.unwrap(getIntent().getParcelableExtra("user"));
Icepick by Frankie Sardo
Simple Icepick public class MainActivity extends Activity { @State String
name; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Icepick.restoreInstanceState(this, savedInstanceState); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Icepick.saveInstanceState(this, outState); } }
Image Loaders
(Universal Image Loader) Picasso Glide Fresco Image Loaders
Picasso by Square
Simple Cache Transformations Debug Picasso
Simple Picasso Picasso.with(context) .load(“http://i.imgur.com/DvpvklR.png”) .setIndicatorsEnabled(true) .into(imageView);
Glide by Google (unofficial)
Glide Bitmap Pool Gif support Thumbnail Animation support Transformations
Simple Glide Glide.with(context) .load(“http://i.imgur.com/DvpvklR.png”) .crossFade() .thumbnail(.1f) .into(imageView);
Picasso? Glide?
Picasso? Glide? http://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en
Picasso? Glide? http://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en
Picasso? Glide? http://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en Library's size
Picasso? Glide? http://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en Method Count
Fresco by Facebook
Fresco Ashmem heap View Gif support Animation
Fresco
Fresco <com.facebook.drawee.view.SimpleDraweeView android:id="@+id/my_image_view" android:layout_width="20dp" android:layout_height="20dp" fresco:fadeDuration="300" fresco:actualImageScaleType="focusCrop" fresco:placeholderImage="@color/wait_color" fresco:placeholderImageScaleType="fitCenter" fresco:failureImage="@drawable/error"
fresco:failureImageScaleType="centerInside" fresco:retryImage="@drawable/retrying" fresco:retryImageScaleType="centerCrop" fresco:progressBarImage="@drawable/progress_bar" fresco:progressBarImageScaleType="centerInside" fresco:progressBarAutoRotateInterval="1000" fresco:backgroundImage="@color/blue" fresco:overlayImage="@drawable/watermark" fresco:pressedStateOverlayImage="@color/red" fresco:roundAsCircle="false" fresco:roundedCornerRadius="1dp" fresco:roundTopLeft="true" fresco:roundTopRight="false" fresco:roundBottomLeft="false" fresco:roundBottomRight="true" fresco:roundWithOverlayColor="@color/corner_color" fresco:roundingBorderWidth="2dp" fresco:roundingBorderColor="@color/border_color" />
Effects
Blurry Android StackBlur GPUImage for Android Picasso/Glide Transformations Effects
Blurry by Wasabeef
Blurry Blur RenderScript DownSampling
Android StackBlur by Enrique López Mañas
Blur RenderScript NDK Android StackBlur
Android StackBlur https://github.com/kikoso/android-stackblur
Android StackBlur https://github.com/kikoso/android-stackblur
GPUImage for Android by CyberAgent
GPUImage OpenGL ES 70 Filters Tone Curve
Picasso/Glide Transformations by Wasabeef
Transformations Picasso, Glide, Fresco Crop Blur Color Filter GPU Filter
DI
(AndroidAnnotations) (Square/Dagger) Google/Dagger Butter Knife DI
Dagger2 by Google
Annotation Processing テスト・メンテナンス Dagger2
Butter Knife by Jake Wharton
View Injection Butter Knife public class MainActivity extends Activity {
@Bind(R.id.user_name) TextView userName; @Bind(R.id.user_thumbnail) ImageView thumbnail; @BindString(R.string.title) String title; @BindDrawable(R.drawable.graphic) Drawable graphic; @BindColor(R.color.red) int red; @BindDimen(R.dimen.spacer) float spacer; }
OnClick, OnTextChange, OnFocusChange...etc Butter Knife @OnClick(R.id.user_name) public void click(View view)
{ // ... } @OnClick({ R.id.user_name, R.id.user_thumbnail }) public void click(View door) { // ... }
FRP
RxJava RxAndroid (RxBinding) (RxLifecycle) FRP
RxJava by Netflix
非同期、リスト操作が簡単 Retrolambdaがあると良い Leakが怖い Retrofitと併用 RxJava
Sample RxJava Observable.just("Google", "Apple", "MicroSoft") .map(String::toUpperCase) .subscribe(name -> { Timber.d("OnNext
" + name); }, throwable -> { Timber.d("OnError"); });
Sample RxJava Observable.just("Google", "Apple", "MicroSoft") .map(String::toUpperCase) .subscribe(name -> { Timber.d("OnNext
" + name); }, throwable -> { Timber.d("OnError"); });
lift compose rxjava-extras (by Dave Moten) RxJava
RxAndroid by RxAndroid authors
Scheduler RxAndroid
Main Thread RxAndroid Observable.just("one", "two", "three", "four", "five") .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(/* an Observer */); final Handler handler = new Handler(); Observable.just("one", "two", "three", "four", "five") .subscribeOn(Schedulers.newThread()) .observeOn(HandlerScheduler.from(handler)) .subscribe(/* an Observer */) Arbitrary Thread
DB/ORM
(ActiveAndroid) Realm (SQLBrite) Android Orma DB/ORM
Realm by Realm
Not SQLite RxJava? Thread間の制約 Realm
Android Orma by gfx
SQLite Annotation Processing RxJava Semi-automatic migration Android Orma
Event Buses
Otto EventBus (RxJava) Event Buses
Otto by Square
Deprecated! Square @Produceが少し便利 Otto
EventBus by greenrobot
EventBus EventBus3 Threading Support Annotation Processing
Debugging
Timber Hugo Debugging Stetho Leak Canary Takt Crashlytics
Timber by Jake Wharton
Logger Timber.Treeを継承して追加する ことで、出力先を自由に変えれる Timber if (BuildConfig.DEBUG) { Timber.plant(new Timber.DebugTree()); }
else { Timber.plant(new CrashReportingTree()); }
Hugo by Jake Wharton
AnnotationでMethod Callsを Loggingできる Hugo @DebugLog public String getName(String first, String
last) { return first + " " + last; } V/Example: ⇢ getName(first="Daichi", last="Furiya") V/Example: ⇠ getName [0ms] = “Daichi Furiya"
Stetho by Facebook
Chrome Developer Toolsを利 用して、Network、Dataの状 況の把握 Stetho-Realm (by uPhyca) Stetho
Stetho
Stetho
Stetho
Leak Canary by Square
メモリリークを検出 Leak Canary
Takt by Wasabeef
FPSを表示 Takt
Crashlytics by Twitter
クラッシュの検出 リアルタイム分析 NDKサポート Crashlytics
Crashlytics
Others
Multi-Dex ProGuard Others
MultiDex by Google
メソッド数の65k制限 最近は安定してきた MultiDex
Android Methods Count MultiDex https://plugins.jetbrains.com/plugin/8076
ProGuard by GuardSquare
ソースコードの難読化 未使用なリソースの削除 難しい ProGuard
ProGuard 15M sample-production.apk Total methods count: 99,280 (multidex enabled) 13M
sample-production-proguard.apk Total methods count: 54,977 Proguard あり Proguard なし
Conclusion
Thank you. twitter.com/wasabeef_jp wasabeef.jp github.com/wasabeef