• 検索結果がありません。

この講座で身につく主なスキル 設計( アーキテクチャ ) の基礎知識(MVVM / MVP) Android Architecture Components(AAC) の使い方 (Android アプリ開発の新スタンダードとなる設計ライブラリ [ViewModel / LiveData / Data

N/A
N/A
Protected

Academic year: 2022

シェア "この講座で身につく主なスキル 設計( アーキテクチャ ) の基礎知識(MVVM / MVP) Android Architecture Components(AAC) の使い方 (Android アプリ開発の新スタンダードとなる設計ライブラリ [ViewModel / LiveData / Data"

Copied!
69
0
0

読み込み中.... (全文を見る)

全文

(1)
(2)

この講座で身につく主なスキル

「設計(アーキテクチャ)」の基礎知識(MVVM / MVP)

Android Architecture Components

AAC

)」の使い方

(Androidアプリ開発の新スタンダードとなる設計ライブラリ [ViewModel / LiveData / DataBinding]

サービス(

Service

)を使い方(バックグラウンド処理)

「Koin」を使ったDependency Injection(DI:依存性の注入)

ランチャースクリーン(スプラッシュスクリーン)の作り方 BottonNavigationViewの使い方

「ExoPlayer」を使ったBGM再生(MediaPlayerより高機能な音声・動画再生ライブラリ)

SeekBarを動かして音量調整する方法(端末のボリュームコントロールとリンクさせる方法)

⇥⇤⌅⇧⌃⌥ ⌦↵

⇥⇤⌅⇧⌃⌥ ⌦↵

(3)

ホップ

ステップ

ジャンプ

どんなアプリを作りたいかを 紙に書く

完成図(レイアウト)の作成と 小道具(画像・音など)の準備 つくり方説明書

(ソースコード)の作成

resフォルダ

javaフォルダ

紙に書いたことを 1つずつ 実装するだけ

⌅✏⇣⌘✓◆ ⌫⇠⇡

⌅✏⇣⌘✓◆ ⌫⇠⇡

⇢⇣ ✓⌧⌅ ✓⌧ ✓!

⇢⇣ ✓⌧⌅ ✓⌧ ✓!

(4)

(注)Google I/O => Google Innovation in the Open

現在のGoogleのほとんどのサービスで適用されている

⇒ スマホだけでなくあらゆるデバイス(web含む)で適用 現在のGoogleのほとんどのサービスで適用されている

⇒ スマホだけでなくあらゆるデバイス(web含む)で適用

Google I/O 2014で発表された

新しいデザインガイドライン(デザイン言語)

✏ ◆⌘⌃"#$ %&'

✏ ◆⌘⌃"#$ %&'

(5)

断片・かけら・小部分

タブレット(大画面UI)の出現がFragmentを誕生させた タブレット(大画面UI)の出現がFragmentを誕生させた

表示だけでなく動作も持てる画面(Activity)のパーツ(部品)

()*+ ,

()*+ , -./0123456 -./0123456 %& %&

(6)

表示だけでなく動作も持てる画面(Activity)のパーツ(部品)

動作が持てる(独自のライフサイクルがある) ビュー(View)との違い

アクティビティ(Activity)との違い

Fragment単独では使えない(必ずActivity に属する)

1つの画面に複数のFragmentを配置できる

(Activityは画面に1つだけ)

()*+ ,

()*+ , -./0123456 -./0123456 %& %&

(7)

onAttach onCreate onCreateView onActivityCreated

onResume onPause

onDestroyView onDestroy

onDetach onCreate

onResume onPause

onDestroy

Activity Fragment

開始開始

完了完了

開始開始 完了完了

画面が開いている

FragmentがActivityにくっつく

FragmentがActivityから離れる Fragmentの生成

Fragment内のViewの生成 Activity#onCreateの完了

⇒ Viewの操作はここでやるのが安全 (特にViewに何かを表示するとき)

Fragment内のViewの破棄 Fragmentの破棄

./012345

./012345 ⇡)$(7$8⌃ ⇡)$(7$8⌃

(8)

対応したい言語コードを設定したvaluesフォルダを用意し 言語ごとに文字列リソース(strings.xml)を作成

res/values

<string name="sort">Sort</string>

<string name="delete">Delete</string>

<string name="edit">Edit</string>

<string name="register">Register</string>

strings.xml

<string name="sort">ソート</string>

<string name="delete">削除</string>

<string name="edit">編集</string>

<string name="register">登録</string>

strings.xml

res/values-ja

■ 日本語 : ja ■ 英語 : en ■ 中国語 : zh

■ スペイン語 : es ■ フランス語 : fr ■ 韓国語 : ko

ファイル名 は同じ

主な言語コード

⌘✓◆⇡9:;

⌘✓◆⇡9:; - - <=>)$? <=>)$? 6 6

(9)

アイテム(View)を1つだけ表示させるためのコンテナ(フレーム)

ビューを重ねて表示させたい場合や、Fragmentを動的に設定する場合 に使える(ルートレイアウトの子ビューとして設定)

Activity

FrameLayout

FragmentA

FragmentB

Fragmentを 動的に入れ替え

./023@0ABC5

./023@0ABC5 %&' %&'

(10)

マテリアルデザイン標準テンプレートであるBasicActivityの上に スライド形式のナビゲーションバーが乗っかった3階建てレイアウト

Class MainActivity extends AppCompatActivity { fun onCreate() {

SetContentView

(R.layout.activity_main) }

}

1つのソースファイル

3つのレイアウトファイル(3階建て構造)

app_bar_main.xml content_main.xml

1階[下]

CoodinatorLayout ConstraintLayout

include

2階[中]

2階以下は BasicActivityと同じ

include

activity_main.xml

DrawerLayout

3階[上]

NavigationView

headerLayout

(nav_header_main.xml)

menu

(menu/activity_main _drawer.xml))

HeaderLayout とmenuから成る

F0GH105HB4EM/0N3/

F0GH105HB4EM/0N3/ %& %&

(11)

状態リスト(StateListDrawable)でタッチフィードバックを定義する res/drawableフォルダに状態リストのxmlファイルを作る

効果を出したいImageButtonの「srcCompat」に、作成した状 態リストを設定する(Propertiesからでも可能)

ImageButtonの背景画像の設定先を「srcCompat」から

「background」に移動させる

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">

<item android:drawable="@color/colorPrimaryBackground" android:state_pressed="true"/>

<item android:drawable="@android:color/transparent" android:state_pressed="false"/>

</selector>

ボタンが押されたとき

ボタンが押されていないとき

