【问题标题】:How to show images with indirect link/URL using Glide如何使用 Glide 显示带有间接链接/URL 的图像
【发布时间】:2019-09-25 16:23:53
【问题描述】:

我正在尝试从 WordPress 博客页面下载博客功能图像,然后再加载它们。

现在,每次用户向下和向上滚动时,图像都会一次又一次地加载。任何想法...plzzz ..我尝试了很多解决方案,例如,这个: Preload multiple images with Glide

但是,它没有用。

我正在使用implementation 'com.github.bumptech.glide:glide:3.7.0'

这是我的代码:

RecyclerViewAdapter

public void getthumbnail(String imageurl, final ImageView imageView, final int position){

    ServiceWrapper serviceWrapper = new ServiceWrapper(null);
    Call<GetThumbnail> call = serviceWrapper.getThumbnailCall(imageurl);
    call.enqueue(new Callback<GetThumbnail>() {


        @Override
        public void onResponse(Call<GetThumbnail> call, Response<GetThumbnail> response) {
            if (response.body() != null && response.isSuccessful()) {
                try {

                    if (response.body().getMediaDetails()!=null){

                       // Log.e("recycler adapter", " image is here--  " + response.body().getMediaDetails().getSizes().getThumbnail().getSourceUrl());
                       // Log.e("Full IMG SIZE - ", " THIS IS FULL IMAGE URL--  " + response.body().getMediaDetails().getSizes().getFull().getSourceUrl());

                        imagepath.add(position, response.body().getMediaDetails().getSizes().getFull().getSourceUrl());


                        Glide.with(mContext)
                                .load(response.body().getMediaDetails().getSizes().getFull().getSourceUrl())
                                .diskCacheStrategy(DiskCacheStrategy.SOURCE)
                                .into(imageView);

                    }else {

                    }
                }catch (Exception e){
                   // Log.e("adapter", "fail not media tag "+ e.toString());
                }

            }
        }

        @Override
        public void onFailure(Call<GetThumbnail> call, Throwable t) {

          //  Log.e("adapter", " faile  image "+t.toString());
        }
    });

}

更新 我找到了这段代码并将其放在其他 Glide 代码之上,但它不起作用:

Glide.with(mContext)
                                .load(response.body().getMediaDetails().getSizes().getFull().getSourceUrl())
                                .downloadOnly(new SimpleTarget<File>() {
                                    @Override
                                    public void onResourceReady(File resource, GlideAnimation<? super File> glideAnimation) {

                                    }
                                });

更新: 现在我使用了这段代码,它并没有更快地下载图像:

Glide.with(mContext)
                                .load(response.body().getMediaDetails().getSizes().getFull().getSourceUrl())
                                .downloadOnly(new SimpleTarget<File>() {
                                    @Override
                                    public void onResourceReady(File resource, GlideAnimation<? super File> glideAnimation) {

                                        Glide.with(mContext)
                                                .load(response.body().getMediaDetails().getSizes().getFull().getSourceUrl())
                                                .diskCacheStrategy(DiskCacheStrategy.SOURCE)
                                                .into(imageView);
                                    }
                                });

这是完整的 ViewAdapter.java

