在 Fresco 上调用 notifyDataSetChanged() 后未显示新图像

New images not displaying after calling notifyDataSetChanged() on Fresco

几天来我一直在尝试在我的 android 应用程序上实现一些功能,但没有成功。

我有一个显示产品的回收站视图。产品包装在 cardView 中,gridLayoutManager 为我处理布局。 cardView 包含一个 textView(产品名称)和一个 simpleDraweeView(产品图像)。

我成功地添加了一个 SwipeRefreshLayout,当用户向下滑动时,产品会刷新并添加新内容(如果存在)。 textView 在刷新时更新得很好。但是,simpleDraweeView 在我向下滚动并再次返回之前不会显示新产品的图像。

我研究了这个问题并发现了这个问题:https://github.com/facebook/fresco/issues/687。但是 post 没有完全说明如何正确设置。

下面是我的代码片段:

刷新代码段(MainActivityFragment Class)

//set refresh more listener for the RecyclerView adapter
mainActivityAdapter.setOnRefreshMoreListener(new OnRefreshMoreListener() {
   @Override
    public void onRefreshMore() {
         swipeRefreshLayout.setRefreshing(true);
         new Handler().postDelayed(new Runnable() {
             @Override
             public void run() {
                 productsArrayList.clear();  //I'm removing previous data
                 mainActivityAdapter.notifyDataSetChanged();
                 fetchOnLoad(); //Function that adds new elements to the productsArrayList
                 mainActivityAdapter.notifyDataSetChanged();
                 swipeRefreshLayout.setRefreshing(false);
              }
         }, 1000);
     }
 });

onBindView 片段(MainActivityAdapter)

@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
  if (holder instanceof ProductViewHolder) {
    final Product product = mProducts.get(position);

    Uri uri = Uri.parse(product.getProductImage());
    final ProductViewHolder productViewHolder = (ProductViewHolder) holder;
    productViewHolder.productName.setText(product.getProductName());
    productViewHolder.cardImage.setImageURI(uri);

  }
}

就像我在上面 post 编辑的 link 一样,我也认为 Fresco 没有显示新加载的图像,因为没有再次调用 onBindViewHolder。在我滚动出视图并再次进入视图后,图像总是出现。我可以像他解决的那样在 ViewHolder 中设置数据吗?如果是这样,如何? 任何帮助将不胜感激。 谢谢

编辑: 根据要求,这里是 fetchOnLoad

的代码
public void fetchOnLoad() {

    // showing refresh animation before making http call
    swipeRefreshLayout.setRefreshing(true);

    // appending offset to url
    String url = "https://www.example.com/spilljson.php";

    // Volley's json array request object
    JsonArrayRequest req = new JsonArrayRequest(url,
            new Response.Listener<JSONArray>() {
                @Override
                public void onResponse(JSONArray response) {
                    Log.d(TAG, response.toString());

                    if (response.length() > 0) {
                        // looping through json and adding to product list
                        for (int i = 0; i < response.length(); i++) {
                            try {
                                JSONObject productObj = response.getJSONObject(i);

                                String image = productObj.getString("productImage");
                                String name = productObj.getString("productName");

                                Product product = new Product();
                                product.setProductName(name); //This works fine. New product names always shown
                                product.setProductImage(image); //This is where I get the issue. New product images are not shown.
                                products.add(product); //Add the individual product to the products arrayList


                            } catch (JSONException e) {
                                Log.e(TAG, "JSON Parsing error: " + e.getMessage());
                            }
                        }
                        mainActivityAdapter.notifyDataSetChanged();
                    }

                    // stopping swipe refresh
                    swipeRefreshLayout.setRefreshing(false);

                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Log.e(TAG, "Server Error: " + error.getMessage());

            Toast.makeText(mActivity, "We can't access our servers :-(", Toast.LENGTH_LONG).show();

            // stopping swipe refresh
            swipeRefreshLayout.setRefreshing(false);
        }
    });

    // Adding request to request queue
    FrescoApplication.getInstance().addToRequestQueue(req);
}

问题截图 这是屏幕截图的 link:https://imgur.com/QQjEviS

完整的 MainActivityAdapter

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

private RecyclerView mRecyclerView;

private final int VIEW_TYPE_ITEM = 0;
private final int VIEW_TYPE_LOADING = 1;
private OnLoadMoreListener onLoadMoreListener;
private OnRefreshMoreListener onRefreshMoreListener;
private boolean isLoading;
private List<Product> mProducts;
private SwipeRefreshLayout mSwipeRefresh;
private int visibleThreshold = 5;
private int lastVisibleItem, totalItemCount;
public static final String STRING_IMAGE_URI = "ImageUri";
public static final String STRING_IMAGE_POSITION = "ImagePosition";
private static MainActivity mActivity;

