前回からの続きです。
Picassoで画像をダウンロードしてみたものの、特定の画像だけ表示されず、
「なんで表示されねーんだ」
「Basic認証がかかってるだと」
「Picassoでどーやるんだ」
ってなりました。
大部分で前回の記事と重複しますが、この記事だけで解決できるように全部書きます。
picasso2-okhttp3-downloaderの導入
Jakeさんが作ったpicasso2-okhttp3-downloaderを使います。
(2018/11/9 追記)
ダウンローダ(OkHttp3Downloader)はPicasso組み込みのものを使います。
そうしないと、setSingletonInstanceでPicassoの全通信にOkHttp3Downloaderを指定した場合、画像のダウンロードが行われません。
ログを見たいのでlogging-interceptorというのも追加しておきます。
dependencies {
// (省略)
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'
}
実装
このレイアウトのimageView
にインターネットから画像をダウンロードして表示しようと思います。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
</android.support.constraint.ConstraintLayout>
認証なし
まず、なんにも認証がかかっていない場合は、
公式のサンプル通りに実装すれば、普通に画像ダウンロードされて表示されます。
package com.example.picassosample
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Picasso.get()
.load("http://i.imgur.com/DvpvklR.png")
.into(this.imageView)
}
}
認証あり
Basic認証ありの場合は、こんな感じで、PicassoのインスタンスをBuiler
経由で生成して、downloadメソッドの引数にOkHttp3Downloader
クラスのインスタンスを渡すようにします。
この時、通信に使うOkHttpClient
クラスにInterceptor
を追加して、HTTP通信に認証ヘッダをねじ込むようにしておきます。
package com.example.picassosample
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import com.squareup.picasso.OkHttp3Downloader
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.activity_main.*
import okhttp3.Credentials
import okhttp3.OkHttpClient
class MainActivity : AppCompatActivity() {
private val picasso: Picasso by lazy {
val client = OkHttpClient.Builder()
.addInterceptor { chain ->
val request = chain.request().newBuilder()
.addHeader("Authorization", Credentials.basic("basic_username", "basic_password"))
.build()
chain.proceed(request)
}
// ↓↓ログ出力用
.addInterceptor(HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.HEADERS
})
// ↑↑ログ出力用
.build()
val downloader = OkHttp3Downloader(client)
Picasso.Builder(this)
.downloader(downloader)
.build()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
this.picasso
.load("https://url/with/basic/auth/sample.png")
.into(this.imageView)
}
}
こうすることで、Basic認証のかかった画像を表示できるようになります。
addInterceptor
の代わりに↓↓でもいけるようです。
authenticator
と言うからにはこちらの方が正しい対応のような気がします。
.authenticator { _, response ->
response.request().newBuilder()
.addHeader("Authorization", Credentials.basic("basic_username", "basic_password"))
.build()
}
ログを見てみると認証ヘッダが追加されていることも分かります。
08-31 15:46:19.212 12643 12665 D OkHttp : --> GET https://url/with/basic/auth/sample.png
08-31 15:46:19.212 12643 12665 D OkHttp : Authorization: Basic YmFzaWNfdXNlcm5hbWU6YmFzaWNfcGFzc3dvcmQ=
08-31 15:46:19.212 12643 12665 D OkHttp : --> END GET
しかし...
画像をキャッシュさせたい
上記のようなレイアウトの場合は分からなかったのですが、、ListViewに画像を表示させてみると、画像がキャッシュされないことに気づきました。
この場合、どうすればキャッシュが有効になるのかというと...
前出のコードをちょっと修正して、setSingletonInstanceというメソッドをpicassoのインスタンスを引数にして呼び出しておきます。
画像ロード時のPicassoの呼び出しは通常の呼び出し方法に戻します。
package com.example.picassosample
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import com.squareup.picasso.OkHttp3Downloader
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.activity_main.*
import okhttp3.Credentials
import okhttp3.OkHttpClient
class MainActivity : AppCompatActivity() {
private val picasso: Picasso by lazy {
val client = OkHttpClient.Builder()
.addInterceptor { chain ->
val request = chain.request().newBuilder()
.addHeader("Authorization", Credentials.basic("basic_username", "basic_password"))
.build()
chain.proceed(request)
}
// ↓↓ログ出力用
.addInterceptor(HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.HEADERS
})
// ↑↑ログ出力用
.build()
val downloader = OkHttp3Downloader(client)
Picasso.Builder(this)
.downloader(downloader)
.build()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Picasso.setSingletonInstance(this.picasso) // <-- ここ
Picasso.get() // <-- ここ
.load("https://url/to/be/required/sample.png")
.into(this.imageView)
}
}
このサンプルだと効果がわかりづらいですが、こうしておくと画像がキャッシュされるようになりました。
とりあえずは以上です。