close

Android網路三大框架為

1.okHttp
2.volley
3.retrofit
其中retrofit封裝okHttp,並且支援多種框架(Rxjava、LiveData...等等),連線速度也是其中最快的

這邊使用MVVM架構開始實作

第一步驟:在gradle引用Library

//retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

第二步驟:AndroidManifest.xml加入連網權限

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

第三步驟:創建Retrofit物件來使用(這邊使用https://jsonplaceholder.typicode.com作為範例),並且使用okhttp的interceptor來做token和error的處理

class RetrofitManager {
    val URL = "https://jsonplaceholder.typicode.com/"
    fun getRetrofit(): Retrofit {
        return Retrofit.Builder()
            .baseUrl(URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(getOkHttp())//add OkHttpClient
            .build()
    }

    fun getOkHttp(): OkHttpClient {
        val token = "RestfulApiToken"
        val okHttpBuilder = OkHttpClient.Builder()
        okHttpBuilder.addInterceptor { chain ->
            val apiRequest = chain.request()
            ////新增token到Header
            apiRequest.newBuilder().addHeader("Authorization","Bearer" + token)
            val apiResponse = chain.proceed(apiRequest)
            //處理Http error code
            when(apiResponse.code()){
                200 -> Log.d("test","success")
                404 -> Log.d("test","fail")
            }
            apiResponse
        }
        return okHttpBuilder.build()
    }
}

第四步驟:創建Api打回來的Json要轉換成的物件

data class AlbumsData(val userId:Int, val id:Int, val title:String)

第五步驟:創建Api連線介面

interface JsonApi {
    //https://jsonplaceholder.typicode.com/albums/1
    @GET("albums/1")
    fun getAlbums(): Call<AlbumsData>

    //https://jsonplaceholder.typicode.com/albums/{id}
    @GET("albums/{id}")
    fun getAlbumsByIdFromPath(@Path("id") Id:Int): Call<AlbumsData>

    //https://jsonplaceholder.typicode.com/albums?postId={Id}
    @GET("albums")
    fun getAlbumsById(@Query("postId") Id:Int): Call<List<AlbumsData>>

    //post albumsData to https://jsonplaceholder.typicode.com
    @POST("albums")
    fun postAlbums(@Body albumsData: AlbumsData): Call<AlbumsData>
}

第六步驟:在Repositoty用Retrofit物件打出Api

class ApiRepository {
    val jsonApi : JsonApi by lazy { RetrofitManager().getRetrofit().create(JsonApi::class.java) }

    fun getAllAlbums(): Call<AlbumsData>{
        return jsonApi.getAlbums()
    }

    fun getAlbumsByIdFromPath(id:Int): Call<AlbumsData>{
        return jsonApi.getAlbumsByIdFromPath(id)
    }

    fun getAlbumsById(id:Int): Call<List<AlbumsData>>{
        return jsonApi.getAlbumsById(id)
    }

    fun postAlbums(albumsData:AlbumsData): Call<AlbumsData>{
        return jsonApi.postAlbums(albumsData)
    }
}

第七步驟:在ViewModel做Repository操作並將資料放入LiveData給Activity做觀察(記得不要在MainThread做網路同步操作)

class ApiViewModel : ViewModel() {

    private val albumsDataList = MutableLiveData<List<AlbumsData>>()
    val albumsLiveDataList: LiveData<List<AlbumsData>> = albumsDataList
    private val albumsData1 = MutableLiveData<AlbumsData>()
    val albumsLiveData1: LiveData<AlbumsData> = albumsData1
    private val albumsData2 = MutableLiveData<AlbumsData>()
    val albumsLiveData2: LiveData<AlbumsData> = albumsData2
    private val albumsData3 = MutableLiveData<AlbumsData>()
    val albumsLiveData3: LiveData<AlbumsData> = albumsData3

    val apiRepository: ApiRepository by lazy { ApiRepository() }

    //同步執行
    fun getAlbumSync() {
        Thread(Runnable {
            var apiResponse1 = apiRepository.getAlbumsById(1).execute()
            var apiResponse2 = apiRepository.getAlbumsByIdFromPath(2).execute()
            var apiResponse3 = apiRepository.getAllAlbums().execute()
            var apiResponse4 = apiRepository.postAlbums(AlbumsData(1, 1, "Castle on the Hill")).execute()

            if (isSuccess(apiResponse1)) {
                albumsDataList.postValue(apiResponse1.body())
            }
            if (isSuccess(apiResponse2)) {
                albumsData1.postValue(apiResponse2.body())
            }
            if (isSuccess(apiResponse3)) {
                albumsData2.postValue(apiResponse3.body())
            }
            if (isSuccess(apiResponse4)) {
                albumsData3.postValue(apiResponse4.body())
            }

        }).start()
    }

    //非同步執行
    fun getAlbumAsync() {

        apiRepository.getAlbumsById(1).enqueue(object : Callback<List<AlbumsData>> {
            override fun onFailure(call: Call<List<AlbumsData>>, t: Throwable) {
                Log.d("test","Fail1")
            }
            override fun onResponse(call: Call<List<AlbumsData>>,response: Response<List<AlbumsData>>) {
                albumsDataList.value = response.body()
            }
        })

        apiRepository.getAlbumsByIdFromPath(2).enqueue(object : Callback<AlbumsData>{
            override fun onFailure(call: Call<AlbumsData>, t: Throwable) {
                Log.d("test","Fail2")
            }
            override fun onResponse(call: Call<AlbumsData>, response: Response<AlbumsData>) {
                albumsData1.value =response.body()
            }
        })

        apiRepository.getAllAlbums().enqueue(object : Callback<AlbumsData>{
            override fun onFailure(call: Call<AlbumsData>, t: Throwable) {
                Log.d("test","Fail3")
            }
            override fun onResponse(call: Call<AlbumsData>, response: Response<AlbumsData>) {
                albumsData2.value=response.body()
            }
        })

        apiRepository.postAlbums(AlbumsData(1, 1, "Castle on the Hill")).enqueue(object : Callback<AlbumsData>{
            override fun onFailure(call: Call<AlbumsData>, t: Throwable) {
                Log.d("test","Fail4")
            }
            override fun onResponse(call: Call<AlbumsData>, response: Response<AlbumsData>) {
                albumsData3.value=response.body()
            }
        })
    }

    private fun <T> isSuccess(apiResponse: Response<T>): Boolean {
        return apiResponse.isSuccessful and (apiResponse.code() == 200)
    }
}

第八步驟:Activity取得資料做使用

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val viewModel = ViewModelProvider(this).get(ApiViewModel::class.java)
        viewModel.getAlbum()
        viewModel.albumsLiveDataList.observe(this, Observer { Log.d("test","List:"+it.toString()) })
        viewModel.albumsLiveData1.observe(this, Observer { Log.d("test","1:"+it.toString()) })
        viewModel.albumsLiveData2.observe(this, Observer { Log.d("test","2:"+it.toString()) })
        viewModel.albumsLiveData3.observe(this, Observer { Log.d("test","3:"+it.toString()) })
    }
}

 

原始碼:https://github.com/a0973378273/kotlinRetrofitSample

arrow
arrow
    全站熱搜

    JBLin 發表在 痞客邦 留言(0) 人氣()