O P(Q=RS 8⇡TUK

O P(Q=RS 8⇡TUK

(12)

■Buttonの下辺から[from]

■ImageViewの上辺へ[to]

■34dpの制約[how]

■ImageViewの右辺から

[from]

■親(parent)の右端へ[to]

■56dpの制約[how]

制約の3要素

画面上のパーツの位置関係を制約(Constraints)で設定

全部の制約を自動的に設定 してくれる「Infer Constraints」

制約を全て解除する

「Clear All Constraints」

個別の制約を解除したい 場合はここで消す

基本は好きなように並べて最後に「Infer Constraints」を押せばいい 基本は好きなように並べて最後に「Infer Constraints」を押せばいい

VB4W5/0H 45@0ABC5 VB4W5/0H 45@0ABC5 & &

%XYZ[ \]^_`ab c

%XYZ[ \]^_`ab c

(13)

RecyclerView + CardViewを使う RecyclerView

CardView

それぞれ

レイアウトファイルを 作って

ソースコードで

結合させる

ListView をさらに

進化させて柔軟にしたもの

丸みのある角と影を持つ FrameLayout(カード)

1枚のカード内に

複数の種類のView(クラス)を 組み込むことが出来る ListViewに出来ない芸当

✏ ◆⌘⌃"#$ ⇡⌅O$⌃

✏ ◆⌘⌃"#$ ⇡⌅O$⌃

I`⌫de⇤◆⌅,⇡ XK

I`⌫de⇤◆⌅,⇡ XK

(14)

⌘✓◆⇡⇢fg

⌘✓◆⇡⇢fg - - ⌘=⇧ 8P ⌘=⇧ 8P 6 6 !%& !%&

h⇤i⇢ h⇤i⇢ j=⌅k=R lmfgn j=⌅k=R lmfgn !⌥op⇤⇡qr !⌥op⇤⇡qr

アーキテクチャ:アプリを構成する部品の役割分担のさせ方のパターン

Androidアプリはややこしい!

エントリー 複数の ポイント

コンポーネント 他の との連携

他のアプリ

(暗黙的インテント) との連携

複雑な ライフ サイクル

メモリがなくなったら システムに勝手に殺される(T_T)

やみくもにソースコード書いてたらグチャグチャになってまうで~(T_T)

ソースコードにも「設計」が要るな~

⇒ 複雑なアプリの堅牢性と品質を高める ソースコードにも「設計」が要るな~

⇒ 複雑なアプリの堅牢性と品質を高める

(15)

完成図 つくり方説明書

レイアウト[xml] ソースコード[kotlin]

✓<*)s *&t< 8 X%uv

✓<*)s *&t< 8 X%uv

(16)

パッケージ A

パッケージ B

クラス

class X {

fun methodA(){

--- }

fun methodB(){

--- }

}

クラス クラス クラス クラス クラス クラス クラス クラス

クラス クラス クラス クラス 関数

(

メソッド

)

関数

(

メソッド

)

関数(メソッド)の行数が増えてきたら

クラス内の関数(メソッド)の数が 増えてきたら

パッケージ内のクラス数が増えてきたら

複数関数

(メソッド)

に分割

複数クラスに分割

複数パッケージに分割

wB5x H 4-y0G06

wB5x H 4-y0G06 ⇡z{;⇡|}~ ⇡z{;⇡|}~

(17)

⇢fg ⇢fg - - ⌘=⇧ 8P ⌘=⇧ 8P 6 6 !⇡ÄÅÇ !⇡ÄÅÇ

【大原則】アプリのデータや状態をコンポーネントに保存してはいけない!

ÉÑ5H GH 5AÖ./012345

ÉÑ5H GH 5AÖ./012345 h h Üá Üá 8)⌅r 8)⌅r

àz⇡k=Râq⇤Jhäã⇡åçr àz⇡k=Râq⇤Jhäã⇡åçr

Üá Üá & & é"⌃ é"⌃ qèêëíì qèêëíì

UIクラスに書くのは

 ①:UI(ビュー)を表示するロジックと

 ②:OS(Androidシステム)とのやり取りだけ!!

UIに表示させるデータを処理する役割は、UIクラスとは別の人(クラス)に やってもらう(モデル=データを処理するコンポーネント)

役割を明確に分離してライフサイクルの影響を受けにくくする 役割を明確に分離してライフサイクルの影響を受けにくくする

Activity/Service/BroadcastReceiver /ContentProvider

(18)

îïBB1x 3

îïBB1x 3 ñóòô⇡fgöõúùû ñóòô⇡fgöõúùû ü ü E†°°† E†°°†

î°H ° 3Nü °†

î°H 3N†B¢3x ü †

î†B¢3x ü

データの表示

Activity/Fragment

Viewに表示する データの処理

(ビジネスロジック)

データの管理

Model-View-ViewModel

(Android Architecture Components(AAC)のパターン)

LiveData LiveData

ViewからViewModelの呼び出しは一方通行

(DataBinding or Livedataを使うことでコールバック地獄から解放!)

ViewからViewModelの呼び出しは一方通行

(DataBinding or Livedataを使うことでコールバック地獄から解放!)

£3§BWH 5B/A

データの取得

ViewModel内のプロパティを監視して 監視元(Activity等)に変更を 自動で通知できるオブジェクト ViewModel内のプロパティを監視して

監視元(Activity等)に変更を 自動で通知できるオブジェクト LiveDataによる自動通知 Or

DataBindingによる自動更新

DataBinding

DataBinding

(19)

î°H ° 3Nü •

î•/3W3453/ü †

î†B¢3x ü

データの表示

Activity/Fragment

Viewに表示する データの処理

(ビジネスロジック)

データの管理

Model-View-Presenter

ViewからPresenterの呼び出しは双方向

(DataBindingもLivedataも不要だがコールバック地獄が残る!)

ViewからPresenterの呼び出しは双方向

(DataBindingもLivedataも不要だがコールバック地獄が残る!)

£3§BWH 5B/A

データの取得

î î lc¶⌦⇡fgöõúùû lc¶⌦⇡fgöõúùû üE†°• üE†°•

VB45/0Ñ5B/

( á453/ß0Ñ3 )

VとPをつなぐ Interface

(20)

ÉÉV ÉÉV ⇡⇢ ⇡⇢ °H3N†B¢3x °H3N†B¢3x !%& !%&

ライフサイクルの影響を受けずに、

UI関連のデータを保存・管理できるクラス

画面の回転等でActivityが破棄されても、データを 保持し続けることが出来る

Activityが

3回破棄されてる!

®©⇡°H 3N†B¢3x

®©⇡°H 3N†B¢3x

™´0/3¢°H 3N†B¢3x

™´0/3¢°H 3N†B¢3x

Fragment間でViewModelを共有しない

⇒ Fragment間でデータのやり取り不可

