インターネット接続(Retrofit)

  • 投稿者:
  • 投稿カテゴリー:その他

環境設定

Retrofitを追加する
合わせてライブラリで必要になるJava8言語機能を追加する

Projectのbuild.gradleのリポジトリ確認
googleとjcenterがあること
buildscript {
….
repositories {
google()
jcenter()
}
….
}

appのbuild.gradleにライブラリを追加しJava8機能のサポート確認

android {

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

kotlinOptions {
    jvmTarget = '1.8'
}

}

dependencies {
// Retrofit
implementation “com.squareup.retrofit2:retrofit:2.9.0”
implementation “com.squareup.retrofit2:converter-scalars:2.9.0”
}

権限の追加

manifests/AndroidManifest.xmlの タグの直前に以下を追加

<uses-permission android:name=”android.permission.INTERNET” />

インターネットからJSONデータを取得し表示するサンプル

xmlレイアウト

単一のフラグメント
データバインディングによりテキストビューを1つ表示

<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/overviewFragment"
    android:name="com.example.android.marsphotos.overview.OverviewFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:layout="@layout/fragment_overview" />
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
            name="viewModel"
            type="com.example.android.marsphotos.overview.OverviewViewModel" />
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.android.marsphotos.overview.OverViewFragment">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{viewModel.status}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

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

アクティビティ

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

フラグメント

ViewModelを定義しデータバインディングする例

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.example.android.marsphotos.databinding.FragmentOverviewBinding

class OverviewFragment : Fragment() {

    // OverviewViewModelを定義
    private val viewModel: OverviewViewModel by viewModels()

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val binding = FragmentOverviewBinding.inflate(inflater)
        binding.lifecycleOwner = this
        binding.viewModel = viewModel
        return binding.root
    }
}

ビューモデル

init処理にてインターネットに接続。
取得データをライブデータにセットする。

データの取得は、launchによりコルーチン(子スレッド)を起動してデータを取得している。
ネットワークエラーが発生する事があるのでエラー処理は必須

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.android.marsphotos.network.MarsApi
import kotlinx.coroutines.launch

class OverviewViewModel : ViewModel() {

    // データバインディングのMutableLiveData変数を定義
    private val _status = MutableLiveData<String>()
    val status: LiveData<String> = _status

    init {
        // データ取得
        getMarsPhotos()
    }

    // データ取得メソッド
    private fun getMarsPhotos() {
        try {
            // launchによりコルーチン(スレッド)を起動してデータを取得する
            viewModelScope.launch {
                // Retrofitライブラリを使用したインターフェイスを利用
                val listResult = MarsApi.retrofitService.getPhotos()
                _status.value = listResult
            }
        } catch (e:Exception){
            // エラー処理
            _status.value = "Failure: ${e.message}"
        }
    }
}

ネットワークインターフェース

Retrofitビルダーの定義(レスポンスの戻りの型やベースURLなど)
Interfaceクラスの定義(エンドポイントと戻り型だけの関数1つ。
なぜこの関数でレスポンスが返されるのか仕組みが不明。。。)
オブジェクトの定義(Retrofitのオブジェクト。シングルトンオブジェクトとなり1つのみインスタンス化される)

import retrofit2.Retrofit
import retrofit2.converter.scalars.ScalarsConverterFactory
import retrofit2.http.GET

// ベースアドレス
private const val BASE_URL = "https://android-kotlin-fun-mars-server.appspot.com"

// Retrofitビルダー(Stringを返すScalarsConverterFactoryでcreate)
private val retrofit = Retrofit.Builder()
    .addConverterFactory(ScalarsConverterFactory.create())
    .baseUrl(BASE_URL)
    .build()

// interface
interface MarsApiService {
    // getリクエストでphotosをエンドポイントと定義
    @GET("photos")
    // suspendとする事でコルーチンからの呼出しが可能
    suspend fun getPhotos() : String
}

// シングルトンオブジェクトとして1つのみインスタンス化される
// retrofitServiceを遅延初期化(実際に利用される時に初期化)
object MarsApi {
    val retrofitService : MarsApiService by lazy {
        // RetrofitビルダーのcreateメソッドにMarsApiServiceインターフェイスを渡す
        retrofit.create(MarsApiService::class.java)
    }
}

トレーニング > KOTLIN を用いた ANDROID の基本 > インターネット > データを取得して表示する > インターネットからデータを取得する > 5. ウェブサービスと Retrofit