import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.support.v7.widget.CardView;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class RecyclerViewAdapter extends 
RecyclerView.Adapter<RecyclerView.ViewHolder> {

private ArrayList<Model> dataset;
private Context mContext;
private ArrayList<Model> list;
private RecyclerViewAdapter adapter;
private RecyclerView recyclerView;
private LinearLayoutManager mLayoutManager;
public static List<WPPost> mListPost;
ArrayList<String> imagepath = new ArrayList<>();
private String baseURL = "https://www.myfitbytes.com/";

public RecyclerViewAdapter(ArrayList<Model> mlist, Context context) {
    this.dataset = mlist;
    this.mContext = context;
}

public static class ImageTypeViewHolder extends RecyclerView.ViewHolder{


    TextView title, subtitle, date;
    ImageView imageView;
    CardView cardview;

    public ImageTypeViewHolder(View itemView) {
        super(itemView);

        this.title = (TextView)  itemView.findViewById(R.id.title);
        //this.subtitle = (TextView) itemView.findViewById(R.id.subtitle);
        this.date = (TextView) itemView.findViewById(R.id.date);
        this.imageView = (ImageView) itemView.findViewById(R.id.Icon);
        this.cardview = (CardView) itemView.findViewById(R.id.cardview);
    }
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from( parent.getContext()).inflate(R.layout.postdetails, parent, false);





    return new ImageTypeViewHolder(view) ;
}

@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
    final Model object = dataset.get(position);
   // Log.d("RecyclerViewAdapter", "IMAGE="+object.Image);
    imagepath.add(position, "");

    if (Build.VERSION.SDK_INT >= 24)
    {
        //( (ImageTypeViewHolder) holder).subtitle.setText(Html.fromHtml(object.subtitle , Html.FROM_HTML_MODE_LEGACY));
        ( (ImageTypeViewHolder) holder).title.setText( Html.fromHtml(object.title , Html.FROM_HTML_MODE_LEGACY) );
        ( (ImageTypeViewHolder) holder).date.setText( Html.fromHtml(object.date , Html.FROM_HTML_MODE_LEGACY) );
    }
    else
    {
        //( (ImageTypeViewHolder) holder).subtitle.setText(Html.fromHtml(object.subtitle ));
        ( (ImageTypeViewHolder) holder).title.setText( Html.fromHtml(object.title ));
        ( (ImageTypeViewHolder) holder).date.setText( Html.fromHtml(object.date ));
    }


    ( (ImageTypeViewHolder) holder).imageView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(mContext, WPPostDetails.class);
            intent.putExtra("itemPosition", position);
            mContext.startActivity(intent);
        }
    });



    try {
        getthumbnail(object.Image, ( (ImageTypeViewHolder) holder).imageView, position);



    }catch (Exception e){
     //   Log.e("adapter ","failed to get image "+e.toString() );
    }
    /// dataset.get(position)



}


public void getthumbnail(String imageurl, final ImageView imageView, final int position){

    ServiceWrapper serviceWrapper = new ServiceWrapper(null);
    Call<GetThumbnail> call = serviceWrapper.getThumbnailCall(imageurl);
    call.enqueue(new Callback<GetThumbnail>() {


        @Override
        public void onResponse(Call<GetThumbnail> call, final Response<GetThumbnail> response) {
            if (response.body() != null && response.isSuccessful()) {
                try {

                    if (response.body().getMediaDetails()!=null){

                       // Log.e("recycler adapter", " image is here--  " + response.body().getMediaDetails().getSizes().getThumbnail().getSourceUrl());
                       // Log.e("Full IMG SIZE - ", " THIS IS FULL IMAGE URL--  " + response.body().getMediaDetails().getSizes().getFull().getSourceUrl());

                        imagepath.add(position, response.body().getMediaDetails().getSizes().getFull().getSourceUrl());

                        Glide.with(mContext)
                                .load(response.body().getMediaDetails().getSizes().getFull().getSourceUrl())
                                .downloadOnly(new SimpleTarget<File>() {
                                    @Override
                                    public void onResourceReady(File resource, GlideAnimation<? super File> glideAnimation) {

                                        Glide.with(mContext)
                                                .load(response.body().getMediaDetails().getSizes().getFull().getSourceUrl())
                                                .diskCacheStrategy(DiskCacheStrategy.SOURCE)
                                                .into(imageView);
                                    }
                                });


                    }else {

                    }
                }catch (Exception e){
                   // Log.e("adapter", "fail not media tag "+ e.toString());
                }

            }
        }

        @Override
        public void onFailure(Call<GetThumbnail> call, Throwable t) {

          //  Log.e("adapter", " faile  image "+t.toString());
        }
    });

}




@Override
public int getItemCount() {

    return dataset.size() ;
   }
 }

更新 所以,现在我尝试将 glide 3 更新到 4.x,我在 build.gradle 中收到以下错误。

所有 com.android.support 库必须使用完全相同的版本规范(混合版本可能导致运行时崩溃)。找到版本 27.1.1、27.1.0、26.1.0。示例包括 com.android.support:support-compat:27.1.1 和 com.android.support:animated-vector-drawable:27.1.0 less... (⌘F1) 有一些库或工具和库的组合是不兼容的,或者可能导致错误。一种这样的不兼容性是使用不是最新版本的 Android 支持库版本进行编译(或者特别是低于您的 targetSdkVersion 的版本)。

代码是:

apply plugin: 'com.android.application'

