この記事はレコチョク Advent Calendar 2022の4日目の記事となります
はじめに
はじめまして、レコチョク新卒一年目の深沢と申します。10月よりAndroid開発グループに配属され、現在Android開発について日々勉強しています。
最近気になっている音楽トピックは「THE LAST ROCKSTARS結成」です。高校時代好きでよく聴いていた
方々で結成されたバンドなので、これからの活動を本当に楽しみにしています。
本記事では初学者の私が10月から1ヶ月で学んだAndroid開発の内容とそれらについての簡単な所感をまとめました。Androidの開発を全く行ったことがない人間が1ヶ月でどれだけ学ぶことができたのか、何に躓いてどう感じているのか、などリアルな声を届けたいと思います。
これからAndroid開発を行おうとしている方、今度Android開発について教える機会があるが、初学者はどう感じているのかを知りたい方などにこの記事が参考になればと思います。
筆者スペック
はじめに、Android開発に携わるまでの私のプログラミング関連のスペックについて簡単にまとめます
- 四年制大学学部卒。理系学部におり、1,2年生の頃基本的なプログラミングの講義あり(Ruby,C)
- 5月から9月まで社内エンジニア研修を経験。主にPHPを学ぶ
- Advent Calendar 2021で先輩がまとめてくださっています。研修内容は大体同じです。
- 上記の研修にて3日間のAndroid研修あり。簡単なレイアウトを作成したり、画面遷移処理を行う
学習環境
私が勉強している環境は以下のとおりです
- 実装にはプレイグラウンドとAndroid Studioを使用
- プレイグラウンド:Kotlinのコードを動かせるブラウザページ
- Android Studio:Googleが提供しているAndroidアプリ開発用の統合開発環境(IDE)
- わからないことがあった場合は、グループの先輩に聞ける状態
個人的難易度
学んだ内容をまとめるにあたって、今回個人的難易度というものを設定しました。以下の基準に沿って学んだ内容それぞれに5段階で難易度をつけています。読者の皆様の参考になりますと幸いです。
- 難易度1: 元々知っている内容であり、調べなくても自力で問題なく使える状態
- 難易度2: Android特有のものというような理由で初めは手こずったが、現在は難易度1と同等に扱える状態
- 難易度3: 調べれば、自力で実装できる状態
- 難易度4: 完全には理解できていないが、なんとなくの処理の流れはつかめている状態
- 難易度5: 内容について半分程度しか理解できておらず、勉強途中の状態
学んだ内容と所感
今回私は主にコードラボ というGoogleが作成したAndroid開発に関する教材を用いて勉強をしました。学んだ単元ごとにコードラボのURLのを貼り付けていますので、細かい内容などはそちらをご確認ください。
※今回、学んだ内容と所感について時系列順で並べたため、使用しているサイトや作成しているアプリが行ったり来たりしています。ご了承ください。
変数・関数について/個人的難易度: 1
変数や関数の設定方法などをコードラボで学びました。そして print()関数を使い、アスキーアートのようなものを作成しました。PHP研修で学んだ内容と似ていたので、特に躓くことなく進めることができました。
// println()で作成した絵 ,,,,,,,,,,,,,,,,,,,,,,,, |||||||||||||||||||||||| ========================== @@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@ |
学んだこと
- テキストを出力するときはprintln()を使用し、 "で囲む。
-
print()内でテキストと変数を同時に使用するときは
${}で変数を囲む。
- 例: println(テキスト:${変数名})
- valを用いて変数を作成する。この値は一度設定すると変更ができない。
- 一連の手順を繰り返すにはrepeat()を使用。
- 例: repeat (23) { print("%") }
コードラボ
Android Studioを用いて画像や文字を配置/個人的難易度: 2
TextViewや ImageViewを用いて簡単な画面を作成しました。Android Studioに慣れていなかったため、配置方法などを覚える時間は少しかかりましたが、実装が視覚的にわかりやすく、難なく対応することができました。
学んだこと
- TextViewはアプリ内でテキストを表示するためのUI要素。フォント、テキストサイズ、色などの属性を設定できる。
- ConstraintLayoutは他のUI要素のコンテナのこと。
- Viewは ConstraintLayout内で水平方向と垂直方向に制約する必要がある。
- ImageViewはアプリ内で画像を表示するためのUI要素。アプリを利用しやすくする内容説明を設定する。
- ユーザーに表示するテキストは文字列リソースに抽出して、翻訳しやすくする。
コードラボ
オブジェクト指向とクラスについて/個人的難易度: 4
ボタンを押すとランダムなサイコロの出目が出力されるというアプリ(以下サイコロアプリ)の作成を通してオブジェクト指向、クラスについて勉強しました(この章ではプレイグラウンドのみ使用)。
Diceクラスを見様見真似で作りはしたのですが、クラスにどういう情報が入るべきなのか、そもそもクラスとは何か?というところから早速躓いていました。当時よりは大分理解が進んだものの、クラスにどんな情報が入っているのかをコードから読み取るのは未だに苦戦しています。
また、個人的にはコンストラクタの意味を理解するのにかなり時間がかかりました。これからも勉強して理解を深めていきたいと思います。
fun main() { val myFirstDice = Dice(6) println("Your ${myFirstDice.numSides} sided dice rolled ${myFirstDice.roll()}!") val mySecondDice = Dice(20) println("Your ${mySecondDice.numSides} sided dice rolled ${mySecondDice.roll()}!") } // クラス定義 class Dice (val numSides: Int) { fun roll(): Int { return (1..numSides).random() } } // 実行結果 Your 6 sided dice rolled 2! Your 20 sided dice rolled 3! |
学んだこと
- IntRangeでrandom()を呼び出して、乱数を生成する。
- 例: (1..6).random()
- クラスはオブジェクトの設計図のようなもの。オブジェクトの特性と動作は変数や関数として実装できる
- インスタンスとはオブジェクト(多くの場合、物体)を表す。オブジェクトのアクションを呼び出して、属性を変更できる。作成するときは、クラスに値を指定できる。
- 例: class Dice(val numSides: Int)のインスタンス作成例は Dice(6)
コードラボ
ボタンを押したときの動作(Viewの情報を呼び出して処理を追加)/ 個人的難易度: 2
Android Studioを用いてサイコロアプリを作成し、画像のROLLボタンを押すとランダムな出目が数字で出力されるようにコードを書きました。Viewを呼び出すという考え方は今回初めて学んだ内容でしたが、今では調べることなく使えるまでになりました。
// ボタンを押したらrollDice()を動かす val rollButton: Button = findViewById(R.id.button) rollButton.setOnClickListener { rollDice() } // rollDice()の定義 private fun rollDice() { val dice = Dice(6) val diceRoll = dice.roll() val resultTextView: TextView = findViewById(R.id.textView) resultTextView.text = diceRoll.toString() } |
学んだこと
- AndroidアプリにButtonを追加する。
- Toastでポップアップメッセージを表示させる。
- setOnClickListener()を使用して、ボタンがクリックされたときの動作を追加する。
- アプリの実行中に TextViewなどのUI要素のメソッドを呼び出して、画面を更新できる。
コードラボ
条件分岐/個人的難易度: 2
サイコロアプリ内でサイコロの出目が特定の数字のときにメッセージが出力されるようなコードをプレイグラウンドで作成しました。条件分岐の書き方は研修で学んだPHPと少し違いましたが、考え方などの大枠は同じであったため、スムーズに進めることができました。
fun main() { val myFirstDice = Dice(6) val rollResult = myFirstDice.roll() val luckyNumber = 4 // whenで条件分岐 when (rollResult) { luckyNumber -> println("You won!") 1 -> println("So sorry! You rolled a 1. Try again!") 2 -> println("Sadly, you rolled a 2. Try again!") 3 -> println("Unfortunately, you rolled a 3. Try again!") 5 -> println("Don't cry! You rolled a 5. Try again!") 6 -> println("Apologies! You rolled a 6. Try again!") } } class Dice(val numSides: Int) { fun roll(): Int { return (1..numSides).random() } } // 実行結果 You won! / Don't cry! You rolled a 5. Try again! |
学んだこと
- 一部の命令を実行するための条件は ifを使用して、設定する。
- whenを使用すると、コンパクトにコードを書ける。
コードラボ
アプリに画像を追加してボタンを押すと変更されるように修正/個人的難易度: 3
Android Studioを用いたサイコロアプリに画像を追加し、より使いやすいアプリに修正しました。条件分岐や画像の貼り付けなど今まで学んだことが沢山出てきたため、骨のある内容でした。出目がランダムにならないなど、思い通りの挙動にならず躓いた部分もありましたが、調べて解決することができました。
学んだこと
- setImageResource()を使用して、ImageViewに表示される画像を変更する。
コードラボ
ログ・デバッグ/個人的難易度: 3
デバッグを出力する方法、ログで確認する方法を学びました。エラー文を探し、原因が書いてある部分を見つけることはできるのですが、その原因の意味を調べきれず先輩に聞いてしまうことが多々あります。今後経験値を増やして自力でデバッグできるように精進していきます。
// Logcat一部抜粋。ここからエラーの原因等を突き止めます。 Process: com.example.debugging, PID: 14896 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.debugging/com.example.debugging.MainActivity}: java.lang.NullPointerException: findViewById(R.id.hello_world) must not be null at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7656) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) Caused by: java.lang.NullPointerException: findViewById(R.id.hello_world) must not be null at com.example.debugging.MainActivity.onCreate(MainActivity.kt:14) |
学んだこと
- デバッグとは、コードのバグをトラブルシューティングするプロセスのこと。
- ログを使用すると、様々なログレベルとタグを含むテキストを出力できる。
- スタックトレースを読むと、クラッシュの原因となった関数の行番号などが得られる。
コードラボ
クラス継承について/個人的難易度: 3
階層やクラスを継承する意味などを学んだあと、実際にプレイグラウンドでコードを書きました。クラスを継承する理由やメリットは理解できましたが、実装方法に慣れるのが大変でした。
型指定( abstract val buildingMaterial: String)とクラス継承( class SquareCabin : Dwelling(3))の表記の違いが全くわからず、よく見てみるとスペースの数が違うということにようやく気がついた、という感じでした。
fun main() { val squareCabin = SquareCabin(6) with(squareCabin) { println("\nSquare Cabin\n============") println("Capacity: {capacity}") println("Material: ${buildingMaterial}") println("Has room? ${hasRoom()}") } } // 抽象クラス定義 abstract class Dwelling(private var residents: Int) { abstract val buildingMaterial: String abstract val capacity: Int fun hasRoom(): Boolean { return residents < capacity } } // クラス継承 class SquareCabin(residents: Int) : Dwelling(residents) { override val buildingMaterial = "Wood" override val capacity = 6 } // 実行結果 Square Cabin ============ Capacity: 6 Material: Wood Has room? false |
学んだこと
- クラス階層は子が親クラスから機能を継承するクラスのツリーである。プロパティと関数はサブクラスによって継承される。
- 機能の一部がサブクラスによって実装されるため、 abstractクラスをインスタンス化することはできない。
- withを使用して、同じオブジェクトインスタンスに対して複数の呼び出しができる。
- kotlin.mathライブラリから機能をインポートし、使用する方法。
コードラボ
XMLコードでレイアウトを作成/個人的難易度: 2
チップの計算を行うというアプリ(以下チップ計算アプリ)の作成を通じて、XMLコードのみでのレイアウト作成を行いました。
GUIでレイアウトを設定することに慣れつつあったため、初めは難しく感じました。コード量も多いと感じたので、精神的ダメージも少なからず受けました。しかし、次第にコードでのレイアウト作成にも慣れ、今ではコードのみで書くことが多くなりました。 app:layout_constraintLayoutなどの新しい考え方はあったものの、そこまで難しいとは感じませんでした。
今では位置関係が把握しやすいので、コードでレイアウトを作成することのほうが多いです。
<!--TextViewをXMLコードのみで設定--> <TextView android:id="@+id/imageView" android:layout_width="160dp" android:layout_height="200dp" android:contentDescription="@null/TODO" android:importantForAccessibility="no" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:srcCompat="@drawable/dice_1" /> |
学んだこと
- XMLはテキストを整理する方法のひとつであり、タグ・要素・属性で構成されている。
- EditTextを使用して、ユーザーがテキストを入力または編集できるようにする。また、そのフィールドに入力すべき内容を示すヒントを表示できる。
- android:inputType属性を指定して、ユーザーが EditTextに入力できるテキストの種類を制限できる。
- RadioButtonを使用して、RadioGroupでグループ化する。 RadioGroupは縦向きか横向きかを選択できる。また、最初に選択する RadioButtonを指定できる。
- Switchを使用して、ユーザーが2つのオプションを切り替えられるようにする。
- ConstraintLayoutのそれぞれの子には垂直方向と水平方向の制約が必要。
- 制約属性の名前は layout_constraint_toOfの形式を取る。
- viewの幅を ConstraintLayoutの幅と同じにするには viewの始端と親の始端の間、 viewの終端と親の終端の間にそれぞれ制約を設定し、幅を 0dpに設定する。
コードラボ
チップ計算アプリ作成を通してkotlinで計算処理を行う/個人的難易度: 3
calculateTip()という関数を作り、計算処理を記述しました。
どういう実装にするべきかを調べたり先輩に相談することはありました。しかし、関数作成の流れ自体は今までも行ってきたものと似ていたため、スムーズに行うことができました。処理の流れを考えながら作成すること自体が好きなので、考え方の引き出しを増やしながら今後どんどん実装していきたいと思います。
private fun calculateTip() { val stringInTextField = binding.costOfService.text.toString() val cost = stringInTextField.toDoubleOrNull() if (cost == null) { binding.tipResult.text = "" return } val tipPercentage = when (binding.tipOptions.checkedRadioButtonId) { R.id.option_twenty_percent -> 0.20 R.id.option_eighteen_percent -> 0.18 else -> 0.15 } var tip = tipPercentage * cost if (binding.roundUpSwitch.isChecked) { tip = kotlin.math.ceil(tip) } val formattedTip = NumberFormat.getCurrencyInstance().format(tip) binding.tipResult.text = getString(R.string.tip_amount, formattedTip) } |
学んだこと
- ビューバインディングを使用すると、アプリ内のUI要素を操作するコードを簡単に書くことができる。
- RadioGroupの checkedRadioButtonId属性を使用して、どの RadioButtonが選択されているか確認する。
- NumberFormat.getCurrencyInstance()を使用して、数値を通貨として設定する。
- %sなどの文字列パラメータを使用して、他の言語に簡単に翻訳できる動的な文字列を作成する。
コードラボ
テーマについて/個人的難易度: 3
アプリテーマの色を変更方法やダークテーマの意義について勉強しました。内容自体はそこまで難しくはありませんでしたが、覚えることが多く、現在も調べないと実装できないため、個人的難易度は3としました。
<!--colors.xml--> <!--使用する色をここに書き込む--> <?xml version="1.0" encoding="utf-8"?> <resources> <color name="black">#FF000000</color> <color name="white">#FFFFFFFF</color> <color name="green">#1B5E20</color> <color name="green_dark">#003300</color> <color name="green_light">#A5D6A7</color> <color name="blue">#0288D1</color> <color name="blue_dark">#005B9F</color> <color name="blue_light">#81D4FA</color> </resources> |
<!--values/themes.xml--> <!--実際の配色を指定--> <resources xmlns:tools="http://schemas.android.com/tools"> <style name="Theme.TipTime" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> <item name="colorPrimary">@color/green</item> <item name="colorPrimaryVariant">@color/green_dark</item> <item name="colorOnPrimary">@color/white</item> <item name="colorSecondary">@color/blue</item> <item name="colorSecondaryVariant">@color/blue_dark</item> <item name="colorOnSecondary">@color/black</item> <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item> </style> </resources> |
学んだこと
- Material Color Tool を使用して、アプリテーマの色を選択する。
- color.xmlファイルでカラーリソースを宣言し、再利用しやすくする。
- ダークテーマを使用すると、消費電力が少なくなり、アプリが暗い場所でも読みやすくなる。
コードラボ
アプリの見た目を整える/個人的難易度: 4
チップ計算アプリの以下について変更しました。
- マテリアルコンポーネント( TextInputLayout, SwitchMaterial)
- アイコン変更
- テーマカラーを変更
- スタイル( style.xmlを作成し、全体についての制約を記述)
- スクロール可能状態へ変更
デザインについての書き方が一気に増えたため、とても難しく感じました。入力欄について位置関係やidなど欄についての制約をする部分( TextInputLayout)と入力する内容についての制約を行う部分( TextInputEditText)の違いや、スタイルとテーマの違いを理解することに躓きました。まだあまり使用できていないので、今後実際に使いながら慣れていきたいと思います。
<!--入力欄を修正--> <com.google.android.material.textfield.TextInputLayout android:id="@+id/cost_of_service" android:layout_width="160dp" android:layout_height="wrap_content" android:hint="@string/cost_of_service" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> <com.google.android.material.textfield.TextInputEditText android:layout_width="match_parent" android:layout_height="wrap_content"/> </com.google.android.material.textfield.TextInputLayout> |
学んだこと
- マテリアルデザインガイドラインに沿って可能な限り、マテリアルデザインコンポーネントを使用し、カスタマイズする。
- アイコンを追加することにより、アプリの各要素がどのように機能するかについてユーザーに視覚的な手がかりを与える。
- エッジケース(デバイスを回転させて、横向きの画面にアプリを表示するなど)でアプリをテストし、必要に応じて改善する。
コードラボ
リスト/個人的難易度: 2
Listと MutableListの違いや、内容の追加、削除方法などを学びました。書き方の違いはありますが、大枠の内容自体はPHPと同じでしたのでそこまで苦労することなく理解ができました。
// Listについて fun main() { // リスト作成 val numbers = listOf(1, 2, 3, 4, 5, 6) // リストの中身 println("List: $numbers") // リストの要素の数 println("Size: ${numbers.size}") } // 実行結果 List: [1, 2, 3, 4, 5, 6] Size: 6 |
// MutableListについて fun main() { // 空のリストを作成 val entrees = mutableListOf<String>() println("Entrees: $entrees") // add()を使用して要素を追加 println("Add noodles: ${entrees.add("noodles")}") println("Entrees: $entrees") println("Add spaghetti: ${entrees.add("spaghetti")}") println("Entrees: $entrees") // addAll()を使用して複数の要素を一度に追加 val moreItems = listOf("ravioli", "lasagna", "fettuccine") println("Add list: ${entrees.addAll(moreItems)}") println("Entrees: $entrees") // remove()を使用して要素を削除 println("Remove spaghetti: ${entrees.remove("spaghetti")}") println("Entrees: $entrees") println("Remove item that doesn't exist: ${entrees.remove("rice")}") println("Entrees: $entrees") // removeAt()を使用して要素番号指定で削除 println("Remove first element: ${entrees.removeAt(0)}") println("Entrees: $entrees") // clear()を使用してリストの中身をすべて消去 entrees.clear() println("Entrees: $entrees") // isEmpty()より要素が空であるか確認 println("Empty? ${entrees.isEmpty()}") } // 実行結果 Entrees: [] Add noodles: true Entrees: [noodles] Add spaghetti: true Entrees: [noodles, spaghetti] Add list: true Entrees: [noodles, spaghetti, ravioli, lasagna, fettuccine] Remove spaghetti: true Entrees: [noodles, ravioli, lasagna, fettuccine] Remove item that doesn't exist: false Entrees: [noodles, ravioli, lasagna, fettuccine] Remove first element: noodles Entrees: [ravioli, lasagna, fettuccine] Entrees: [] Empty? true |
学んだこと
- リストは特定の型の要素を順序立てて集めたもの。
- インデックスは要素の位置を反映する整数の位置
- 例: myList[2]
- リストには Listと MutableListの2種類がある。
- Listは読み取り専用であり、初期化後は変更できない。ただし、 sorted()や reversed()などのオペレーションを適用すると、元のリストを変更せずに新しいリストを返すことができる。
- MutableListは要素の追加、削除、変更などを作成後に行うことができる。
- addAll()を使用して、可変リストにアイテムのリストを追加できる。
- whileループを使用して、式が falseを返し、ループを終了するまでコードのブロックを実行する。
- forループを使用してリストの全アイテムを反復処理する。
- vararg修飾子を使用すると、可変長引数を関数やコンストラクタに渡すことができる。
コードラボ
RecyclerView/個人的難易度: 5
AffirmationアプリというRecyclerViewに文章を表示するアプリを作成しました。AdapterやViewHolderなどRecyclerViewを実装するために必要なものが多く、それらの理解に時間がかかりました。特にAdapterの実装は関数をオーバーライドしたり、アダプタをMainActivityで設定したりなど、やらなければいけないことが沢山あるので初学者にはかなり重い内容だと思います。
// 作成したItemAdapter class ItemAdapter( private val context: Context, private val dataset: List<Affirmation> ) : RecyclerView.Adapter<ItemAdapter.ItemViewHolder>() { // ビューホルダー作成 class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { // list_item.xmlで定義したIDのビューを代入 val textView: TextView = view.findViewById(R.id.item_title) //val imageView: ImageView = view.findViewById(R.id.item_image) } // onCreateViewHolder()をオーバーライド override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { val adapterLayout = LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false) return ItemViewHolder(adapterLayout) } // onBindViewHolder()をオーバーライド override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { val item = dataset[position] holder.textView.text = context.resources.getString(item.stringResourceId) } // getItemCount()をオーバーライド override fun getItemCount() = dataset.size } |
学んだこと
- RecyclerViewウィジェットを使用すると、データのリストを表示できる。アダプタパターンを使用して、データの調整と表示を行う。
- ViewHolderはアダプタパターンを使用して、データの調整と表示を行う。
- RecyclerViewは組み込みの LayoutManagersに付属している。項目の配置を LayoutManagersに委譲する。
- アダプタの実装は次のように行う。
- アダプタ用に新しいクラスを作成する。
- 単一のリスト項目ビューを表す ViewHolderクラスを作成する。 RecyclerView.ViewHolderクラスを拡張する。
- アダプタクラスを RecyclerView.Adapterクラスを拡張するよう書き換える。
- メソッド getItemCount(), onCreateViewHolder(), onBindViewHolder()をアダプタ内に実装する。
コードラボ
RecyclerViewに画像を追加/個人的難易度: 3
RecyclerViewの実装を除いて画像を追加することのみを考えると、画像を取得し、設定するという内容ですので、そこまで難しくはありませんでした。しかし、カードビューという新しいものも出てきますので、覚えることは沢山ありました。
学んだこと
- RecyclerViewで追加コンテンツを表示するには、基になるデータモデルクラスとデータソースを変更する。次に、リストアイテムのレイアウトとアダプタを更新して、そのデータをビューに設定する。
- リソースアノテーションを用いて、適切なタイプのリソースIDがクラスのコンストラクタに渡されるようにする。
- マテリアルカードにコンテンツを表示するにはMaterialCardViewを使用する。
コードラボ
おわりに
初学者の私が1ヶ月で学んだ内容についてまとめました。こう並べると結構沢山の内容について勉強したなぁと思うとともに、まだまだ学ぶことが沢山あるので頑張ろうとも思います。大変なこともあると思いますが、私とともにAndroid開発頑張っていきましょう!
最後まで読んでいただきありがとうございました!
明日のレコチョク Advent Calendarは5日目【連載企画1日目】ウェブ画面開発者の頭の中を見てみよう!〜準備編〜です。お楽しみに!