Fragment間でViewModelを共有する

⇒ Fragment間でデータのやり取り可能

ViewModelからはAndroidフレームワーク関連のクラス

(Activity/Fragment含む)を原則参照してはいけない ViewModelからはAndroidフレームワーク関連のクラス

(Activity/Fragment含む)を原則参照してはいけない

ApplicationContextを使いたい場合はAndroidViewModelを継承させる

(21)

アプリの「今の状態」にアクセスするための橋渡しをする抽象クラス

状況・事情・背景

ソースコード

クラス横断的なアプリケーションレベル でのオペレーションの状況

■ アクティビティの起動

■ ブロードキャスト

■ インテントの受け渡し等

Context

抽象クラスだが実装は Androidシステムが行っている

■ アプリ固有のリソース・クラス ■ アプリの環境情報

静的状態

動的状態

■ ActivityContext ⇒ Activityが破棄されたら破棄される

■ ApplicationContext ⇒ Applicationが生きている限り有効(★)

■ ActivityContext ⇒ Activityが破棄されたら破棄される

■ ApplicationContext ⇒ Applicationが生きている限り有効(★)

全く別物

⇢ ⇢ VB453¨5 VB453¨5 ! % & ' ! % & '

(22)

システム上の都合でActivityが破棄された場合にActivityの状態を一時的に保存する

■ 画面(Activity)の構成が変化したとき(画面の向きの変更・表示言語の変更等)

 ⇒ onDestroy()が呼び出されて破棄され、その直後にonCreate()が呼び出されて再生成される

■ Activityが停止状態(Paused)の時に、他のアプリなどでメモリが使われてしまった場合

 ⇒ onDestroy()が呼び出されて破棄されて、再生成してくれない(長時間の停止状態は良くない)

onSaveInstanceState()をオーバーライドして

Activityが破棄されても残しておきたい情報を保存しておく

onSaveInstanceState()で保存したBundle型の 情報がonCreate()の引数として渡される

ÉÑ5H GH 5A

ÉÑ5H GH 5A ⇡≠ÆØ∞± ≤≥ ⇡≠ÆØ∞± ≤≥

h h B4™0G3á4W504Ñ3™5053 B4™0G3á4W504Ñ3™5053 r r

(23)

ÉÉV ÉÉV ⇡⇢ ⇡⇢ @HG3M050 @HG3M050 !%& !%&

監視可能なデータを保持するためのクラス

(原則「ViewModel」クラスの中で使う)

データに変更があった場合は、監視元に自動で通知 させることが出来る (コールバック地獄からの解放!)

$ O=(¥=⌅

$ O=(¥=⌅ @H @H G3M050 G3M050

外注元から呼び出しを受けた上で 更新(コールバック要)

外注元から呼び出しを受けた上で

更新(コールバック要) 監視元の変更を自分でキャッチして 自分で更新(コールバック不要)

監視元の変更を自分でキャッチして 自分で更新(コールバック不要)

° á453/ß0Ñ3

外注先(P)のことは 何もわからない

° °†

LiveData

(スパイ)

LiveData

(スパイ)

監視先にスパイを 送って監視

変更があったら スパイ自ら監視元に通知 変更があったら

コールバックメソッド呼び出し

(24)

⇢ ⇢ M050DH M050DH 4¢H 4¢H 41@H 41@H µ/0/A µ/0/A !%& !%&

レイアウトファイル上で別のクラスと結びつけて(バインド) バインド先のメンバをレイアウトファイル上からも参照できる機能

【Kotlin Android Extentionsとの違い】

「’ndViewById」が不要になる点は同じだが、

他クラスのメンバをレイアウトファイル上からでも参照できる 【Kotlin Android Extentionsとの違い】

「’ndViewById」が不要になる点は同じだが、

他クラスのメンバをレイアウトファイル上からでも参照できる

コールバック撲滅のみならず ソースコード自体も削減出来る!

レイアウトファイルが所属するView

(Activity/Fragment等)とは違うクラス

î†0H 4ÉÑH ° 5H GH 5A∂∑5ü °†

î°H 3N†B¢3x ∂ ∑5ü

LiveData LiveData

î0Ñ5HGH

°

5A∏20H

°

4∂¨2xü î0Ñ5HGH5A∏20H4∂¨2xü

プロパティ メソッド

レイアウトファイル から参照可能

View-ViewModel間の

ソースコード上でのやり取りが不要に

(25)

完成図(layout)でつけた「id」を説明書(kotlin)でそのまま使える!

完成図(layout)でつけた「id」を説明書(kotlin)でそのまま使える!

appレベルのbuild.gradleに「kotlin-android- extentions」プラグインを入れる

apply plugin: 'kotlin-android-extensions'

説明書(kotlin)に結びついている完成図(layout)

をインポートする

import kotlinx.android.synthetic.main.activity_main.*

完成図(layout)のファイル名

⇢ ⇢ ßH ßH 4¢°H 4¢°H 3NDAá 3NDAá ¢ ¢ ! !

7π∫) ⌫⇠⇡⌅ ✓

7π∫) ⌫⇠⇡⌅ ✓

(26)

†°°† †°°† h h ÉÉV ÉÉV r⇡IJKª r⇡IJKª

ViewModel+LiveData(DataBinging無し)

°H 3N†B¢3x

°H 3N ( Üá )

îÉÑH 5H GH 5AEÖE./012345ü

監視プロパティの設定 ViewModelインスタンス取得

  (Fragmentの場合はonActivityCreatedで)

[普通のViewModel]

ViewModelProviders.of(this).get(ビューモデルクラス) [Fragment間でシェアする場合]

ViewModelProviders.of(activity).get(ビューモデルクラス)

ビジネスロジック

  (処理の中身=メソッド)の実装    ⇒ 監視プロパティの値変更

値変更を受けてView側に自動的に通知され、

⑤の処理が実行される(呼び出し不要)

監視プロパティを「監視(

observe)」

し、値変更を受けた処理を記述

監視プロパティ.observe(this, Observer{

値変更を受けた処理を記述 })

LiveData LiveData

処理の外注

(ビューのイベント処理等)

  (ViewModelのメソッド呼び出しだけ)

Viewクラス内に

ビジネスロジック(処理の中身)は書かない

(27)

†°°† †°°† h h ÉÉV ÉÉV r⇡IJKº r⇡IJKº

ViewModel+LiveData+DataBinging

°H 3N†B¢3x

°H 3N ( Üá )

îÉÑH 5H GH 5AEÖE./012345ü

監視プロパティの設定 LiveData LiveData

ビジネスロジック

  (処理の中身=メソッド)の実装    ⇒ 監視プロパティの値変更