android {
compileSdkVersion 26
  defaultConfig {
    applicationId "com.myfitbytes"
    minSdkVersion 14
    targetSdkVersion 26
    versionCode 3
    versionName "3.0"
    testInstrumentationRunner 
 "android.support.test.runner.AndroidJUnitRunner"
   }
    buildTypes {
     release {
         minifyEnabled false
         proguardFiles getDefaultProguardFile('proguard-android.txt'), 
     'proguard-rules.pro'
    }
}

packagingOptions {
    exclude 'META-INF/DEPENDENCIES'
    exclude 'META-INF/LICENSE'
    exclude 'META-INF/LICENSE.txt'
    exclude 'META-INF/license.txt'
    exclude 'META-INF/NOTICE'
    exclude 'META-INF/NOTICE.txt'
    exclude 'META-INF/notice.txt'
    exclude 'META-INF/ASL2.0'
  }
 }

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'

implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:design:26.1.0'
implementation 'com.android.support:support-v4:26.1.0'

//library for wordpress rest api
implementation 'com.android.support:cardview-v7:26.1.0'
implementation 'com.android.support:recyclerview-v7:26.0.0-beta2'
implementation 'com.google.code.gson:gson:2.6.2'
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.0.2'
implementation 'com.squareup.okhttp:okhttp:2.4.0'
implementation 'com.squareup.okhttp3:okhttp:2.0.2'
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.1'

  //implementation 'com.github.bumptech.glide:glide:3.7.0'
implementation 'com.github.bumptech.glide:glide:4.8.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'


implementation 'com.android.volley:volley:1.0.0'

implementation 'org.ocpsoft.prettytime:prettytime:4.0.1.Final'

//Firebase
implementation 'com.google.firebase:firebase-core:16.0.4'
implementation 'com.google.firebase:firebase-messaging:17.3.3'

implementation 'org.apache.httpcomponents:httpcore:4.4.1'
//implementation 'org.apache.httpcomponents:httpclient:4.5.6'
//implementation group: 'org.apache.httpcomponents' , name: 'httpclient- android' , version: '4.3.5.1'

implementation files('libs/google-http-client-1.24.1.jar')
implementation files('libs/httpclient-4.5.3.jar')

//bottom nav
implementation 'com.aurelhubert:ahbottomnavigation:2.1.0'

//picasso to download image from url faster
implementation 'com.squareup.picasso:picasso:2.71828'

testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

 }

 apply plugin: 'com.google.gms.google-services'

而且,这条线是红色的:

implementation 'com.android.support:appcompat-v7:26.1.0'

【问题讨论】:

  • 您希望图像在应用外可用吗?例如,用户可以在图库或文件资源管理器中看到它们。另一种选择是图像在您的应用程序本地,它们将通过清除应用程序数据来清除。您的要求是哪一个?
  • 嗨,我唯一需要的是让这个应用程序更快。现在,当用户打开应用程序时,图像加载大约需要 10-15 秒,加上当用户开始上下滚动时,图像开始从一个位置更改到另一个位置,例如,当第一张图像出现并且您向下滚动时然后向上回到第一个图像变成图像#10 大约 5 秒钟,然后返回到原来的位置。但是,我不希望图像显示在他们的画廊中,他们可能会觉得我在看他们
  • 我认为将图像显示在错误的位置来自RecyclerView 的视图池。你的图片有多大?是myfitbytes.com的首页图片吗?
  • 图片尺寸为 300x200
  • 但是,他们在错误的位置 15 秒..然后他们在正确的位置..只是它很慢

标签: java android android-glide


【解决方案1】:

加载延迟问题和图像项处置来自onBindViewHolder 方法,您在其中调用了Web 服务。每次滚动出现列表项时,都会调用onBindViewHolder 以使用正确的值初始化视图。所以你根本不应该在这里调用 web 服务(但在代码中它每次都被调用)。由于Glide 创建了一个请求队列,它保证图像只会被下载一次,因为它会缓存它们。它还保证如果ImageView在滚动过程中RecyclerView的可见区域内,图像将被加载。

另一方面,在您的情况下,到达图像 url 需要两个级别的 webservice api-s。所以我们应该结合Glide过程和检索图像url过程来达到最佳性能。使用Glide-OkHttp3-Integration 库,我开发了这两个级别的异步调用,使Glide 了解您的数据流。

• 请注意,您应该清理并重建您的项目,以便在编译时创建GlideApp 类。

ViewAdapter.java

// some code blocks

