動かざることバグの如し

近づきたいよ 君の理想に

kotlin-AndroidでHTTPで取得したデータを表示する

環境

やりたいこと

URL指定したらHTTPリクエストしてデータを取得、表示まで

基礎を学ぶ用なので必要最低限のコードのみ

ライブラリの追加

自分でゴリゴリHttpURLConnection書くのはツラみがあるのでokhttpというライブラリを使う。

元々JavaのライブラリだがKotlinにも対応しているので問題ない。古いQiitaの記事とかだと未対応だから~って書いてあるが。

build.gradleのdependencies項目に以下を追記 これだけ

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
(略)
    compile 'com.squareup.okhttp3:okhttp:3.10.0'
}

コード

先にMainActivityにid=mytextのテキストビューを追加しておく

外部からデータを取得するメソッド ふつうはJSONとかだが、サンプルとしてここではGoogleのサイトを取得している

class MainActivity : AppCompatActivity() {
(略)
}

fun getHtml(): String {
    val client = OkHttpClient()
    val req = Request.Builder().url("http://google.com").get().build()
    val resp = client.newCall(req).execute()
    return resp.body()!!.string()
}

次にパーミッション。AndroidManifest.xml<uses-permission android:name="android.permission.INTERNET" />を追加

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.user.fetchsample">

    <application>
        (略)
    </application>
    <uses-permission android:name="android.permission.INTERNET" />

</manifest>

でメインの処理を書く。が、以下は動きそうで動かない ネットワーク通信はメインスレッドで行っていけなく、非同期通信しなければならない。(android.os.NetworkOnMainThreadExceptionが発生する)

// NOT WORK
class MainActivity : AppCompatActivity() {

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

        val tview = findViewById<TextView>(R.id.mytext)
        val result = getHtml()
        tview.setText(result)

仕方ないのでAsyncTaskを使う。AsyncTaskクラスを継承したMyAsyncTaskをMainActivityクラス内に記述。doInBackground()は非同期で行いたい処理の内容、onPostExecute()はdoInBackground()終了後にメインスレッドで実行される処理の内容である

    inner class MyAsyncTask: AsyncTask<Void, Void, String>() {

        override fun doInBackground(vararg p0: Void?): String? {
            return getHtml()
        }

        override fun onPostExecute(result: String?) {
            super.onPostExecute(result)
            val tview = findViewById<TextView>(R.id.mytext)
            tview.setText(result)

        }
    }

で以下で非同期処理が実行される

MyAsyncTask().execute()

ソース全体は以下

package com.example.user.fetchsample

import android.os.AsyncTask
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import okhttp3.OkHttpClient
import okhttp3.Request

class MainActivity : AppCompatActivity() {

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

        MyAsyncTask().execute()
    }

    inner class MyAsyncTask: AsyncTask<Void, Void, String>() {

        override fun doInBackground(vararg p0: Void?): String? {
            return getHtml()
        }

        override fun onPostExecute(result: String?) {
            super.onPostExecute(result)
            val tview = findViewById<TextView>(R.id.mytext)
            tview.setText(result)

        }
    }

}

fun getHtml(): String {
    val client = OkHttpClient()
    val req = Request.Builder().url("http://google.com").get().build()
    val resp = client.newCall(req).execute()
    return resp.body()!!.string()
}

サンプルとはいえgetHtml()がグローバルなところにいるのはいかがなものかと思いつつ、今日は眠いのでここまで

参考リンク