ViewとViewModel間のやり取りをレイアウトファイル に記述するのでソースファイルでのコーディング不要に!

DataBindingsの初期設定

①依存関係設定 ②ルートを「layout」に

②ViewModelクラスの結びつけ(dataに)

ビューの表示属性(text等)に

   ViewModelの監視プロパティ設定

ビューのイベント属性(onClick等)

   にViewModelのメソッド設定 DataBindingsインスタンス取得

一旦ビルドしないとバインディングクラス使えない

(Fragmentの場合はonCreateViewで)

コード上でのViewModelとの結びつけ

① ViewModelインスタンス取得

② ②に①をセット

③ ②にLifeCycleOwnerをセット

監視プロパティの変更を レイアウトに反映させるため

(28)

ïBB1x 3

ïBB1x 3 ñó⇡òô ñó⇡òô fg b^ fg b^

Ω⌅,✓)8 Q⌅

Ω⌅,✓)8 Q⌅

ViewModel+LiveData+DataBinging

ViewModel(VM)はAndroidのフレームワーククラスを参照してはいけない

(VMはActivityよりライフサイクル長いのでメモリリーク引き起こす可能性  ⇒ ApplicationContextを持ちたい場合はAndroidViewModelを使う)

UIクラス(Activity/Fragment等:View)はなるべく小さく

(UIクラスの責務はデータの変更に伴うViewの更新とユーザー操作のViewModelへの伝達のみ)

データ処理に関するビジネスロジックはViewModelに記述

(ViewModelはUIクラス(View)とデータ(Model)との間のコネクター)

データの取得処理は、ViewModelに直接書かず、Repositoryを使う

(データソースが変わっても影響を受けずに済むように(VMから同じメソッドで呼び出せるように))

DataBindingを使う

(ViewとUIクラスの関係をクリーンに保ち、Viewの更新の関わるコーディングを最小限に出来る)

(29)

あらかじめ特定の役割を持ったアプリを構成する部品

自分で作ったコンポーネントはマニフェストファイルの

<application>タグ内への登録が必要

自分で作ったコンポーネントはマニフェストファイルの

<application>タグ内への登録が必要 Activity

Service Broadcast

Receiver Content Provider

1つのUIで1つの画面を表すもの

(1つのUIに複数の画面は持てない)

バックグラウンドでの処理

(UIはない=見えない)

システム全体へのアナウンス処理 [全体放送]

(設定情報変更・特定のイベント発生等)

端末内の他のアプリとのデータ共有

(FileProviderはここから派生)

Intentに よって起動

Intentに よって起動

É4¢/BH ¢

É4¢/BH ¢ ⌘✓◆⇡ ⌘✓◆⇡

æÄk ø=¿ ,h¡¬p√r

æÄk ø=¿ ,h¡¬p√r

(30)

使い方2ステップ

Applicationクラスを継承した自作クラスの作成

マニフェストファイルの”application”タグに①で作成し たクラスを設定

Androidアプリが起動したときに作成され、呼び出されるクラス

アプリが立ち上がるときに行いたい設定や、アプリ 内で共有したいデータを設定するときに使える

<application android name = “ .作成した自作クラス名”>

<application android name = “ .作成した自作クラス名”>

ɧ§x H Ñ05H B4

ɧ§x H Ñ05H B4 8)⌅%& 8)⌅%&

(31)

何もせずに、データを保持するためだけのクラス

"=O8)⌅

"=O8)⌅ -¢050EÑx -¢050EÑx 0WW6 0WW6

data class User (val name: String, val age: Int)

class宣言の頭に

「data」をつける

引数を最低1つ持つ

プライマリコンストラクタ

引数は「val」か「var」

で宣言してしまう

⇒ 宣言の文無し!

データクラスが最初から持っているメソッド

equals(other: Any): Boolean データインスタンス(User)が他のオブジェクトと等しいかどうか判定 hashCode(): Int データインスタンス(User)がハッシュ値(各オブジェクトに割り

振った識別番号(=ID)を取得

toString(): String ”User(name=John, age=42)”形式の文字列に変換

to(that: B): Pair<User

, B>

データインスタンス(User)と他のクラス(B)とをペア付け copy(変更したい引数): User データインスタンス(User)内の一部のデータだけを変更

(32)

var

val strName

(小文字から)

クラスの種類(=型) :String

省略可(型推論)

“きーぼー”

中身を途中で変える場合

(「=」を2回以上使う場合)

中身を途中で変えない場合

なるべくこっちを使う

▶ 基本データ型 ⇒ 値そのもの

▶ いわゆるクラス ⇒ インスタンス

K otlinは空っぽ(null)がキライ!!

■ どーしても今決められない場合 ⇒ 先頭に「lateinit」をつける

■ どーしても空っぽ(null)が入る場合 ⇒ 「型」のうしろに「?」をつける ■ どーしても今決められない場合 ⇒ 先頭に「lateinit」をつける

■ どーしても空っぽ(null)が入る場合 ⇒ 「型」のうしろに「?」をつける

(オブジェクト) 変数

8)⌅&ƒ≈⌦^a∆ «\⇤J%

8)⌅&ƒ≈⌦^a∆ «\⇤J%

Ic %⌥T»⇤Jh… ⇡Àr

Ic %⌥T»⇤Jh… ⇡Àr

(33)

インスタンスを経由せずにアクセスできるオブジェクト=静的オブジェクト

クラス内で「companion object」として設定

クラス外でトップレベルプロパティ・関数として設定

「クラス名(≠インスタンス名). オブジェクト名」でアクセス

「オブジェクト名」でダイレクトにアクセス可能

Javaでいうところの「static」

Kotlinにしか出来ない芸当

Ã⇡8)⌅qèÕl$ ⌅O ⌅Œœì[

Ã⇡8)⌅qèÕl$ ⌅O ⌅Œœì[

–t ¥8, ⌘8—⌅ ⌦⇡K“

–t ¥8, ⌘8—⌅ ⌦⇡K“

(34)

「オブジェクト=インスタンス=実体」⇒ 全部同じ意味

「オブジェクト=インスタンス=実体」⇒ 全部同じ意味

■ クラス(class): 実体を生み出すための金型(何度も生成できる)

■ オブジェクト(object):すでに生み出された実体(1度しか生成できない)

ヒト(class)はいくらでも 生み出すことができるけど

 (object)はこの世にたった 一人しか存在しえない

みんな同じ「ヒト」だが 名前が違う

(別インスタンス)

8)⌅ 8)⌅ -Ñx -Ñx 0WW6 0WW6 %–t ¥8, %–t ¥8, -Bµ” -Bµ” 3Ñ56 3Ñ56 ⇡‘J ⇡‘J

