とりあえず動かしたい人向け。
Androidでは標準になりつつあるhttpクライアントのokhttp3を利用して、画像を非同期でダウンロードしてimageViewに表示させる。細かい設定はいろいろできるが、とりあえずどのようにすれば動作するのかを簡単にまとめてみる。
Androidの通信は、アクティビティで直接的に通信を始めるとエラーになる。これは重い処理であるネットワーク通信についてはアクティビティとは異なる別のスレッドで非同期に実施すべきという方針だからだ。なので、通常であればAsyncTask(現在、使用は非推奨)かAsyncTaskLoader(推奨)を利用して通信をするのだが、それだと処理にいろいろ面倒なのでokhttp3というライブラリを使うと楽にできる。
okhttp3の非同期の通信では、特定のメソッドをコールバックする方法で行われる。Javaによくあるパターンの、コールバックするクラスのインスタンスを渡してあげると、処理が終わったときにそのクラスのメソッドが実行されるヤツだ。
なので、まずはokhttp3が通信を完了したときに呼び出されるコールバックされるクラスを作成する。
コールバックされるクラスは下記のように、アクティビティにinner classとして作成してあげると、innerクラスからアクティビティのメンバ変数にアクセスできるのでいいだろう。
詳しい説明は下記のソースのコメントを読んでほしい。
さきほど作成した受信終了するとコールバックさせるメソッドでデータを取得して、それをビットマップに変換してimageViewに表示させるだけ。okhttp3では、コールバックされるクラスは別スレッドで実行されているので、そのままではアクティビティのスレッドとは異なるため、アクティビティのUI部品を操作するとエラーになる。そのため、別スレッドからアクティビティのスレッドを経由してUI部品を操作する必要がある。
具体的には以下のように記述をする。
Androidでは標準になりつつあるhttpクライアントのokhttp3を利用して、画像を非同期でダウンロードしてimageViewに表示させる。細かい設定はいろいろできるが、とりあえずどのようにすれば動作するのかを簡単にまとめてみる。
Androidの通信は、アクティビティで直接的に通信を始めるとエラーになる。これは重い処理であるネットワーク通信についてはアクティビティとは異なる別のスレッドで非同期に実施すべきという方針だからだ。なので、通常であればAsyncTask(現在、使用は非推奨)かAsyncTaskLoader(推奨)を利用して通信をするのだが、それだと処理にいろいろ面倒なのでokhttp3というライブラリを使うと楽にできる。
okhttp3の非同期の通信では、特定のメソッドをコールバックする方法で行われる。Javaによくあるパターンの、コールバックするクラスのインスタンスを渡してあげると、処理が終わったときにそのクラスのメソッドが実行されるヤツだ。
なので、まずはokhttp3が通信を完了したときに呼び出されるコールバックされるクラスを作成する。
コールバックされるクラスは下記のように、アクティビティにinner classとして作成してあげると、innerクラスからアクティビティのメンバ変数にアクセスできるのでいいだろう。
詳しい説明は下記のソースのコメントを読んでほしい。
class MainActivity : AppCompatActivity() {
//アクティビティにはその他の記述もあるが、ここでは省略
//Callbackを継承するinnerクラスを作成し、必要なメソッドをoverrideする
inner class ImageDownloadCallback : Callback {
//処理が終わった時に呼ばれる
override fun onResponse(call: Call?, response: Response?) {
Log.v("nullpo", "onResponse")
}
//処理が失敗したときに呼ばれる
override fun onFailure(call: Call?, e: IOException?) {
Log.v("nullpo", "onFailure")
}
}
}
次に処理を実行する本体部分を記述する。具体的には以下のようになる。これも簡単なのでソースにコメントを参照して欲しい。
//ボタンクリックで通信を開始する
btnButton01.setOnClickListener {
//アクセス先などの設定をする
val request: Request = Request.Builder().let {
//フリー画像サイトの画像への直リンクです
it.url("https://www.pakutaso.com/shared/img/thumb/nuko-8_TP_V1.jpg")
it.get()
it.build()
}
//通信するクライアントのインスタンスを生成する
val client: OkHttpClient = OkHttpClient()
//クライアントがアクセス先などの設定をもとに通信を行う
//enqueueの引数は、先ほど作成したコールバックさせるクラスのインスタンス
//処理が終わると、そのクラスのメソッドが呼ばれる
client.newCall(request).enqueue(ImageDownloadCallback())
}
さらに、受信したデータをビットマップに変換して、imageViewに表示させる。さきほど作成した受信終了するとコールバックさせるメソッドでデータを取得して、それをビットマップに変換してimageViewに表示させるだけ。okhttp3では、コールバックされるクラスは別スレッドで実行されているので、そのままではアクティビティのスレッドとは異なるため、アクティビティのUI部品を操作するとエラーになる。そのため、別スレッドからアクティビティのスレッドを経由してUI部品を操作する必要がある。
具体的には以下のように記述をする。
inner class ImageDownloadCallback : Callback {
override fun onResponse(call: Call?, response: Response?) {
Log.v("nullpo", "onResponse")
if (response?.body()?.byteStream() != null) {
if (response.isSuccessful) {
//受信した画像データをビットマップに変換する
val bitmap: Bitmap = BitmapFactory.decodeStream(response!!.body()!!.byteStream())
//アクティビティのスレッドへ処理を投げる
//直接的にインスタンスに対して操作するとエラーになる
Handler(Looper.getMainLooper()).post {
//imageViewにビットマップデータを表示させる
ivImageView01.setImageBitmap(bitmap)
}
}
}
}
override fun onFailure(call: Call?, e: IOException?) {
Log.v("nullpo", "onFailure")
}
}
あとお約束のコンパイル設定と通信の許可を忘れないように。
//マニフェストファイルにインターネットを利用する許可を設定しておく
<uses-permission android:name="android.permission.INTERNET" />
//gradleのほうにはokhttp3を利用する設定をしておく
compile 'com.squareup.okhttp3:okhttp:3.10.0'