@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
    final Model object = dataset.get(position);

    if (Build.VERSION.SDK_INT >= 24) {
        // ( (ImageTypeViewHolder) holder).subtitle.setText(Html.fromHtml(object.subtitle , Html.FROM_HTML_MODE_LEGACY));
        ((ImageTypeViewHolder) holder).title.setText(Html.fromHtml(object.title , Html.FROM_HTML_MODE_LEGACY));
        ((ImageTypeViewHolder) holder).date.setText(Html.fromHtml(object.date , Html.FROM_HTML_MODE_LEGACY));
    } else {
        // ((ImageTypeViewHolder) holder).subtitle.setText(Html.fromHtml(object.subtitle));
        ((ImageTypeViewHolder) holder).title.setText(Html.fromHtml(object.title));
        ((ImageTypeViewHolder) holder).date.setText(Html.fromHtml(object.date));
    }


    ((ImageTypeViewHolder) holder).imageView.setOnClickListener(new View.OnClickListener() {
       @Override
       public void onClick(View v) {
           Intent intent = new Intent(mContext, WPPostDetails.class);
           intent.putExtra("itemPosition", position);
           mContext.startActivity(intent);
       }
    });

    JsonApiGlideUrl url = new JsonApiGlideUrl(object.Image);
    GlideApp.with(imageView.getContext())
         .load(url)
         .into(imageView);
}

// some code blocks

OkHttpAppGlideModule.java

import android.content.Context;
import android.support.annotation.NonNull;

import com.bumptech.glide.Glide;
import com.bumptech.glide.Registry;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.module.AppGlideModule;

import java.io.InputStream;

/**
 * Registers OkHttp related classes via Glide's annotation processor.
 *
 * <p>For Applications that depend on this library and include an
 * {@link AppGlideModule} and Glide's annotation processor, this class
 * will be automatically included.
 */
@GlideModule
public final class OkHttpAppGlideModule extends AppGlideModule {

    @Override
    public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
        registry.replace(JsonApiGlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
    }

    @Override
    public boolean isManifestParsingEnabled() {
        return false;
    }

}

JsonApiGlideUrl.java

import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.Headers;

import java.net.URL;

public class JsonApiGlideUrl extends GlideUrl {

    public JsonApiGlideUrl(URL url) {
        super(url);
    }

    public JsonApiGlideUrl(String url) {
        super(url);
    }

    public JsonApiGlideUrl(URL url, Headers headers) {
        super(url, headers);
    }

    public JsonApiGlideUrl(String url, Headers headers) {
        super(url, headers);
    }

}

OkHttpUrlLoader.java

import android.support.annotation.NonNull;

import com.bumptech.glide.load.Options;
import com.bumptech.glide.load.model.ModelLoader;
import com.bumptech.glide.load.model.ModelLoaderFactory;
import com.bumptech.glide.load.model.MultiModelLoaderFactory;

import java.io.InputStream;

import okhttp3.Call;
import okhttp3.OkHttpClient;

/**
 * A simple model loader for fetching media over http/https using OkHttp.
 */
public class OkHttpUrlLoader implements ModelLoader<JsonApiGlideUrl, InputStream> {

    private final Call.Factory client;

    // Public API.
    @SuppressWarnings("WeakerAccess")
    public OkHttpUrlLoader(@NonNull Call.Factory client) {
        this.client = client;
    }

    @Override
    public boolean handles(@NonNull JsonApiGlideUrl url) {
        return true;
    }

    @Override
    public LoadData<InputStream> buildLoadData(@NonNull JsonApiGlideUrl model, int width, int height, @NonNull Options options) {
        return new LoadData<>(model, new OkHttpStreamFetcher(client, model));
    }

    /**
     * The default factory for {@link OkHttpUrlLoader}s.
     */
    // Public API.
    @SuppressWarnings("WeakerAccess")
    public static class Factory implements ModelLoaderFactory<JsonApiGlideUrl, InputStream> {

        private static volatile Call.Factory internalClient;
        private final Call.Factory client;

        private static Call.Factory getInternalClient() {
            if (internalClient == null) {
                synchronized (Factory.class) {
                    if (internalClient == null) {
                        internalClient = new OkHttpClient();
                    }
                }
            }
            return internalClient;
        }

        /**
         * Constructor for a new Factory that runs requests using a static singleton client.
         */
        public Factory() {
            this(getInternalClient());
        }