(35)

onCreate onResume

onPause onDestroy

(オン・クリエイト)

(オン・レジューム)

(オン・ポーズ)

(オン・デストロイ)

・・・画面を立ち上げる時(1回だけ)

・・・画面を閉じる時(1回だけ)

画面が見える

画面が見えない

画面が 開いている

状態

開いている≠見える Androidでは

画面は1つしか 見ることができない

Androidでは 画面は1つしか

見ることができない

’÷h ’÷h ÉÑ5H ÉÑ5H GH GH 5A 5A r⇡)$(7$8⌃ r⇡)$(7$8⌃

(36)

キーと値のペアでちょっとしたデータの読み取りと書き込みが出来るクラス

データの書き込み

val pref = context.getSharedPreferences(

データを保存するファイル名

, Context.MODE_PRIVATE) val editor = pref.edit()

editor.putString(

“キーの名前”

, userName) editor.commit()

データの読み取り

val pref = context.getSharedPreferences(

データを保存するファイル名

, Context.MODE_PRIVATE) Val defaultUserName =

“名無しの権兵衛”

val userName = pref.getString(

“キーの名前”,

defaultUserName)

Contextを継承しているクラスで使う場合は「this」

「パッケージ名+ファイル名」⇒ 一意で識別できるように

ファイルは共有ファイル扱いなので アクセスは自アプリからだけに制限

データが存在しない場合の デフォルト値を設定しておく

◊ÿ`%U⌫"=O≤Ÿ

◊ÿ`%U⌫"=O≤Ÿ

-™´0/3¢•/3ß3/34Ñ3W6

-™´0/3¢•/3ß3/34Ñ3W6

(37)

「DialogFragment(サポートライブラリベース」

を継承したAlertDialogFragmentクラスの作成

使い方5ステップ

setPositiveButton() / setNegativeButton()の処理の中身

(ラムダ式の中)はコールバックメソッドの呼び出し

呼び出し元で実装するコールバックメソッドを

定義したインターフェースの作成

onCreateDialogメソッドをオーバーライドし て、AlertDialogを作成(基礎編の5ステップ)

onAttach()をオーバーライドしてインタフェー スリスナーを設定

呼び出し元のActivityでAlertDialogFragmentを

表示させ(show())、コールバックメソッドを実装

DialogFragmentで作成したDialogをActivityから呼び出す(ボタン押下処理も)

DialogFragment作成段階ではcreate()にしておく onPositiveButtonClicked() / onNegativeButtonClicked()

MH 0x B1./012345

MH 0x B1./012345 I`⌫ I`⌫

Éx 3/5MH 0x B1

Éx 3/5MH 0x B1 ⇡ XK ⇡ XK -@H -@H G3M050 G3M050 ⁄I€S= ‹ 6 ⁄I€S= ‹ 6

(38)

apply / also / let / run

apply / also / let / run

用途 関数 呼び出し元

へのアクセス 戻り値

オブジェクト の初期化

apply this

呼び出し元自身(this)

also it

呼び出し元自身(it)

NULL

(空っぽ)

チェック

let it

let関数の実行結果

run this

run関数の実行結果自分で指定できる

自分で指定できない

 ■ this : 呼び出し元のレシーバーそのもの

 ■ it : 呼び出し元のレシーバーが渡されたラムダ式の唯一の引数it  ■ this : 呼び出し元のレシーバーそのもの

 ■ it : 呼び出し元のレシーバーが渡されたラムダ式の唯一の引数it

›`fiXfl‡ ⌅k=✓ä · ⇡IJå^

›`fiXfl‡ ⌅k=✓ä · ⇡IJå^

(39)

既存のクラスを継承せずにメソッド(関数)を追加できる機能

fun 既存のクラスの型.追加するメソッド名(引数):戻り値の型{処理の中身}

val soundPool = SoundPool(・・・)

soundPool.play(soundId1, 1.0f, 1.0f, 0, 0, 1.0f ) soundPool.play(soundId2, 1.0f, 1.0f, 0, 0, 1.0f ) soundPool.play(soundId3, 1.0f, 1.0f, 0, 0, 1.0f ) soundPool.play(soundId4, 1.0f, 1.0f, 0, 0, 1.0f )

fun SoundPool.play2 (soundId: Int) {

this .play(soundId, 1.0f, 1.0f, 0, 0, 1.0f ) }

soundPool. play2 (soundId1) soundPool. play2 (soundId2) soundPool. play2 (soundId3)

このおまじないを打つのが面倒! 余計なコーディングがなくなってスッキリ!

他のクラスのメンバをあたかも自分のクラスの メンバであるかのようにアクセスできる機能 他のクラスのメンバをあたかも自分のクラスの

メンバであるかのようにアクセスできる機能

レシーバ

(this)

レシーバ

(this)

‚„ ä ·

‚„ ä · -3¨534WH -3¨534WH B4EßC4Ñ5H B4EßC4Ñ5H B4W6 B4W6 %& %&

(40)

ListViewを進化させた大きなデータセットを表示するためのコンテナ

Dataset

Adapter ViewHolder

RecyclerView

x行目のデータを 表示されるで~

リスト1行分のView

表示させる段階になってからViewを生成させ、キャッシュに貯めて使いまわす

⇒ 少ないメモリで大きなデータを効率的に表示させる工夫

表示させる段階になってからViewを生成させ、キャッシュに貯めて使いまわす

⇒ 少ないメモリで大きなデータを効率的に表示させる工夫

LayoutManager

リストとデータのつなぎ役

表示の位置調整 画面に表示されるリスト

x行目のデータ 取ってくるわ~

取ってきたデータ からView作るわ~

作ったView送るから リストに表示して~

表示が終わったら キャッシュにためといて

使いまわすわ~

⇢ ⇢ £3ÑAÑx £3ÑAÑx 3/°H 3/°H 3N 3N !%&' !%&'

(41)

使い方8ステップ

リストの位置調整を行うLayoutManagerの設定 リストとデータのつなぎ役であるAdapterの設定

(RecyclerView.Adapterを継承したクラスの作成)

リスト1行分のViewを保持するViewHolderの設定

(RecyclerView.ViewHolderを継承・②で作ったAdapterクラスの内部クラスに)

ViewHolder用(リスト1行分)のレイアウトファイルの作成

(CardViewを使うことが多い)

ViewHolderの生成

(②で作ったAdapterクラス内でonCreateViewHolderメソッドをオーバーライド)

ViewHolderの中身のViewの設定 ⇒ ここでリスト1行分のViewが作られる

(②で作ったAdapterクラス内でonBindViewHolderメソッドをオーバーライド)

Adapterが保持しているリストの行数の取得 ⇒ LayoutManagerに伝える

(②で作ったAdapterクラス内でgetItemCountメソッドをオーバーライド)

RecyclerViewにAdapterをセット

⇢ ⇢ £3ÑAÑx £3ÑAÑx 3/°H 3/°H 3N 3N !⇡IJK !⇡IJK

Adapterクラスの 実装必須メソッド3つ

(42)

アプリ外(URL)からの画像取得処理を効率化してくれるライブラリ

val url = URL(“http:// ・・・ ” )

val inputStream = url.openStream() val bitmap = BitmapFactory

.decodeStream(inputStream) imageView = setImageBitmap(bitmap) inputStream.close

Glide.with(this)

.load(“http:// ” ・・ ) .into(imageView)

通常の画像取得処理 Glideを使うと

①:取得したい画像のURLを指定

②:InputStreamで画像を読み込み

③:読み込んだ画像をビットマップに変換(デコード)

④:ImageViewに画像をセット

⑤:InputStreamを閉じる

5つもの工程をたった1文でやってくれる(+メモリ管理までやってくれる)

5つもの工程をたった1文でやってくれる(+メモリ管理までやってくれる)

’ ‰Â ~ Ê ~)$t)◆⇢

’ ‰Â ~ Ê ~)$t)◆⇢ ïx ïx H H ¢3 ¢3 ! !

