【问题标题】:How to download an image using Glide via HTTP POST method如何通过 HTTP POST 方法使用 Glide 下载图像
【发布时间】:2016-12-27 09:23:21
【问题描述】:

服务器提供API通过Post请求加载图片,其body看起来像

{
 "image_id": someId,
 "session_id": "someId"
}
响应 - 流。
如何通过 HTTP POST 方法使用 Glide 下载图像?

【问题讨论】:

  • 什么是图片ID?
  • 理想情况下,服务器必须将 image url 作为 GET 请求发送,然后您必须将该 url 传递给 Glide。希望您使用 Volley 发出请求,如果您使用两个异步请求,一个用于内容,另一个用于图像,您的应用程序性能将得到改善

标签: android android-glide image-loading


【解决方案1】:

使用 Glide & Retrofit 2 通过 HTTP POST 方法加载图像的算法:

1) 创建接口,所有通过HTTP POST方法加载图片的请求都应实现该接口:

public interface CacheableRequest {
    String getCacheKey();
}

2) 创建要加载的模型,将作为 Glide.with(context).load(model) 的参数:

import java.io.IOException;
import java.io.InputStream;

import okhttp3.ResponseBody;
import retrofit2.Call;

public class RetrofitStream {

    private final Call<ResponseBody> call;
    private final CacheableRequest request;

    public RetrofitStream(Call<ResponseBody> call, CacheableRequest request) {
        this.call = call;
        this.request = request;
    }

    public InputStream getStream() throws IOException {
        return call.execute().body().byteStream();
    }

    public String getCacheKey() {
        return request.getCacheKey();
    }
}

3) 创建 com.bumptech.glide.load.data.DataFetcher 的实现:

import android.support.annotation.Nullable;

import com.bumptech.glide.Priority;
import com.bumptech.glide.load.data.DataFetcher;

import java.io.IOException;
import java.io.InputStream;

public class RetrofitFetcher implements DataFetcher<InputStream> {

    private final RetrofitStream retrofitStream;
    private InputStream stream;

    public RetrofitFetcher(RetrofitStream retrofitStream) {
        this.retrofitStream = retrofitStream;
    }

    @Nullable
    @Override
    public InputStream loadData(Priority priority) throws Exception {
        return stream = retrofitStream.getStream();
    }

    @Override
    public void cleanup() {
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException ignored) {
            }
        }
    }

    @Override
    public String getId() {
        return retrofitStream.getCacheKey();
    }

    @Override
    public void cancel() {

    }
}

4) 创建 com.bumptech.glide.load.model.ModelLoader 的实现:

import android.content.Context;
import android.support.annotation.Keep;
import android.support.annotation.Nullable;

import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.model.GenericLoaderFactory;
import com.bumptech.glide.load.model.ModelCache;
import com.bumptech.glide.load.model.ModelLoader;
import com.bumptech.glide.load.model.ModelLoaderFactory;

import java.io.InputStream;

public class RetrofitStreamLoader implements ModelLoader<RetrofitStream, InputStream> {

    private final ModelCache<RetrofitStream, RetrofitStream> modelCache;

    @Keep
    public RetrofitStreamLoader() {
        this(null);
    }

    public RetrofitStreamLoader(@Nullable ModelCache<RetrofitStream, RetrofitStream> modelCache) {
        this.modelCache = modelCache;
    }

    @Override
    public DataFetcher<InputStream> getResourceFetcher(RetrofitStream model, int width, int height) {
        // GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time spent parsing urls.
        RetrofitStream stream = model;
        if (modelCache != null) {
            stream = modelCache.get(model, 0, 0);
            if (stream == null) {
                modelCache.put(model, 0, 0, model);
                stream = model;
            }
        }
        return new RetrofitFetcher(stream);
    }

    /**
     * The default factory for {@link RetrofitStreamLoader}s.
     */
    public static class Factory implements ModelLoaderFactory<RetrofitStream, InputStream> {

        private final ModelCache<RetrofitStream, RetrofitStream> modelCache = new ModelCache<>(500);

        @Override
        public ModelLoader<RetrofitStream, InputStream> build(Context context, GenericLoaderFactory factories) {
            return new RetrofitStreamLoader(modelCache);
        }

        @Override
        public void teardown() {
            // Do nothing.
        }
    }
}

5) 创建 GlideModule 的实现,允许配置 Glide

import android.content.Context;

import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.load.DecodeFormat;
import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory;
import com.bumptech.glide.module.GlideModule;

import java.io.InputStream;

