【问题标题】:New images not displaying after calling notifyDataSetChanged() on Fresco在 Fresco 上调用 notifyDataSetChanged() 后未显示新图像
【发布时间】:2018-01-20 17:57:17
【问题描述】:

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

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

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

我研究了这个问题并遇到了这个问题:https://github.com/facebook/fresco/issues/687。但是该帖子并未完全说明如何正确设置。

下面是我的代码sn-ps:

刷新片段(MainActivityFragment 类)

//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);

  }
}

就像我在上面发布的链接中一样,我也认为 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);
}

问题截图 这是截图的链接: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() {}

}

【问题讨论】:

  • fetchOnLoad()的post code;
  • 添加在上面。谢谢。

标签: android android-recyclerview notifydatasetchanged fresco


【解决方案1】:

试试这个

//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);
     }
 });

【讨论】:

  • 嘿,我试过了,结果还是一样。加载新图像时(调用 notifyDataSetChanged 后)...仅显示占位符图像。这是一个视觉表示。我认为这将有助于突出问题:imgur.com/QQjEviS
  • 你能把MainActivityAdapter的完整代码贴出来吗,那里可能遗漏了什么
  • 还有productsproductsArrayList在哪里? ArrayList 是如何传递给 MainActivityAdapter 的?
  • 根据要求,我已经包含了 MainActivityAdapter 和 MainActivityFragment 的完整代码。澄清一下,我希望应用程序在用户滑动刷新后立即显示新获取的图像。目前,该应用程序仅在滑动后显示占位符图像。但是,再次向下和向上滚动会显示图像 - 这并不理想。
【解决方案2】:

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

我尝试通过尝试在视图中缓存 SimpleDraweeView 来实现https://github.com/facebook/fresco/issues/687 此处提供的解决方案,但这对我的情况没有帮助。我使用此链接 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);

【讨论】:

    猜你喜欢
    • 2019-06-30
    • 2018-11-29
    • 2018-07-13
    • 1970-01-01
    • 1970-01-01
    • 2016-05-20
    • 2012-01-12
    • 1970-01-01
    • 2021-02-17
    相关资源
    最近更新 更多