如果您想跳到答案,请转到下面列表中的第3点!
经过一段时间的摸索,我尝试了几种方法,找到了一种可以实现上面列出的所有功能的方法,尽管这不是最干净的方法:
1.尝试在Picasso中添加OkHttp3拦截器,以修改传递之前的响应
我的第一个想法是在OkHttp中使用拦截器,我们通常使用它来修改/添加头
请求
发送之前,不要修改
响应
-如果可能的话,你不应该这样做。
拦截器如下所示:
private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
@Override public okhttp3.Response intercept(Chain chain) throws IOException {
okhttp3.Response originalResponse = chain.proceed(chain.request());
if (validate(originalResponse.headers()) {
return originalResponse.newBuilder()
.body(null)
.build();
}
return originalResponse;
}
};
然后,我尝试使用Jake Wharton的拦截器将此拦截器添加到毕加索实例中
com.jakewharton.picasso:picasso2-okhttp3-downloader
该库为毕加索2.5.2和Retrofit 2.0.2添加了OkHttp3拦截器支持。
2.尝试制作
HEAD
在使用毕加索通话之前,请求使用Retrofit 2验证标题
1.答
头部
请求在步骤2之前分别验证响应头。
2.答
GET
请求下载包含图像的整个响应主体(如果步骤1.返回有效)
在我之前的方法中,我想将这两个步骤捆绑在一起,这在概念上是错误的,因为无论哪种方式,正文都会被下载,但只有在满足标准时才会被删除,因此无论哪种方法都会浪费带宽。
我计划使用Retrofit 2实现步骤1,使用Picasso 2.5实现步骤2。
由于为这样一个简单的调用实现Retrofit rest接口会带来很多开销,所以我很快从这个角度出发。
3.通过做一个
头部
使用OkHttp3调用以验证标头,然后使用URI调用Picasso
与方法#2类似,但不是使用Retrofit
head()
很快,我实现了一个AsyncTask,它将运行一个简单的OkHttp
头部()
调用一个给定的链接,它会返回一个包含化身和相关链接的枚举类型的项。此调用将在不同的线程上进行。
初始化另一个调用的线程,一旦收到OkHttp调用的反馈(使用简单的模式通知UI线程),就会处理信息,并在需要时启动Picasso调用。
package com.example;
import android.net.Uri;
public class Avatar {
AvatarType _avatarType;
Uri _uri;
public Avatar(AvatarType type, Uri uri) {
_avatarType = type;
_uri = uri;
}
public AvatarType getType() {
return _avatarType;
}
public Uri getUri() {
return _uri;
}
}
package com.example;
public enum AvatarType {
TYPE_X,
TYPE_Y
}
package com.example;
import android.net.Uri;
import android.os.AsyncTask;
import java.io.IOException;
import okhttp3.OkHttpClient;
import okhttp3.Request;
public class AvatarDownloaderTask extends AsyncTask<String, String, Avatar> {
private OnTaskCompleted _listener;
public AvatarDownloaderTask(OnTaskCompleted listener){
_listener = listener;
}
@Override
protected Avatar doInBackground(String... params) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(params[0])
.head()
.build();
try {
okhttp3.Response response = client.newCall(request).execute();
if (Integer.parseInt(response.header("Content-Length")) > 100) {
return new Avatar(AvatarType.TYPE_Y, Uri.parse(params[0]));
}
} catch (IOException e) {
cancel(true);
}
return new Avatar(AvatarType.TYPE_X, Uri.parse(params[0]));
}
@Override
protected void onPostExecute(Avatar s) {
super.onPostExecute(s);
_listener.onTaskCompleted(s);
}
@Override
protected void onCancelled(Avatar s) {
super.onCancelled(s);
_listener.onTaskCompleted(s);
}
public interface OnTaskCompleted{
void onTaskCompleted(Avatar avatar);
}
}
public class ProfileFragment extends Fragment implements AvatarDownloaderTask.OnTaskCompleted{
private void loadAvatar(String avatarUrl) {
new AvatarDownloaderTask(this).execute(avatarUrl);
}
@Override
public void onTaskCompleted(Avatar avatar) {
switch (avatar.getType()) {
case TYPE_X:
_avatarProgressBar.setVisibility(View.GONE);
_avatarImageView.setVisibility(View.GONE);
_avatarImageViewPlaceholder.setVisibility(View.VISIBLE);
break;
case TYPE_Y:
ImageHandler.sharedHandler(getContext()).bypassImageResizer(avatar.getUri(), _avatarImageView, new com.squareup.picasso.Callback() {
@Override
public void onSuccess() {
_avatarProgressBar.setVisibility(View.GONE);
_avatarImageViewPlaceholder.setVisibility(View.GONE);
_avatarImageView.setVisibility(View.VISIBLE);
}
@Override
public void onError() {
_avatarProgressBar.setVisibility(View.GONE);
_avatarImageView.setVisibility(View.GONE);
_avatarImageViewPlaceholder.setVisibility(View.VISIBLE);
}
});
break;
}
}
}
这绝对不是一种干净的方法,迫使我这样做的API设计从一开始就不好。我很想听听其他人的反馈和建议,如何以另一种方式对此进行改进/修复。AsyncTask还有其他轻量级方法吗?如何将数据传回主/UI线程-这可以修复/改进/消除吗?
干杯