Androidことはじめ集

## はじめに
サクッとアプリを書きたい時によく使うライブラリを使えるようになるまでをTips的にまとめときます。

いちいち検索するの面倒だからまとめた！ってだけなので、詳しく知りたい人はググって他の記事を見たほうがいいと思います。

## Navigation
### 準備
appの`build.gradle`

```build.gradle
implementation "androidx.navigation:navigation-fragment-ktx:2.1.0-alpha06"
implementation "androidx.navigation:navigation-ui-ktx:2.1.0-alpha06"
```

### `navigation`resourceファイルの作成
`res/navigation/nav_graph.xml`つくる

```nav_graph.xml
<?xml version="1.0" encoding="utf-8"?>
<navigation
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/nav_graph"
        app:startDestination="@id/main_fragment">

    <fragment
            android:id="@+id/main_fragment"
            android:name="<package>.MainFragment"
            android:label="fragment_main"
            tools:layout="@layout/fragment_main"/>

</navigation>
```

### ActivityにFragment表示

```activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".ui.MainActivity">

    <fragment
            android:id="@+id/nav_host_fragment"
            android:layout_height="match_parent"
            android:layout_width="match_parent"
            android:name="androidx.navigation.fragment.NavHostFragment"
            app:navGraph="@navigation/nav_graph"
            app:defaultNavHost="true"
    />

</androidx.constraintlayout.widget.ConstraintLayout>
```

### Tips
#### 遷移したい

```Fragment.kt
findNavController().navigate(R.id.action_main_fragment_to_second_fragment)
```

#### 親Activityから操作したい

```Activity.kt
// layoutのfragmentを指定
findNavController(R.id.nav_host_fragment).navigate(R.id.action_main_fragment_to_second_fragment)
```

## databinding
### 準備
appの`build.gradle`

```build.gradle
android{
  ...
  dataBinding {
    enabled = true
  }
}
```

### レイアウト
`<layout></layout>`で囲む

```fragment.xml

<layout>

// かっこいいレイアウト

</layout>

```

### インスタンス化
#### Fragment

```Fragment.kt
val binding = inflate(
            inflater,
            R.layout.fragment_main,
            container,
            false
        ) as FragmentMainBinding
```

#### Activity

```Activity.kt
val binding = DataBindingUtil.setContentView(this, R.layout.activity_main) as ActivityMainBinding
```

## Room
### 準備
appの`build.gradle`

```build.gradle
implementation "androidx.room:room-runtime:2.2.0-alpha01"
implementation "androidx.room:room-ktx:2.2.0-alpha01"
annotationProcessor "androidx.room:room-compiler:2.2.0-alpha01"
kapt "androidx.room:room-compiler:2.2.0-alpha01"
```

### 保存するアイテムの`Entity`クラスの作成

`data class`に`@Entity`アノテーション付いただけです
`@PrimaryKey`で主キーパラメータを指定できて、`autoGenerate = true`オプションで主キーの値がデータベース上に重複してた場合は自動で値を付与してくれます。
ちなみに主キーは整数型限定っぽいです。

```ItemEntity.kt
@Entity
data class ItemEntity(
    @PrimaryKey(autoGenerate = true)
    val id: Int,
    val title: String,
    val content: String
)
```

### `Data Access Objects`(DAO)クラスの作成

`@Dao`アノテーション付けます。
名前の通りこのクラスを使ってデータにアクセスしていくので、適宜機能を増やしていけばいいと思います。

```ItemDao.kt
@Dao
interface ItemDao {
    @Insert
    suspend fun insert(entity: ItemEntity)

    @get:Query("SELECT * FROM ItemEntity")
    val all: List<ItemEntity>
}
```

### `Database`クラスの作成

`@Database`アノテーション付けます
このクラス内の`itemDao()`から操作します