        /**
         * Constructor for a new Factory that runs requests using given client.
         *
         * @param client this is typically an instance of {@code OkHttpClient}.
         */
        public Factory(@NonNull Call.Factory client) {
            this.client = client;
        }

        @NonNull
        @Override
        public ModelLoader<JsonApiGlideUrl, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {
            return new OkHttpUrlLoader(client);
        }

        @Override
        public void teardown() {
            // Do nothing, this instance doesn't own the client.
        }

    }

}

OkHttpStreamFetcher.java

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;

import com.bumptech.glide.Priority;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.HttpException;
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.util.ContentLengthInputStream;
import com.bumptech.glide.util.Preconditions;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

import okhttp3.Call;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;

/**
 * Fetches an {@link InputStream} using the okhttp library.
 */
public class OkHttpStreamFetcher implements DataFetcher<InputStream>, okhttp3.Callback {

    private static final String TAG = "OkHttpFetcher";
    private final Call.Factory client;
    private final JsonApiGlideUrl url;
    private OkHttpJsonApiFetcher okHttpJsonApiFetcher;
    private InputStream stream;
    private ResponseBody responseBody;
    private DataCallback<? super InputStream> callback;
    // call may be accessed on the main thread while the object is in use on other threads. All other
    // accesses to variables may occur on different threads, but only one at a time.
    private volatile Call call;

    // Public API.
    @SuppressWarnings("WeakerAccess")
    public OkHttpStreamFetcher(Call.Factory client, JsonApiGlideUrl url) {
        this.client = client;
        this.url = url;
    }

    @Override
    public void loadData(@NonNull Priority priority, @NonNull final DataCallback<? super InputStream> callback) {

        okHttpJsonApiFetcher = new OkHttpJsonApiFetcher(client, url);
        okHttpJsonApiFetcher.loadData(new DataCallback<GlideUrl>() {

            @Override
            public void onDataReady(@Nullable GlideUrl data) {
                Request.Builder requestBuilder = new Request.Builder().url(data.toStringUrl());
                for (Map.Entry<String, String> headerEntry : data.getHeaders().entrySet()) {
                    String key = headerEntry.getKey();
                    requestBuilder.addHeader(key, headerEntry.getValue());
                }
                Request request = requestBuilder.build();
                OkHttpStreamFetcher.this.callback = callback;

                call = client.newCall(request);
                call.enqueue(OkHttpStreamFetcher.this);
            }

            @Override
            public void onLoadFailed(@NonNull Exception e) {
                callback.onLoadFailed(e);
            }
        });
    }

    @Override
    public void onFailure(@NonNull Call call, @NonNull IOException e) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "OkHttp failed to obtain result", e);
        }
        callback.onLoadFailed(e);
    }

    @Override
    public void onResponse(@NonNull Call call, @NonNull Response response) {
        responseBody = response.body();
        if (response.isSuccessful()) {
            long contentLength = Preconditions.checkNotNull(responseBody).contentLength();
            stream = ContentLengthInputStream.obtain(responseBody.byteStream(), contentLength);
            callback.onDataReady(stream);
        } else {
            callback.onLoadFailed(new HttpException(response.message(), response.code()));
        }
    }

    @Override
    public void cleanup() {
        okHttpJsonApiFetcher.cleanup();

        try {
            if (stream != null) {
                stream.close();
            }
        } catch (IOException e) {
            // Ignored
        }
        if (responseBody != null) {
            responseBody.close();
        }
        callback = null;
    }

    @Override
    public void cancel() {
        okHttpJsonApiFetcher.cancel();

        Call local = call;
        if (local != null) {
            local.cancel();
        }
    }

    @NonNull
    @Override
    public Class<InputStream> getDataClass() {
        return InputStream.class;
    }

    @NonNull
    @Override
    public DataSource getDataSource() {
        return DataSource.REMOTE;
    }

}

OkHttpJsonApiFetcher.java

import android.support.annotation.NonNull;
import android.util.Log;

import com.bumptech.glide.load.HttpException;
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.model.GlideUrl;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

import okhttp3.Call;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;

/**
 * Fetches an {@link InputStream} using the okhttp library.
 */
public class OkHttpJsonApiFetcher implements okhttp3.Callback {