(43)

完成図

(レイアウトファイル)

に貼り付けたビューと その属性(プロパティ)は、アプリが開いたときに

有効となり、ずっと変わらない

静的

アプリ

(プログラム)

を動かしている途中で変えたい場合、

説明書

(kotlinファイル)

で設定する

動的

【動的にビューを表示(非表示)】

⇒ View#visibility = View.VISIBLE (View.INVISIBLE) 【動的にビューを使える(使えない)】

⇒ View#isEnable = true (false) 【動的にビューを表示(非表示)】

⇒ View#visibility = View.VISIBLE (View.INVISIBLE) 【動的にビューを使える(使えない)】

⇒ View#isEnable = true (false)

✓<*) Á ëqUaJ Ë ∆Õ

✓<*) Á ëqUaJ Ë ∆Õ ÈÍ =h

ÈÍ =h °H °H 3N 3N r rÎ Î

(44)

一定時間(間隔)を開けてから行う処理のこと 使い方3ステップ

タイマー処理を行うクラス:Timerの準備

(インスタンス化)

タイマー処理を実行する

使い終わったTimerをキャンセルする (Timer#cansel)

Timer#

schedule (最初の処理までの間隔, 2回目以降の処理間隔,

●●

)

 ■ Timerはキャンセルしたら再利用できない(もう一度①から)  ■ Timerは一度動かすと一時停止・再開ができない

 ■ Timerはキャンセルしたら再利用できない(もう一度①から)  ■ Timerは一度動かすと一時停止・再開ができない

処理を何度も繰り返す場合

タイマー処理の中身

(ラムダ式)

タイマー処理の中身

(ラムダ式)

「for Timer in kotlin.concurrent」の方を使う

O$✏= ÏÌ %&' Ó

O$✏= ÏÌ %&' Ó Ô Ô H H 23/ 23/  

(45)

Androidは処理を流すベルトコンベア(スレッド)が1本しかない

タイマー処理用に別のベルトコンベアを作る

文字を出す メインスレッド(UIスレッド)

メインスレッド(UIスレッド)

サブスレッド(バックグラウンドスレッド)

計算する

タイマー処理

画像を出す 音を出す 文字を出す

画像を出す 音を出す 音を出す

文字を出す

タイマー処理

文字を出す 画像を出す 音を出す 文字を出す 画像を出す 音を出す

文字を出す 画像を出す 音を出す 文字を出す

別のベルトコンベア(スレッド)で 処理をするためのクラス

⇒正確には「インターフェース」 Runnable

サブスレッドでは画面に何かを表示する処理はできない サブスレッドでは画面に何かを表示する処理はできない

O$✏= ÏÌ %&' Ó

O$✏= ÏÌ %&' Ó Ô Ô H H 23/ 23/  

(46)

fun toBeSynchronized() = sharedResource.operation()

val result = lock(lock, ::tobeSynchronized )

ナゾを解く3つのカギ

Kotlinでは関数の引数に関数を 持つことができる(高階関数)

引数となる関数はラムダ式(名前 のない関数)として直接処理を書 くことができる

val result = lock(lock,

sharedResource.operation() )

最後の引数が関数の場合、Kotlin では()の外に出す

「::」+引数とする関数名

val result = lock(lock )

sharedResource.operation()

 関数名の直後の{}は引数となっている関数の中身!!

 関数名の直後の{}は引数となっている関数の中身!!

ä · ƒ⇡ ÒÚ ⌥

ä · ƒ⇡ ÒÚ ⌥ -6 -6 Õ&⇤fi Õ&⇤fi

ÛÙ ⇤`aJ ∫ ı  ˆ fi

ÛÙ ⇤`aJ ∫ ı  ˆ fi

(47)

名前を付けずに(=宣言をせずに)、処理の中身を直接記述した関数

【普通の関数】fun 関数名(引数:型):戻り値の型 処理の中身

        fun addCalc (a:Int, b:Int): Int { return a + b}

【ラムダ式】 引数:型 -> 戻り値の型 処理の中身

        {a:Int, b:Int -> Int a + b}

▶ 引数、戻り値の型は省略できる

▶ 引数が1つだけの場合は暗黙の引数「it」が使える

 

 ① 関数の引数として

② 関数型インターフェースの実装(clickListener等)

 

 ① 関数の引数として

② 関数型インターフェースの実装(clickListener等)

2つの使い道

メソッドが1つだけのインターフェース

) Á˜¯˘ ƒ≈⇡⇤Jä ·

) Á˜¯˘ ƒ≈⇡⇤Jä · - - +j R +j R 6 6

(48)

バックグラウンドでの処理(UIはない=見えない ⇔ Activity)

アプリの4大構成要素(コンポーネント)の1つ

■ 別のアプリを使っている間にバックグラウンドで音楽再生

■ 別のActivityを操作している間にネットワークからデータを取得 など ⇒ 一度起動すると処理が終了するまで動作が継続する(他人に邪魔されない)

開始されたサービス

バインドされたサービス

startService()で起動するサービス

実装は簡単だが、Activityからの操作は サービスの起動と停止しか出来ない

bindService()で起動するサービス

実装は複雑だが、サービスの起動・停止 に加え、Activity・Service間の相互操 作も出来る

簡単だけど小機能

難しいけど多機能

中断されると問題のある 処理の実装に向いている