```ItemDatabase.kt
@Database(entities = [ItemEntity::class], version = 1)
abstract class ItemDatabase : RoomDatabase() {
    abstract fun itemDao(): ItemDao

    companion object {
        private var INSTANCE: ItemDatabase? = null

        fun getInstance(context: Context): ItemDatabase? {
            if (INSTANCE == null) {
                synchronized(ItemDatabase::class) {
                    INSTANCE = Room.databaseBuilder(
                        context.applicationContext,
                        ItemDatabase::class.java, "item.db"
                    ).build()
                }
            }
            return INSTANCE
        }

        fun destroyInstance() {
            INSTANCE = null
        }
    }
}
```

### Tips

#### インスタンス化

```Activity.kt
val dao = ItemDatabase.getInstance(this)?.itemDao()
```

#### 挿入
`autoGenerate = true`なので勝手にidを振ってくれます

```Activity.kt
dao?.insert(ItemEntity(0, "title", "content"))
```

#### 読み込み
細かく読み込みたい場合は`ItemDao`に追記

```Activity.kt
dao?.all?.let {
    it.forEach { item ->

    }
}
```

## Koin

### 準備
appの`build.gradle`

```build.gradle
implementation 'org.koin:koin-android:1.0.2'
```

### `Application`クラスの作成
例として`Hoge.kt`があるとします

```App.kt
class App : Application() {

    override fun onCreate() {
        super.onCreate()

        startKoin(
            this, listOf(
                this.module
            )
        )
    }

    private val module = module {
        factory { 
            //Injectionしたいクラスのインスタンス化(今回はHogeクラス)
            Hoge()
        }
    }
}
```

### `Manifest`ファイルでapplicationを指定
`application`タグの`name`に先程作成した`Application`クラスを指定します

```AndroidManifest.xml
...

<application
            android:name=".App"

...
```

### 実際につかう
例えば上記`App.kt`で`Hoge`クラスのインスタンスをモジュール化していた場合は以下のように書くとインスタンス`hoge`にinjectされます

```Activity.kt
val hoge: Hoge by inject()
```

### Tips
#### 複数のモジュールを使いたい
例えば`Huga.kt`もモジュール化したい時

```App.kt
class App : Application() {

    override fun onCreate() {
        super.onCreate()

        startKoin(
            this, listOf(
                this.hogeModule,
                this.hugaModule
            )
        )
    }

    private val hogeModule = module {
        factory { 
            Hoge()
        }
    }

    // Hugaクラスをインスタンス化するモジュールを追加
    private val hugaModule = module {
        factory { 
            Huga()
        }
    }
}
```

又はこう

```App.kt
class App : Application() {

    override fun onCreate() {
        super.onCreate()

        startKoin(
            this, listOf(
                this.module
            )
        )
    }

    private val module = module {
        factory { 
            Hoge()
        }

        // このモジュール内でHugaクラスもインスタンス化する
        factory { 
            Huga()
        }
    }
}
```

#### コンストラクタでinjectさせたい
例えば`Huga.kt`のコンストラクタで`Hoge.kt`のインスタンスを使いたい場合

```Huga.kt
class Huga(private val hoge:Hoge){

}
```

```App.kt
class App : Application() {

    override fun onCreate() {
        super.onCreate()

        startKoin(
            this, listOf(
                this.hogeModule,
                this.hugaModule
            )
        )
    }

    private val hogeModule = module {
        factory { 
            Hoge()
        }
    }

    private val hugaModule = module {
        factory { 
            // `get()`で自動injectされます
            Huga(get())
        }
    }
}
```

#### `interface`をインスタンス化したい
もし`Hoge.kt`が`interface`だった場合

```Hoge.kt
interface Hoge{

}
```

```HogeImpl.kt
class HogeImpl():Hoge{

}
```

```App.kt
class App : Application() {

    override fun onCreate() {
        super.onCreate()

        startKoin(
            this, listOf(
                this.hogeModule,
                this.hugaModule
            )
        )
    }

    private val hogeModule = module {
        factory { 
            // `as ~~`で明記する
            HogeImpl() as Hoge
        }
    }
}
```

## and more ... !