背景
最近使用Glide的過程中發(fā)現(xiàn)了一些內(nèi)存泄漏的問題,經(jīng)過反復(fù)查找看彼,終于大致鎖定原因:app跑起來的時(shí)候难捌,存在三個(gè)OkHttpClient對(duì)象實(shí)例。
總感覺哪里不對(duì)跨晴,應(yīng)該只有兩個(gè)才合理欧聘。
一個(gè)是普通接口請求使用的OkHttpClient,需要帶上各種參數(shù)給服務(wù)器端盆;
另一個(gè)是項(xiàng)目最近使用Webp格式圖片怀骤,試用期需要做A/B測試,需要在圖片請求里增加cookie發(fā)給服務(wù)器焕妙,所以需要單獨(dú)的OkHttpClient蒋伦。
而現(xiàn)在出現(xiàn)了三個(gè)。
排查過程
經(jīng)過反復(fù)排查访敌,找到了app目錄下的build.gradle文件里的這一段
implementation("com.github.bumptech.glide:okhttp3-integration:" + $glideVersion) {
exclude group: "com.android.support"
}
然后找到我的AppGlideModule類中注冊組件方法凉敲,有這么 一段:
@Override
public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
ImageCookieJar imageCookieJar = new ImageCookieJar(context);
mHeaderUaValue = "mValue"
OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(imageCookieJar)
.connectTimeout(TIME_OUT, TimeUnit.MILLISECONDS)
.writeTimeout(TIME_OUT, TimeUnit.MILLISECONDS)
.readTimeout(TIME_OUT, TimeUnit.MILLISECONDS)
.addInterceptor(new Interceptor() {
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Request request = chain.request().newBuilder()
.addHeader(INTERCEPT_HEADER_KEY, INTERCEPT_HEADER_VALUE)
.header(HEADER_UA_KEY, mHeaderUaValue)
.build();
return chain.proceed(request);
}
}).build();
OkHttpUrlLoader.Factory factory = new OkHttpUrlLoader.Factory(client);
registry.replace(GlideUrl.class, InputStream.class, factory);
}
這里創(chuàng)建了一個(gè)OkHttpClient實(shí)例,用來處理圖片請求的寺旺。然后我們點(diǎn)進(jìn)這個(gè)OkHttpUrlLoader.Factory類看爷抓,發(fā)現(xiàn)有個(gè)getInternalClient()方法里也會(huì)創(chuàng)建一個(gè)OkHttpClient實(shí)例:
private static Call.Factory getInternalClient() {
if (internalClient == null) {
synchronized (Factory.class) {
if (internalClient == null) {
internalClient = new OkHttpClient();
}
}
}
return internalClient;
}
這個(gè)方法會(huì)在OkHttpUrlLoader.Factory的無參數(shù)構(gòu)造方法中被調(diào)用:
/**
* Constructor for a new Factory that runs requests using a static singleton client.
*/
public Factory() {
this(getInternalClient());
}
在這個(gè)依賴包的目錄下,還有一個(gè)OkHttpLibraryGlideModule類阻塑。
在OkHttpLibraryGlideModule里面的注冊組件方法中會(huì)調(diào)用到這個(gè)OkHttpUrlLoader.Factory的默認(rèn)構(gòu)造方法蓝撇,從而創(chuàng)建這個(gè)OkHttpClient實(shí)例:
@GlideModule
public final class OkHttpLibraryGlideModule extends LibraryGlideModule {
@Override
public void registerComponents(@NonNull Context context, @NonNull Glide glide,
@NonNull Registry registry) {
registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
}
}
細(xì)看一下這方法,發(fā)現(xiàn)有個(gè)@GlideModule注解陈莽。
這個(gè)@GlideModule注解渤昌,就是我們實(shí)現(xiàn)Glide的配置類所用的。
也就是說走搁,這類會(huì)自動(dòng)被實(shí)例會(huì)独柑,自動(dòng)調(diào)用這個(gè)類的注冊組件方法。這里就產(chǎn)生了一個(gè)OkHttpClient實(shí)例私植。
解決方案
那么現(xiàn)在需要把這個(gè)不需要的OkHttpClient實(shí)例干掉忌栅,保留普通接口的OkHttpClient實(shí)例和項(xiàng)目需要的OkHttpClient實(shí)例就夠了。
最粗暴的做法就是曲稼,把依賴包里OkHttpStreamFetcher和OkHttpUrlLoader類的代碼復(fù)制出來索绪,作為自己的代碼,然后去掉這個(gè)依賴贫悄。
再次打開Android Profiler觀察瑞驱,可以看到就剩兩個(gè)了。
關(guān)于
本文為日常工作記錄窄坦,技術(shù)有限唤反,編寫若有錯(cuò)漏,請不吝指出鸭津。
我的GitHub:https://github.com/EKwongChum