public class RetrofitGlideModule implements GlideModule {

    private final static int IMAGES_CACHE_MAX_BYTE_SIZE = 20 * 1024 * 1024;
    private final static String IMAGES_CACHE_PATH = "images";

    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        builder.setDiskCache(new InternalCacheDiskCacheFactory(context, IMAGES_CACHE_PATH, IMAGES_CACHE_MAX_BYTE_SIZE))
                .setDecodeFormat(DecodeFormat.PREFER_RGB_565);
    }

    @Override
    public void registerComponents(Context context, Glide glide) {
        glide.register(RetrofitStream.class, InputStream.class, new RetrofitStreamLoader.Factory());
    }
}

6) 在 AndroidManifest.xml 中添加关于创建的 RetrofitGlideModule 的元数据

<application...>
<meta-data
        android:name="<package>.RetrofitGlideModule"
        android:value="GlideModule" />
</application>

现在您可以通过以下方式下载图片了:

Call<ResponseBody> call = retrofit.getImage(cacheableRequest);
Glide.with(context).load(new RetrofitStream(call, cacheableRequest)).into(imageView);

【讨论】:

    【解决方案2】:

    首先你必须为上述响应创建一个模型对象

        Example : 
    
        import android.os.Parcel;
        import android.os.Parcelable;
    
        public class Movies implements Parcelable {
            private String poster_path;
            private String id;
    
            public Movies() {
            }
    
            private Movies(Parcel in) {
                poster_path = in.readString();
                id = in.readString();
            }
    
            public static final Creator<Movies> CREATOR = new Creator<Movies>() {
                @Override
                public Movies createFromParcel(Parcel in) {
                    return new Movies(in);
                }
    
                @Override
                public Movies[] newArray(int size) {
                    return new Movies[size];
                }
            };
    
            public String getPoster_path() {
                return poster_path;
            }
    
            public void setPoster_path(String poster_path) {
                this.poster_path = poster_path;
            }
    
            public String getId() {
                return id;
            }
    
            public void setId(String id) {
                this.id = id;
            }
    
    
            @Override
            public int describeContents() {
                return 0;
            }
    
            @Override
            public void writeToParcel(Parcel dest, int flags) {
                dest.writeString(poster_path);
                dest.writeString(id);
            }
        }
    

    根据响应创建模型后,我们需要保存这些数据。

       private void fetchTask(final String movieType) {
    
                if (jsonObjectRequest != null) {
                    jsonObjectRequest.cancel();
                    movies.clear();
                }
                Uri.Builder builder = new Uri.Builder();
                builder.scheme("https")
                        .authority("api.themoviedb.org")
                        .appendPath("3")
                        .appendPath("movie")
                        .appendPath(movieType)
                        .appendQueryParameter(MOVIE_API_KEY, MOVIE_API_VALUE);
                String url = builder.build().toString();
                jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
    
                        try {
                            JSONArray jsonArray = response.getJSONArray(MovieModelConstants.MOVIE_RESULTS);
                            for (int i = 0; i < jsonArray.length(); i++) {
                                JSONObject jsonObject = jsonArray.getJSONObject(i);
                                Movies data = new Movies();
                                data.setPoster_path(jsonObject.getString(MOVIE_POSTER_PATH));
                                data.setId(jsonObject.getString(MOVIE_ID));
                                movies.add(data);
                            }
                            moviesAdapter = new MoviesAdapter(movies);
                            moviesAdapter.setItemClickListener(clickListener);
                            recyclerViewMovies.setAdapter(moviesAdapter);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
    
                    }
                }, new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
    
                        Toast.makeText(getContext(), getString(R.string.errorMessage), Toast.LENGTH_SHORT);
    
                    }
                });
                Volley.newRequestQueue(getContext()).add(jsonObjectRequest);
            }
        }
    

    在适配器中你需要根据位置加载

    Picasso.with(holder.mMovieItem.getContext()).load(generateUrlForPoster(String.valueOf(data.get(position).getPoster_path()))).into(holder.mMovieItem);
    

    【讨论】:

      【解决方案3】:

      Glide 中没有这样的方法可以接收 post 请求的 url。

      因此,您只需使用 HTTPUrlConnection 从请求中获取 bytes[],然后使用 Glide 将此 bytes[] 加载到 imageView。

       Glide.with(context).load(byteArr).into(imageView);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-28
        • 1970-01-01
        • 2015-02-08
        • 1970-01-01
        • 2017-10-18
        相关资源
        最近更新 更多