    private static final String TAG = "OkHttpJsonApiFetcher";
    private final Call.Factory client;
    private final JsonApiGlideUrl url;
    private ResponseBody responseBody;
    private DataFetcher.DataCallback<? super GlideUrl> callback;
    // call may be accessed on the main thread while the object is in use on other threads. All other
    // accesses to variables may occur on different threads, but only one at a time.
    private volatile Call call;

    // Public API.
    @SuppressWarnings("WeakerAccess")
    public OkHttpJsonApiFetcher(Call.Factory client, JsonApiGlideUrl url) {
        this.client = client;
        this.url = url;
    }

    public void loadData(@NonNull final DataFetcher.DataCallback<? super GlideUrl> callback) {
        Request.Builder requestBuilder = new Request.Builder().get().url(url.toStringUrl());
        for (Map.Entry<String, String> headerEntry : url.getHeaders().entrySet()) {
            String key = headerEntry.getKey();
            requestBuilder.addHeader(key, headerEntry.getValue());
        }
        Request request = requestBuilder.build();
        this.callback = callback;

        call = client.newCall(request);
        call.enqueue(this);
    }

    @Override
    public void onFailure(@NonNull Call call, @NonNull IOException e) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "OkHttp failed to obtain result", e);
        }
        callback.onLoadFailed(e);
    }

    @Override
    public void onResponse(@NonNull Call call, @NonNull Response response) {
        responseBody = response.body();
        if (response.isSuccessful() && responseBody != null) {
            try {
                String json = responseBody.string();
                String url = JsonApiDataModel.getSourceUrl(json);
                callback.onDataReady(new GlideUrl(url));
            } catch (IOException e) {
                callback.onLoadFailed(new HttpException(response.message(), response.code()));
                e.printStackTrace();
            }
        } else {
            callback.onLoadFailed(new HttpException(response.message(), response.code()));
        }
    }

    public void cleanup() {
        if (responseBody != null) {
            responseBody.close();
        }
        callback = null;
    }

    public void cancel() {
        Call local = call;
        if (local != null) {
            local.cancel();
        }
    }

}

JsonApiDataModel.java

import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;

public class JsonApiDataModel {

    @SerializedName("media_details")
    MediaDetails mediaDetails;

    public static String getSourceUrl(String json) {
        return new Gson().fromJson(json, JsonApiDataModel.class).mediaDetails.sizes.full.sourceUrl;
    }

    public class MediaDetails {
        @SerializedName("sizes")
        Sizes sizes;
    }

    public class Sizes {
        // you can use full, medium or thumbnail here!
        @SerializedName("full")
        Full full;
    }

    public class Full {
        @SerializedName("source_url")
        String sourceUrl;
    }

}

.

测试代码和视觉结果:

import com.aminography.glideapplication.glide.okhttp3.GlideApp;
import com.aminography.glideapplication.glide.okhttp3.JsonApiGlideUrl;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final ImageView imageView = findViewById(R.id.imageView);
        TextView textView = findViewById(R.id.textView);

        String sourceUrl = "https://www.myfitbytes.com/wp-json/wp/v2/media/2811";

        textView.setText("JsonApiGlideUrl:\n\n" + sourceUrl);

        final JsonApiGlideUrl url = new JsonApiGlideUrl(sourceUrl);
        GlideApp.with(MainActivity.this).load(url).into(imageView);
    }

}

【讨论】:

  • =( 仍然出现错误11-10 10:39:58.340 10322-10322/com.myfitbytes E/AndroidRuntime: FATAL EXCEPTION: main Process: com.myfitbytes, PID: 10322 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.myfitbytes/com.myfitbytes.MainActivity}: java.lang.NullPointerException: Argument must not be null at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2955)
  • 另外,请记住 object.Image 有很多链接。在这个例子中,MainActivity(或者在我的情况下是 Blog.java 片段)只传递一个链接...但是我有很多跨度>
  • 你在上面运行测试代码吗?还是您自己的 RecyclerView 代码?您提到的错误意味着您正在传递空上下文来启动活动。
  • 伙计..在这 jjsajjajajaja 之后我需要给你买杯咖啡......不是开玩笑!
  • 您应该传递一个链接,就像在示例中使用的一样。它返回一个包含帖子所有详细信息的 json。
【解决方案2】:

• 首先,我强烈建议您使用Glide v4

