Slide 1

Slide 1 text

$PNQPOFOU1BUUFSO GPS"OESPJE Gotanda.mobile #2 2017/03/23 @mattak

Slide 2

Slide 2 text

Ϛονϣ"DUJWJUZ໰୊

Slide 3

Slide 3 text

class MainActivity : FragmentActivity() {
 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState)
 this.setContentView(R.layout.activity_maps)
 }
 } プロジェクト作成時

Slide 4

Slide 4 text

class MainActivity : FragmentActivity(),
 GoogleApiClient.ConnectionCallbacks,
 GoogleApiClient.OnConnectionFailedListener {
 
 var client: GoogleApiClient? = null
 
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 this.setContentView(R.layout.activity_maps)
 /* ... */
 }
 
 override fun onStart() {
 super.onStart()
 /* ... */
 }
 
 override fun onResume() {
 super.onResume()
 /* ... */
 }
 
 override fun onConnected(bundle: Bundle?) { /* ... */ }
 
 override fun onConnectionSuspended(value: Int) { /* ... */ }
 
 override fun onConnectionFailed(result: ConnectionResult) { /* ... */ }
 } GoogleApiClient追加

Slide 5

Slide 5 text

class MainActivity : FragmentActivity(),
 GoogleApiClient.ConnectionCallbacks,
 GoogleApiClient.OnConnectionFailedListener,
 LocationListener, ResultCallback { 
 var client: GoogleApiClient? = null
 
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 this.setContentView(R.layout.activity_maps)
 /* ... */
 }
 
 override fun onStart() {
 super.onStart()
 /* ... */
 }
 
 override fun onResume() {
 super.onResume()
 /* ... */
 }
 
 override fun onConnected(bundle: Bundle?) { /* ... */ }
 
 override fun onConnectionSuspended(value: Int) { /* ... */ }
 
 override fun onConnectionFailed(result: ConnectionResult) { /* ... */ }
 
 override fun onLocationChanged(location: Location?) { /* ... */ }
 
 override fun onResult(result: LocationSettingsResult) { /* ... */ }
 } LocationAPI追加

Slide 6

Slide 6 text

class MainActivity : FragmentActivity(),
 GoogleApiClient.ConnectionCallbacks,
 GoogleApiClient.OnConnectionFailedListener,
 LocationListener, ResultCallback,
 OnMapReadyCallback {
 
 var client: GoogleApiClient? = null
 
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 this.setContentView(R.layout.activity_maps)
 /* ... */
 /* ... */
 }
 
 override fun onStart() {
 super.onStart()
 /* ... */
 }
 
 override fun onResume() {
 super.onResume()
 /* ... */
 }
 
 override fun onConnected(bundle: Bundle?) { /* ... */ }
 
 override fun onConnectionSuspended(value: Int) { /* ... */ }
 
 override fun onConnectionFailed(result: ConnectionResult) { /* ... */ }
 
 override fun onLocationChanged(location: Location?) { /* ... */ }
 
 override fun onResult(result: LocationSettingsResult) { /* ... */ }
 
 override fun onMapReady(client: GoogleMap?) { /* ... */ }
 } GoogleMap追加

Slide 7

Slide 7 text

Payment追加 PushSDK追加 TrackingSDK追加 … 無限に膨らんでいくコード 増えていくinterface 厄介な継承 リファクタリングつらい …

Slide 8

Slide 8 text

Α͋͘Δରࡦ

Slide 9

Slide 9 text

ܧঝʹΑΔղܾ

Slide 10

Slide 10 text

1. 継承分離による解決 MainActivity FragmentActivity class MainActivity : FragmentActivity()

Slide 11

Slide 11 text

1. 継承分離による解決 MainActivity FragmentActivity class MainActivity : FooSDKActivity() FooSDKActivity class FooSDKActivity : FragmentActivity()

Slide 12

Slide 12 text

1. 継承分離による解決 - 継承がかぶると詰む (外部SDKとか - 継承元に密に依存する - 無限に継承が増える - テスタビリティが低い - 各要素の独立性を確保できない

Slide 13

Slide 13 text

'SBHNFOU ʹΑΔղܾ

Slide 14

Slide 14 text

2. Fragmentによる解決 - テスタビリティ低い (mock) - 制約が大きい、別の問題が起きやすい - Viewが必要 (onCreateView)

Slide 15

Slide 15 text

֎෦Ϋϥε ʹΑΔղܾ

Slide 16

Slide 16 text

3. 外部クラスによる解決 - モジュールとして外部クラスにする - Lifecycleで必要モジュールの関数を呼ぶ

Slide 17

Slide 17 text

3. 外部クラスによる解決 Activity.onCreate() override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 Class1.setup(this) Class2.setup(this) // …
 } Class1.setup() Class2.setup() Activity.onResume() Class1.connect() Class3.run() …

Slide 18

Slide 18 text

3. 外部クラス化による解決 - Classごとの呼び出し形式が統一されてない - Class間の依存に対応しにくい - なんだかんだActivityでベタ実装しがち - でも筋はいい気がする

Slide 19

Slide 19 text

ͦ͜Ͱɺ $PNQPOFOU1BUUFSO

Slide 20

Slide 20 text

第14章: Component 1つのゲームの要素の処理が 複数のドメインにまたがる ものであっても、各ドメイン が結合しないようにする。

