目次
Android開発(kotlin)最初の一歩。独特の用語と基本構造を学ぶ
Androidアプリ開発を勉強する第一歩として基本的な用語とか構造を知るところからやるべきと思い、Android Studioで新規プロジェクトの「Basic Activity」選択で生成されたソースをサンプルに確認したことを整理してみました。
なお、確認に使用したのは「Android Studio Dolphin | 2021.3.1 Patch 1」です。
用語の確認
Androidアプリケーションには独特の用語がたくさんでてきます。
それを把握しないで進めるのは効率が悪いので、先に簡単に調べました。
- Activity:Androidアプリの画面に相当
- Fragment:画面におけるユーザインタフェースや挙動に相当
- View:テキストボックスやボタンのような画面を構成する部品に相当
- binding:Fragmentやviewを紐づける仕組
- lifecycle:作成、停止などの処理のタイミングで呼ばれるコールバック的な仕組
さすがに、これだけだとわからないので、もう少し掘り下げます。
ActivityとFragmentとView
スマホの画面全体が「Activity」。
その上に別に定義した「Fragment」を差し替えて画面遷移を表現する。
その「Fragment」にはボタンやテキストなどの「View」を配置する。
そういうイメージです。
このうち単独で表示できるのは「Activity」だけです。
なので「Fragment」は必ず「Activity」の子として存在する必要があります。
ですが、「Fragment」は特定の「Activity」から独立した存在で、1つの「Fragment」を複数の「Activity」で使いまわすことも可能です。
binding(バインディング)
Fragmentとかviewとかを紐づける仕組みがバインディングです。
これの説明は実際のソースを見たほうがわかりやすそうに思うので、ここではこれくらいにして後ろでふれます。
lifecycle(ライフサイクル)
画面遷移や、アプリキルなどの様々な動作の都度「Activity」の生成と消滅、子である「Fragment」の場合だと「Activityに付く・取り外す」を繰り返します。
その変化の都度、コールバック的に呼び出されるメソッドが定義されていて、それがライフサイクルです。
なので「Activity」も「Fragment」もlifecile(ライフサイクル)を持ちます。
activityの主要なライフサイクルの例は以下です。
- onCreate() :Activityの生成
- onStart() :Activityの状態の開始
- onResume() :前面に表示されユーザとのやりとりが可能になる直前
- onPause() :アプリがバックグラウンドに移動した(一時停止)
- onStop() :Activityが非表示になり停止した
- onRestart() :Activityの再表示
- onDestroy() :Activityが破棄される
Fragmentの主要なライフサイクルだと以下です。
- onAttach() :Fragmentが取り付けられた
- onCreateView() :Fragment内のUIを描画する
- onActivityCreated() :Activity内のonCreate()が完了した
- onDestoyView() :FragmentのUI(View)が破棄された
- onDetach() :Fragmentが取り外された
ほかにもたくさん種類はありますが、ここではこちらのリンクを貼るだけにします。
つまり、Androidアプリというのは、この「lifecycle(ライフサイクル)」が呼び出されたタイミングごとに適切な処理を書いて動かすというイメージなのですね。
新規プロジェクト「Basic Activity」を見ていく
前回インストールしたとき、動作確認用に新規プロジェクト「Basic Activity」を生成して、上記の基本知識を生成されたソースでどうなっているか見てみました。
生成されたプロジェクトのフォルダ構成
まず、生成されたプロジェクトのトップレベルのフォルダ構成の確認です。
manifestフォルダには「AndroidManifest.xml」があります。
JavaフォルダにActivityやFragmentのクラスを定義したソース(kotlin)があります。
resフォルダに画面レイアウトや画面に表示する部品および表示テキストなど、画面構成する要素を定義したxmlファイルがあります。
特徴:「main()」関数がない
たいていのプログラミング言語だとプログラムの起動時に最初に実行されるmainメソッドというメソッドがあり、使用する「kotlin」言語にも「main()」メソッドはあるのですけど、まず、それが見当たりません。
このサンプルでは「MainActivity」が呼び出されmainの代わりをしています。
どのActivityが最初に呼ばれるかは「AndroidManifest.xml」に記載されています。
特徴:コンストラクタがない
クラス生成時に最初に実行される仕組みとしてコンストラクタがあります。
でも、MainActivityクラスでコンストラクタを探しましたが、これもありません。
MainActivityクラスが継承するAppCompatActivityクラスで定義されているライフサイクルのメソッドをオーバーライドするのですが、その中「onCreate()メソッド」がコンストラクタのような働きをします。
特徴:画面構成や部品もXMLファイルで定義
MainActivityやFragmentクラスのソースを見て違和感があるのは、どこにも表示しているボタンなどの部品に関する記述がないことです。
どこにあるのかと探すと、Androidでは参照される部品や出力文字列などは「res」フォルダの「xml」ファイルに定義されていました。
実は、resフォルダの「nav_graph.xml」に以下のような記載があるのですが、これによって「FirstFragment」クラスのレイアウトはXMLファイル「fragment_first]」にあるよということが定義されています。
android:id="@+id/FirstFragment"
android:name="com.example.hello.FirstFragment"
android:label="@string/first_fragment_label"
tools:layout="@layout/fragment_first"
それで「layout」フォルダにある「fragment_first.xml」の中身をみると
などと書いてあります。
これがFragmentで表示している部品(View)の定義です。
ここに例えば、Buttonだとidが「button_first」になっているので、Fragmentクラスの中で以下のように「binding」を介して参照できています。
binding.buttonFirst.setOnClickListener {
findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
}
特徴:binding(バインディング)の実装方法
前にでてきた「binding」変数が文字通り、バインディングの仕組みを使う部分です。
この「binding」はFragmentクラスの中で以下のように定義されています。
private var _binding: FragmentFirstBinding? = null
private val binding get() = _binding!!
このように宣言した「_binding」変数に対して、ライフサイクル「onCreateView()」の中で以下のように紐づけられてます。
_binding = FragmentFirstBinding.inflate(inflater, container, false)
return binding.root
そして「onDestroyView()」の中では以下のようにしてます。
_binding = null
上記では「_binding」変数に実体(ここではFragmentFirstBinding)を入れています。
こうすることで、「binding」から参照できるようになるということです。
もちろん、_bindingを直接参照することもできます。
ですが、その時には「?」をつける必要があるので、上記のようにbindingを定義して、参照するときに自動で呼ばれる「get」に対して「_binding!!」という書き方で「_binding」を強制し「binding.titleText.text = title」と書けるようにしています。
ちなみに、
private var _binding: FragmentFirstBinding? = null
private val binding get() = _binding!!
のような書き方は「バッキングプロパティ」というやり方とのこと。
とまあ・・この辺りはわかったのですが、実は僕にはまだ「FragmentFirstBinding」なる実体がどこにあるのかはわかっていません。
Fragmentのソースで「import com.example.hello.databinding.FragmentFirstBinding」していますが、Android Studioからは見えないので、現時点で謎のままです。
また、調べてわかったら追記しようと思います。
特徴:画面遷移の実態もXMLファイルで定義
Basuc Activityをコンパイル・実行すると最初に「FirstFragment」で定義された画面が表示され表示されたボタンを押すと「SecondFragment」で定義の画面に遷移します。
逆もあるので、
- FirstFragmentの「次へ」ボタンを押すとSecondFragmentへ遷移。
- SecondFragmentの「前へ」ボタンを押すとFirstFragmentへ遷移。
となります。
ボタンがトリガーなので、各Fragmentのソースには
binding.buttonFirst.setOnClickListener {
findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
}
とか
binding.buttonSecond.setOnClickListener {
findNavController().navigate(R.id.action_SecondFragment_to_FirstFragment)
}
とあるのがトリガーで中に書かれているのが画面遷移のアクションです。
Navigationという仕組みが使われているのですが、実は[ Basic Activity ]は2枚のFragment、とそのFragmentの遷移をNavigationで実装したサンプルとのことです。
では。
上記の「findNavController().navigate()」で実行されるアクションはどこで定義されているのか?なのですが、それはクラスではなく、resフォルダの「nav_graph.xml」にありました。
例えば、FirstFragmentの定義には
<action
android:id="@+id/action_FirstFragment_to_SecondFragment"
app:destination="@id/SecondFragment" />
と書かれています。
上の「action_FirstFragment_to_SecondFragment」がidで、下の「app:destination」が意味通り「遷移先」のFragmentのidを指定しています。
このように定義しておいて、actionのidを指定して「 findNavController().navigate(R.id.action_SecondFragment_to_FirstFragment)
とするだけで画面遷移できる・・という仕組みです。
特徴:R.idという謎記述
引用した蒸気のソースを見ていると「R.id」という謎記述がでてきます。
この「 R」 は Resource(リソース)の頭文字です。
Rクラスはコンパイル時に自動生成・更新されます。
res フォルダにある全ての要素に ID をつけて管理するのが、R クラスです。
要素に対して MainActivity.kt から変更を加える場合は、id を使って紐づける必要があって、xxxxxのidを参照するのに「R.id.xxxxx」みたいに書きます。
なので、前の例の「R.id.action_SecondFragment_to_FirstFragment」は「nav_graph.xml」ファイルに定義されている「action_SecondFragment_to_FirstFragment」というIDのactionを参照しているということになります。
resフォルダ以下は複数のフォルダ・ファイルに分かれて定義が書かれているので、それぞれの定義がどのファイルに記述されているかなどを意識するのは大変ですからね、それらをまとめた「R」クラスを介することで、そこを簡素化している・・ということなんだと僕は理解しています。
以上、調べたことをざっと書きました。
まだまだ、これだけではサンプルを動かす程度のことしかできず、ちょっと改造しようとしても躓きまくりではありますが、なんとなく、アウトライン的な部分はわかってきたような気がしてます。
今回はこのへんで。
ではでは。