加载延迟问题和图像项处置来自onBindViewHolder 方法,您在其中调用了Web 服务。每次滚动出现列表项时,都会调用onBindViewHolder 以使用正确的值初始化视图。所以你根本不应该在这里调用 web 服务(但在代码中它每次都被调用)。由于Glide 创建了一个请求队列,它保证图像只会被下载一次,因为它会缓存它们。它还保证如果ImageView 在滚动过程中RecyclerView 的可见区域中,图像将被加载。此外,通过将diskCacheStrategy 设置为DiskCacheStrategy.ALLGlide 显示根据ImageView 大小调整大小的图像。

@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
    final Model object = dataset.get(position);

    if (Build.VERSION.SDK_INT >= 24) {
        // ( (ImageTypeViewHolder) holder).subtitle.setText(Html.fromHtml(object.subtitle , Html.FROM_HTML_MODE_LEGACY));
        ((ImageTypeViewHolder) holder).title.setText(Html.fromHtml(object.title , Html.FROM_HTML_MODE_LEGACY));
        ((ImageTypeViewHolder) holder).date.setText(Html.fromHtml(object.date , Html.FROM_HTML_MODE_LEGACY));
    } else {
        // ((ImageTypeViewHolder) holder).subtitle.setText(Html.fromHtml(object.subtitle));
        ((ImageTypeViewHolder) holder).title.setText( Html.fromHtml(object.title));
        ((ImageTypeViewHolder) holder).date.setText( Html.fromHtml(object.date));
    }


    ((ImageTypeViewHolder) holder).imageView.setOnClickListener(new View.OnClickListener() {
       @Override
       public void onClick(View v) {
           Intent intent = new Intent(mContext, WPPostDetails.class);
           intent.putExtra("itemPosition", position);
           mContext.startActivity(intent);
       }
    });

    Glide.with(imageView.getContext())
         .load(object.Image)
         .apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL))
         .into(imageView);
}

通过上述更改,您的RecyclerView 应该可以顺利且快速地运行。如果你想让GlideRecyclerView更加融合,可以关注this。但我觉得这不是必须的,上一层就够了。

【讨论】:

  • 感谢您的帮助。你还想让我在getthumbnai里面使用Glide吗?l
  • 不客气,伙计。不,不要使用getThumbnail() 方法。像我一样直接在onBindViewHolder() 中使用Glide。请这样做并告诉我结果。我在RecyclerView 中使用Glide 来展示数百张图片,每张图片都有MB 大小。所以使用这种结构不会导致性能和速度的泄漏。
  • 现在的问题是我认为...(我不知道,但我认为)glide 4 给我一个库错误。我将更新问题,以便您查看我的app
  • 根据位置显示不正确的图像的原因是您为每个项目异步调用了一个webservice api。当收到它的结果(例如15秒后)并尝试在ImageView中显示时,根据RecyclerView的视图池机制,它会尝试在目标ImageView中显示另一张图像,因为项目已滚动。因此,创建了一个竞争条件并产生了问题。
  • 请检查我的更新...谢谢。这发生在将 glide 库更新到 4.8
【解决方案3】:

Glide 的当前版本是“4.8.0”。你有什么理由不想使用那个版本? https://github.com/bumptech/glide

https://github.com/bumptech/glide/blob/master/samples/flickr/src/main/java/com/bumptech/glide/samples/flickr/FlickrPhotoGrid.java

您需要使用 RecyclerView。这是一个例子:

 grid.addItemDecoration(new RecyclerView.ItemDecoration() {
      @Override
      public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
          RecyclerView.State state) {
        outRect.set(gridMargin, gridMargin, gridMargin, gridMargin);
      }
    });
    grid.setRecyclerListener(new RecyclerView.RecyclerListener() {
      @Override
      public void onViewRecycled(RecyclerView.ViewHolder holder) {
        PhotoViewHolder photoViewHolder = (PhotoViewHolder) holder;
        GlideApp.with(FlickrPhotoGrid.this).clear(photoViewHolder.imageView);
      }
    });

【讨论】:

  • 我从上面显示的链接中提取了一个 sn-p,该链接位于他们的 GitHub 帐户上。 RecyclerView 将在您滚动窗口时为您缓存缩略图。查看找到 FlickrPhotoGrid.java 的类和示例。我建议你利用这个例子。 RecyclerView 会根据可见内容进行大量缓存,并针对您要解决的问题进行了高度优化。
猜你喜欢
  • 2011-05-14
  • 2018-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-25
  • 2021-05-06
相关资源
最近更新 更多