public MainActivityAdapter(RecyclerView recyclerView, SwipeRefreshLayout refreshLayout, List<Profile> products, MainActivity myContext) {
    mRecyclerView = recyclerView;
    mProducts = products;
    mActivity = myContext;
    mSwipeRefresh = refreshLayout;

    final GridLayoutManager gridLayoutManager = (GridLayoutManager) recyclerView.getLayoutManager();
    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            totalItemCount = gridLayoutManager.getItemCount();
            lastVisibleItem = gridLayoutManager.findLastVisibleItemPosition();
            if (!isLoading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
                if (onLoadMoreListener != null) {
                    onLoadMoreListener.onLoadMore();
                }
                isLoading = true;
            }
        }
    });

    mSwipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {
            if (onRefreshMoreListener != null) {
                onRefreshMoreListener.onRefreshMore();
            }
        }
    });
}

public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
    this.onLoadMoreListener = mOnLoadMoreListener;
}

public void setOnRefreshMoreListener(OnRefreshMoreListener mOnRefreshMoreListener) {
    this.onRefreshMoreListener = mOnRefreshMoreListener;
}

public static class ViewHolder extends RecyclerView.ViewHolder {
    public final View mView;
    public final SimpleDraweeView mImageView;
    public final RelativeLayout mLayoutItem;

    public ViewHolder(View view) {
        super(view);
        mView = view;
        mImageView = (SimpleDraweeView) view.findViewById(R.id.user_image_listing);
        mLayoutItem = (RelativeLayout) view.findViewById(R.id.layout_item);
    }
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if (viewType == VIEW_TYPE_ITEM) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.main_layout_profile, parent, false);
        return new ProductViewHolder(view);
    } else if (viewType == VIEW_TYPE_LOADING) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_loading, null, false);
        return new LoadingViewHolder(view);
    }
    return null;
}

@Override
public void onViewRecycled(ViewHolder holder) {
    if (holder instanceof ProductViewHolder) {
        ProductViewHolder productViewHolder = (ProductViewHolder) holder;

        if (productViewHolder.mImageView.getController() != null) {
            productViewHolder.mImageView.getController().onDetach();
        }
        if (productViewHolder.mImageView.getController() != null) {
            productViewHolder.mImageView.getTopLevelDrawable().setCallback(null);
        }
    }
}

@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
  if (holder instanceof ProductViewHolder) {
    final Product product = mProducts.get(position);

    Uri uri = Uri.parse(product.getProductImage());
    final ProductViewHolder productViewHolder = (ProductViewHolder) holder;
    productViewHolder.productName.setText(product.getProductName());
    productViewHolder.cardImage.setImageURI(uri);

  }
}

@Override
public int getItemCount() {
    return mProducts == null ? 0 : mProducts.size();
}

public void setLoaded() {
    isLoading = false;
}

@Override
public int getItemViewType(int position) {
    return mProducts.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
}

private class LoadingViewHolder extends ViewHolder {
    public ProgressBar progressBar;

    public LoadingViewHolder(View view) {
        super(view);
        progressBar = (ProgressBar) view.findViewById(R.id.progressBar1);
    }
}

private class ProductViewHolder extends ViewHolder {
    public TextView productName;
    public SimpleDraweeView cardImage;

    public ProductViewHolder(View view) {
        super(view);
        productName = (TextView) view.findViewById(R.id.txt_product_name);
        cardImage = (SimpleDraweeView) view.findViewById(R.id.product_image);
    }
}
}

完整 MainActivityFragment

public class MainActivityFragment extends Fragment {

public static final String STRING_IMAGE_URI = "ImageUri";
public static int SPAN_SIZE = 2;
public static final String STRING_IMAGE_POSITION = "ImagePosition";
public static final String STRING_PRODUCT_NAME = "Name";
private static MainActivity mActivity;
private List<Product> productsArrayList;
private MainActivityAdapter mainActivityAdapter;
private SwipeRefreshLayout swipeRefreshLayout;
private Connectivity connectivity; //Simple class I created to check when internet connection is available or not. Works fine.

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mActivity = (MainActivity) getActivity();
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    swipeRefreshLayout = (SwipeRefreshLayout) inflater.inflate(R.layout.main_layout_recyclerview, container, false);
    setupRecyclerView(swipeRefreshLayout);
    return swipeRefreshLayout;
}

