【问题标题】:RecyclerView is not ALWAYS showing resultsRecyclerView 并不总是显示结果
【发布时间】:2018-01-18 08:04:57
【问题描述】:

我遇到了一个奇怪的问题,即 RecyclerView 在显示我的结果时被击中或错过。我正在使用 Volley 来调用服务器上的 REST API,该服务器返回一个 json 文件。 Log.i() 显示我的结果每次都被抓取,但它们并不总是显示在屏幕上。我会说他们大约有 30% 的时间出现。

片段列表

public class FragmentList extends Fragment {

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View v = inflater.inflate(R.layout.fragment_fragment_list, container, false);
    RecyclerView recyclerView;
    FoodAdapter adapter;

    final List<Food> foodList = new ArrayList<>();
    recyclerView = v.findViewById(R.id.recyclerView);
    recyclerView.setHasFixedSize(true);

    recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

    String url = "https://www.example.com";
    StringRequest sr = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            try {
                Log.i(TAG, response);
                JSONArray foodResp = new JSONArray(response);
                for (int i = 0; i < foodResp.length(); i++) {
                    JSONObject foodObj = foodResp.getJSONObject(i);
                    foodList.add(
                            new Food(
                                    1,
                                    R.drawable.ic_launcher_background,
                                    foodObj.getString("mealTitle"),
                                    foodObj.getString("mealDesc"))
                    );
                }

            } catch (Exception e) {
                Log.i(TAG, "Error: " + e.getMessage());
            }

        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Log.i(TAG, "err: " + error.toString());
        }
    }){
        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
            Map<String, String> params = new HashMap<>();
            params.put("data", "value");

            return params;
        }
    };
    Volley.newRequestQueue(getActivity()).add(sr);

    adapter = new FoodAdapter(getActivity(), foodList);
    recyclerView.setAdapter(adapter);

    return v;
}

}

fragment_fragment_list.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.localfridge.localfridge.FragmentList">

<!-- TODO: Update blank fragment layout -->

<android.support.v7.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

</android.support.v7.widget.RecyclerView>

FoodAdapter 只是装箱

FoodAdapter.java

ublic class FoodAdapter extends RecyclerView.Adapter<FoodAdapter.FoodViewHolder> {

private Activity mCtx;
private List<Food> foodList;

public FoodAdapter(Activity mCtx, List<Food> foodList) {
    this.mCtx = mCtx;
    this.foodList = foodList;
}

@Override
public FoodViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(mCtx);
    View view = inflater.inflate(R.layout.list_item, null);

    FoodViewHolder foodView = new FoodViewHolder(view);

    return foodView;
}

@Override
public void onBindViewHolder(FoodViewHolder holder, int position) {
    Food food = foodList.get(position);
    holder.txtFoodTitle.setText(food.getFoodTitle());
    holder.txtFoodDesc.setText(food.getFoodDesc());
    holder.imageView.setImageDrawable(mCtx.getResources().getDrawable(food.getImage(), null));
}

@Override
public int getItemCount() {
    return foodList.size();
}

class FoodViewHolder extends RecyclerView.ViewHolder {
    ImageView imageView;
    TextView txtFoodTitle, txtFoodDesc, txtFoodLoc;

    public FoodViewHolder(View itemView) {
        super(itemView);
        imageView = itemView.findViewById(R.id.foodImg);
        txtFoodTitle = itemView.findViewById(R.id.foodTitle);
        txtFoodDesc = itemView.findViewById(R.id.foodDesc);
    }
}
}

【问题讨论】:

  • onResponse 中的 for 循环之后调用 adapter.notifyDataSetChanged()
  • 在这种情况下调用adapter.notifyItemRangeChanged()可以获得更好的性能。

标签: java android android-recyclerview android-volley


【解决方案1】:

因为Volley Requests 是异步的。所以当你得到结果时填写你的适配器并设置适配器,意味着当onResponse被调用时

解决方案 1

    @Override
    public void onResponse(String response) {
        try {
            Log.i(TAG, response);
            JSONArray foodResp = new JSONArray(response);
            for (int i = 0; i < foodResp.length(); i++) {
                JSONObject foodObj = foodResp.getJSONObject(i);
                foodList.add(
                        new Food(
                                1,
                                R.drawable.ic_launcher_background,
                                foodObj.getString("mealTitle"),
                                foodObj.getString("mealDesc"))
                );
            }
          adapter = new FoodAdapter(getActivity(), foodList);
          recyclerView.setAdapter(adapter);
        } catch (Exception e) {
            Log.i(TAG, "Error: " + e.getMessage());
        }

    }

更新

解决方案 2

按照 cmets 中的建议。您可以提前设置适配器,但在这种情况下,您必须通知适配器数据已更改

@Override
    public void onResponse(String response) {
        try {
            Log.i(TAG, response);
            JSONArray foodResp = new JSONArray(response);
            for (int i = 0; i < foodResp.length(); i++) {
                JSONObject foodObj = foodResp.getJSONObject(i);
                foodList.add(
                        new Food(
                                1,
                                R.drawable.ic_launcher_background,
                                foodObj.getString("mealTitle"),
                                foodObj.getString("mealDesc"))
                );
            }
         if(adapter!=null)
        {
          adapter.notifyDataSetChanged();
        }
        } catch (Exception e) {
            Log.i(TAG, "Error: " + e.getMessage());
        }

    }

【讨论】:

  • 他可以提前设置适配器。但他确实必须调用 notifyDataSetChanged 来刷新它。
  • 非常感谢@GabeSechan 和 zaid!这解决了我的问题。
  • @j_timko 很高兴知道
猜你喜欢
  • 2016-11-25
  • 1970-01-01
  • 1970-01-01
  • 2018-04-19
  • 1970-01-01
  • 1970-01-01
  • 2017-11-12
  • 2015-07-22
  • 1970-01-01
相关资源
最近更新 更多