サービスはバックグラウンド処理ではあるが、実行はメインスレッドで行われる サービスはバックグラウンド処理ではあるが、実行はメインスレッドで行われる

™3/GH Ñ3

™3/GH Ñ3 h7= h7= È È ⌅r%&' ⌅r%&'

(49)

 ■ プロセス = 実行中のプログラム(1アプリに1プロセス ⇒ 他のアプリから独立)

 ■ スレッド = 処理を流すためのベルトコンベア(基本は1本:シングルスレッド)

OSがCPUに割り当てる最小の実行単位=関数 (Thread of Execution)

アプリ同士のやり取りは出来ず、1度に実行できる処理(関数)は1つだけ

 ■ アプリ間でやり取りをしたい場合 ⇒ プロセス間通信(IPC)を使う

 ■ 一度に複数の処理を実行したい場合 ⇒ 別スレッド(ワーカースレッド)を立てる  ■ アプリ間でやり取りをしたい場合 ⇒ プロセス間通信(IPC)を使う

 ■ 一度に複数の処理を実行したい場合 ⇒ 別スレッド(ワーカースレッド)を立てる

アプリA用 のプロセス

アプリB用 のプロセス

アプリC用 のプロセス

Androidシステム 計算する

時間の かかる処理 文字を出す

画像を出す 音を出す サービス

時間のかかる処理

別スレッド(ワーカースレッド) メインスレッド(UIスレッド)

時間のかかる処理を 行う場合に作成

⇒ 画面は操作できない 普段はこれしかない

(サービスもここで実行)

全体のメモリ管理 プロセス間(アプリ間)

のやり取り×

⇢✓<—⌅!%⇢⌅ ˙ R!

⇢✓<—⌅!%⇢⌅ ˙ R!

(50)

  Activityが閉じられても続く処理(中断されると問題のある処理)か?

Service内の メインスレッドで実行

YES

Service内の

別スレッドで実行

集中的な作業や

ブロック操作を行う処理か?

ネットワークへのアクセス・DBへの問い合わせ等

NO

Activity内の

別スレッドで実行 Activity内の

メインスレッドで実行

YES

集中的な作業や

ブロック操作を行う処理か?

ネットワークへのアクセス・DBへの問い合わせ等

NO

YES NO

Service IntentService

⇢7= È ⌅!%⇢ ˚ ⌅ ˙ R!⇡IJå^

⇢7= È ⌅!%⇢ ˚ ⌅ ˙ R!⇡IJå^

(51)

開始されたサービス バインドされたサービス

startService()呼び出し直後に 呼ばれるコールバック

⇒ Serviceの開始

bindService()呼び出し直後に 呼ばれるコールバック

⇒ IBinderの取得

自分で止めるか(stopSelf)

誰かに止めてもらう(stopService)まで動き続ける 自分で止めるか(stopSelf)

誰かに止めてもらう(stopService)まで動き続ける サービスがバインドされている間だけ実行

(unBindされたら自動的に破棄)

サービスがバインドされている間だけ実行

(unBindされたら自動的に破棄)

 画面がないのでライフサイクルは単純

™3/GH Ñ3