Slide 21

Slide 21 text

特にUnityでの実装が参考になる 1 GameObject N Component

Slide 22

Slide 22 text

Componentにライフサイクルが移譲されている public class MyComponent : MonoBehaviour { void Awake() { } void Start() { } void Update() { } void FixedUpdate() { } void OnApplicationFocus(bool focusStatus) { } }

Slide 23

Slide 23 text

UnityのComponentがすごいところ✨ View:Component = 1:N - 好きなだけComponentの付け足しができる Lifecycleの分離 - Component毎自由にライフサイクルに処理がかける - ファイルが膨れることがない - 機能分離が容易

Slide 24

Slide 24 text

UnityのComponentがすごいところ✨ Component同士の依存が取得しやすい var collider = this.GetComponent(); Portabilityの高さ - Componentを使いまわしできる - 利用する側に依存しない

Slide 25

Slide 25 text

"OESPJEͰ ࣮૷ͯ͠ΈΑ͏

Slide 26

Slide 26 text

方針 - Activity, Fragmentへの依存薄く - 機能分離できるようにする - 使いまわせるようにする - 必要に応じて依存取得しやすくする

Slide 27

Slide 27 text

Componentの定義 - Lifecycleのみにする - onCreate, onStart,… - Activityを参照可能にする

Slide 28

Slide 28 text

Componentの定義 public interface Component {
 void onComponentsAssigned(Components components);
 
 void onCreate(Activity activity, Bundle savedInstanceState);
 
 void onStart(Activity activity);
 
 void onRestart(Activity activity);
 
 void onResume(Activity activity);
 
 void onPause(Activity activity);
 
 void onStop(Activity activity);
 
 void onDestroy(Activity activity);
 }

Slide 29

Slide 29 text

全ライフサイクル 実装するんのめんどくない?

Slide 30

Slide 30 text

空基底クラスをつくってやる public class BaseComponent implements Component {
 
 @Override
 public void onCreate(Activity activity, Bundle savedInstanceState) {}
 
 @Override
 public void onStart(Activity activity) {}
 // …
 }

Slide 31

Slide 31 text

復数のComponent管理は?

Slide 32

Slide 32 text

Componentsの定義 Components Component has

Slide 33

Slide 33 text

Componentsの定義 - Component達を保持する - LifecycleにComponent達を呼び出すだけ - ComponentsもComponent

Slide 34

Slide 34 text

Componentsを実装する public class Components implements Component {
 private Component[] components;
 
 public Components(Component... components) {
 this.components = components;
 }
 
 @Override
 public void onCreate(Activity activity, Bundle savedInstanceState) {
 for (Component component : this.components) {
 component.onCreate(activity, savedInstanceState);
 }
 }
 
 @Override
 public void onStart(Activity activity) {
 for (Component component : this.components) {
 component.onStart(activity);
 }
 } // ...
 }

Slide 35

Slide 35 text

Componentsの使い方 class AppComponents : Components(
 SampleComponent1(),
 SampleComponent2(),
 SampleComponent3()
 ) 必要Componentを列挙するだけ

Slide 36

Slide 36 text

Activityからどう呼ぶ?

Slide 37

Slide 37 text

必要なライフサイクルで呼び出し class ExampleActivity : FragmentActivity() {
 val component: Component = AppComponents()
 
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 component.onCreate(this, savedInstanceState)
 }
 
 override fun onStart() {
 super.onStart()
 component.onStart(this)
 }
 
 override fun onResume() {
 super.onResume()
 component.onStart(this)
 }
 // ....
 }

Slide 38

Slide 38 text

Componentの依存取得どうする?

Slide 39

Slide 39 text

getComponentで取得 class SampleComponent : BaseComponent() {
 override fun onCreate(activity: Activity?, savedInstanceState: Bundle?) {
 val another = this.getComponent(AnotherComponent::class.java)
 // DO SOMETHING
 }
 }

Slide 40

Slide 40 text

どこがすごいの?

Slide 41

Slide 41 text

ここがすごい!✨ Activityが全く太らない 継承問題がない 各ComponentがPortable Activity,Fragmentを問わずつかえる 機能を疎結合にできる 他のComponentとの依存も書ける Mockもつくりやすい

Slide 42

Slide 42 text

Activityの実装 class MainActivity : FragmentActivity() {
 private val mAppComponents = AppComponents()
 
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_maps)
 
 this.mAppComponents.onCreate(this, savedInstanceState)
 }
 
 override fun onStart() {
 super.onStart()
 this.mAppComponents.onStart(this)
 }
 
 override fun onResume() {
 super.onResume()
 this.mAppComponents.onResume(this)
 }
 
 override fun onRestart() {
 super.onRestart()
 this.mAppComponents.onRestart(this)
 }
 
 override fun onPause() {
 super.onPause()
 this.mAppComponents.onPause(this)
 }
 
 override fun onStop() {
 super.onStop()
 this.mAppComponents.onStop(this)
 }
 
 override fun onDestroy() {
 super.onDestroy()
 this.mAppComponents.onDestroy(this)
 }
 } 基本Lifecycleのみなら これ以上増えない

Slide 43

Slide 43 text

ͭ͘Γ·ͨ͠ʂ⭐͍ͩ͘͞ʂ HJUIVCDPNNBUUBLDPNQPOFOU (あとで公開しときます)