private void setupRecyclerView(final SwipeRefreshLayout swipeRefreshLayout) {
    RecyclerView recyclerView = (RecyclerView) swipeRefreshLayout.findViewById(R.id.recyclerview);

    productsArrayList = new ArrayList<>();

    connectivity = new Connectivity(mActivity);

    //The same data is being displayed across the 3 viewpagers I have for now...
    if (MainActivityFragment.this.getArguments().getInt("type") == 1) {
        SPAN_SIZE = 2;
    } else if (MainActivityFragment.this.getArguments().getInt("type") == 2) {
        SPAN_SIZE = 2;
    } else if (MainActivityFragment.this.getArguments().getInt("type") == 3) {
        SPAN_SIZE = 1;
    }

    //If internet connection is found... fetch content
    if(connectivity.isInternetAvailable()){
        //This fetches the data from the internet and adds it to the products ArrayList declared above.
        fetchOnLoad();
    } else{
        Toast.makeText(mActivity, "No Internet", Toast.LENGTH_SHORT).show();
    }


    //If products were added to the ArrayList, proceed
    if (productsArrayList != null) {
        GridLayoutManager layoutManager = new GridLayoutManager(mActivity,SPAN_SIZE,GridLayoutManager.VERTICAL,false);
        recyclerView.setLayoutManager(layoutManager);
        mainActivityAdapter = new MainActivityAdapter(recyclerView, swipeRefreshLayout, productsArrayList, mActivity);
        recyclerView.setAdapter(mainActivityAdapter);

        swipeRefreshLayout.setColorSchemeColors(getResources().getColor(R.color.colorAccent));


        //Load more listener for the RecyclerView adapter - working just fine. However, I fear it
        //will have the same problem when I start introducing new products. NB: The JSON that is on my server has static information.
        //This limits the number of visible products to 40 for now as I am reusing data from the
        //products ArrayList.
        mainActivityAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
            @Override
            public void onLoadMore() {
                if (productsArrayList.size() <= 40) {
                    swipeRefreshLayout.setRefreshing(true);
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            fetchOnLoad();
                            mainActivityAdapter.notifyDataSetChanged();
                            mainActivityAdapter.setLoaded();
                            swipeRefreshLayout.setRefreshing(false);

                        }
                    }, 1500);
                } else {
                    Toast.makeText(mActivity, "More products coming soon", Toast.LENGTH_SHORT).show();
                }
            }
        });

        //Code for this provided above
        mainActivityAdapter.setOnRefreshMoreListener(new OnRefreshMoreListener() {});
    }
}
//Code for this provided above
public void fetchOnLoad() {}

}

试试这个

//set refresh more listener for the RecyclerView adapter
mainActivityAdapter.setOnRefreshMoreListener(new OnRefreshMoreListener() {
   @Override
    public void onRefreshMore() {
         swipeRefreshLayout.setRefreshing(true);
         new Handler().postDelayed(new Runnable() {
             @Override
             public void run() {
                 productsArrayList.clear();  //I'm removing previous data
                 mainActivityAdapter.notifyDataSetChanged();
                 fetchOnLoad(); //Function that adds new elements to the productsArrayList

                 // There's no need to call these two because they are called in the
                 // JsonArrayRequest in onResponse.
                 //mainActivityAdapter.notifyDataSetChanged();
                 //swipeRefreshLayout.setRefreshing(false);
              }
         }, 1000);
     }
 });

我找到了我认为可以分享的问题解决方案。我在使用 Fresco 时遇到的问题是,当 notifyDataSetChanged() 被调用时,它会很好地加载图像,但不会渲染它们。这样,我每次都留下一个占位符。但是,在滚动出视图然后再次返回时,将显示图像。我不喜欢那样。

我尝试实施此处提供的解决方案 https://github.com/facebook/fresco/issues/687 by trying to cache the SimpleDraweeView in the viewholder, but that did not help in my case. I used the explanation from this link https://teamtreehouse.com/community/now-lets-work-on-oncreateviewholder-i-started-it-for-youall-you-need-to-do-is-to-create-a 以了解如何做到这一点。

我的解决方案是从 Fresco 切换到 Glide,而在我看来,Glide 恰好比 Fresco 更快、响应更快。下面这个简单的代码解决了所有问题...

Glide.with(mActivity)
     .load(profile.getUserImage())
     .placeholder(R.color.stay_color)
     .into(mImageView);