™3/GH Ñ3 ⇡)$(7$8⌃ ⇡)$(7$8⌃

(52)

startService()によって起動する簡単なサービス(開始・停止しか出来ない)

■ 一旦開始されると原則意図的に止めない限り止まらない

■ 呼び出し元に結果を返さない

Androidシステム

Activity

Service

onStartCommand() onStartCommand()

サービスの開始 startService()

サービスの開始 startService()

Intent Intent

Intent Intent

サービスの停止 stopService()

サービスの停止 stopService()

onDestroy() onDestroy()

呼び出し元に 結果を返さない

⇢ ¸˝ í\⌫7= È ⌅

⇢ ¸˝ í\⌫7= È ⌅ -™3/GH -™3/GH Ñ36 Ñ36 !%& !%&

(53)

bindService()によって起動する複雑なサービス

■ サービスがバインドされている間だけ実行(バインドが外れたら自動的に破棄)

■ 開始・停止だけでなく、Activity・Service間の相互操作、呼び出し元に結果も返せる

Binderクラスの拡張

  サービスが他のアプリ(プロセス)で使われているか?

(自分のアプリから自分以外のアプリのServiceを使いたいケースか?)

Messengerの利用 AIDLの利用

NO 別スレッド(マルチスレッド化)が必要か?

YES

NO YES

プロセス間通信

(IPC)

他のアプリ(プロセス) からの複数の要求を 同時に処理する必要があるか?

複雑なので Google先生は おすすめしていない

⇢S$ Rí\⌫7= È ⌅

⇢S$ Rí\⌫7= È ⌅ -™3/GH -™3/GH Ñ36 Ñ36 ! !

(54)

短い音と長い音では何が違うのか?

短い音

(sound)

長い音

(music)

使う道具(クラス)

SoundPool MediaPlayer

ファイルの大きさ

小さい 大きい

使い方

メモリにロード ストリーミング

(メモリにロードしない)

É4¢/BH ¢

É4¢/BH ¢ Õ Õ ˛ ˛ T ⌫⇠⇡⌦⇡K“ T ⌫⇠⇡⌦⇡K“

(55)

「MediaPlayer」より高機能なBGM・ビデオ再生用ライブラリ

⇢ ⇢ ˇ ˇ ¨B•x0A3/ ¨B•x0A3/ ! % & ' ! % & '

ExoPlayerがMediaPlayerより高機能な点

BGMのループ再生を途切れずに(シームレスに)やってくれる

「Dynamic Adaptive Streaming over HTTP(DASH)」や

「Smooth Streaming」といった高度なストリーミング技術に対応

 ■

実装が簡単だが低機能な「MediaPlayer」

(Androidフレームワーク内)

 ■

実装は複雑だが高機能な「ExoPlayer」

(オープンソース)

 ■

実装が簡単だが低機能な「MediaPlayer」 (Androidフレームワーク内)

 ■

実装は複雑だが高機能な「ExoPlayer」 (オープンソース)

単体のライブラリなので自分でバージョンコントロール・開発者 による拡張・修正が可能

(MediaPlayerはAndroidフレームワーク(SDK)に組み込まれており出来ない)

サポートされているファイルフォーマットが多い など

(56)

ˇ ¨B•x 0A3/

ˇ ¨B•x 0A3/ Õ Õ /3W /3W ( ⌃ ( ⌃ ˜ ˜ «\⌫ «\⌫ Dï† Dï†  

⇥ óíì Ø ⇤⌅⇧ ⇤K“

⇥ óíì Ø ⇤⌅⇧ ⇤K“

使い方9ステップ

ExoPlayerのライブラリをセット(build.gradleに依存関係設定)

「SimpleExoPlayer」のインスタンスを作成(初期化)

BGMを読み込むための「RawResourceDataSource」の設定

=> 「DataSource」は「InputStream」的なもの(BGMデータを読み込むためのクラス)

resフォルダ内のBGMのリソースIDをUriスキームに変換

  

=> ExoPlayerでの再生対象は全て一旦Uriスキームに変換される(rawresource://resourceId)

④で設定したUriから再生する部分(DataSpec)を設定し、

③で設定した「RawResourceDataSource」を開く

③で設定した「RawResourceDataSource」インスタンスを返す DataSource.Factoryの設定

ExoPlayerの再生対象となる「MediaSource」インスタンスの設定

  => DataSource.Factory(⑥で設定)・ExtractorFactory・Uri(④で設定)を使う

②で設定したSimpleExoPlayerに⑦で設定したMediaSourceを設定し再生

  => setPlayWhenReady(true):再生、setPlayWhenReady(false):一時停止、ループはsetRepeatMode()

使い終わったらSimpleExoPlayerインスタンスの破棄(release)+

RawResourceDataSourceを閉じる(close)

(57)

ˇ ¨B•x 0A3/

ˇ ¨B•x 0A3/ Õ Õ /3W /3W ( ⌃ ( ⌃ ˜ ˜ «\⌫ «\⌫ Dï† Dï†  

⇥ óíì Ø ⇤⌅⇧ ⇤K“

⇥ óíì Ø ⇤⌅⇧ ⇤K“

simpleExoPlayer.apply{

prepare(mediaSource)

repeatMode = REPEAT_MODE_ALL playWhenReady = true

}

val mediaSource =

ExtractorMediaSource

.Factory(dataSourceFactory)

.setExtractorFactory(MP3Extractor.FACTORY)

.createMediaSource(dataSourceUri)

val dataSourceUri = RawResource

.buildRawResourceUri (BGM

のリソース

ID )

val dataSourceFactory = DataSource.Factory{

return rawResourceDataSource

} val rawResourceDataSource

= RawResourceDataSource(this)

rawResourceDataSource .open(dataSpec) val dataSpec

= DataSpec(dataSourceUri)

(58)

■ File:ファイルの保存先の絶対パス

■ Uri : スキームが付与された特定の書式に変換されたファイルのパス

’leスキーム contentスキーム

Uri.fromFile()で取得可能

FileProvider(ContentProvider) で保存されたファイルのみ取得可能

他のアプリとの共有ファイルへは

「contentスキームのUri」経由でないとアクセスできない 他のアプリとの共有ファイルへは

「contentスキームのUri」経由でないとアクセスできない

File

/storage/emulated/0/Pictures/FOOTPRINT/image.jpg

Uri

Çleスキーム

Çle:///storage/emulated/0/Pictures/FOOTPRINT/image.jpg

content スキーム

content:// パッケージ名 .Çleprovider/external_Çles/

Pictures/FOOTPRINT/image.jpg

Uniform Resourse Identi’ers

APIレベル24(Android7.0)以降は原則使用不可

É4¢/BH ¢

É4¢/BH ¢ b^ ( b^ ( ⌃ ⌃ $⌃⇡ $⌃⇡ ⌥ ⌥ J J

h h .H .H x x 3 3 % % Ü/H Ü/H r r

(59)

ファイルを少しずつ(バイト単位で)読み込むための仕組み [Stream=小川]

一見きれいな画像も 実はただの数字の羅列!!

InputStream

画像全体を一度に取り込むと

メモリが足りなくなるので

バイト単位で少しずつ取り込む 1ビット(bit): 1桁の2進数

1バイト(byte)=8ビット

ビットマップ にデコード

(出典:CODINGEEK)

á 4§C5™5/302

á 4§C5™5/302 %& %& - - S$,⌅,◆= S$,⌅,◆= Á Á 6 6

(60)

効果音ファイルをrawフォルダに入れる

効果音ファイルをメモリにロードして

サウンドID(整数)を取得する

使い終わった音ファイルをメモリの上から後片付け

完成図

layout

説明書

kotlin

resフォルダの下に自分で作る

サウンドIDを使って効果音を鳴らす

loadメソッド loadメソッド

playメソッド playメソッド

releaseメソッド releaseメソッド

効果音を出すためのクラス:SoundPoolを準備する

(インスタンス化)

(≠リソースID)

onResumeに onResumeに

onPauseに onPauseに

⌦ ˛

⌦ ˛ -™BC4¢6 -™BC4¢6 T ⌫⇠⇡ T ⌫⇠⇡ ↵ ↵ ⌅ ⌅ ✓ ✓

(61)

™33∑D0/

™33∑D0/ ëqUa ëqUa ˛ ˛   K“ K“

h ✏⇣ ⇡ ⌘ ◆ Í = Á k ,<=⌃%◆ 8íì K“r h ✏⇣ ⇡ ⌘ ◆ Í = Á k ,<=⌃%◆ 8íì K“r

使い方6ステップ

Context経由でAudioManagerインスタンス取得 音楽再生時

(AudioManager.STREAM_MUSIC)

端末の最大ボリューム値の取得

SeekBarにsetOnSeekBarListernerをセット

③の引数のラムダ式内で

onProgressChangedメソッドを実装 し、SeekBarの現在値(progress)を取得

④で取得したprogressを②で取得した端末の 最大ボリューム値で換算

⑤で換算した端末の現在のボリューム値を①で

取得したAudioManagerにセット

参照

関連したドキュメント

日頃から製造室内で行っていることを一般衛生管理計画 ①~⑩と重点 管理計画

これは基礎論的研究に端を発しつつ、計算機科学寄りの論理学の中で発展してきたもので ある。広義の構成主義者は、哲学思想や基礎論的な立場に縛られず、それどころかいわゆ

本節では本研究で実際にスレッドのトレースを行うた めに用いた Linux ftrace 及び ftrace を利用する Android Systrace について説明する.. 2.1

このような情念の側面を取り扱わないことには それなりの理由がある。しかし、リードもまた

ASTM E2500-07 ISPE は、2005 年初頭、FDA から奨励され、設備や施設が意図された使用に適しているこ

しかし , 特性関数 を使った証明には複素解析や Fourier 解析の知識が多少必要となってくるため , ここではより初等的な道 具のみで証明を実行できる Stein の方法

キャンパスの軸線とな るよう設計した。時計台 は永きにわたり図書館 として使 用され、学 生 の勉学の場となってい たが、9 7 年の新 大

○池本委員 事業計画について教えていただきたいのですが、12 ページの表 4-3 を見ます と、破砕処理施設は既存施設が 1 時間当たり 60t に対して、新施設は