【问题标题】:Parsing JSON after setting Adapter to RecyclerView. Items still displayed将 Adapter 设置为 RecyclerView 后解析 JSON。仍然显示的项目
【发布时间】:2017-11-29 19:45:45
【问题描述】:

我不明白以下内容。 我在调用 parseJSON() 之前创建了 Adapter 并为其设置了一个新的空 ArrayList。我不调用 notifyDataSetChanged 并且仍然显示项目。为什么不是空的?

public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private ExampleAdapter mAdapter;
private ArrayList<ExampleItem> mExampleList;
private RequestQueue mRequestQueue;

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

    mRecyclerView = findViewById(R.id.recycler_view);
    mRecyclerView.setHasFixedSize(true);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this));

    mExampleList = new ArrayList<>();
    mAdapter = new ExampleAdapter(MainActivity.this, mExampleList);
    mRecyclerView.setAdapter(mAdapter);

    mRequestQueue = Volley.newRequestQueue(this);

    parseJSON();
}

private void parseJSON() {
    String url = "https://pixabay.com/api/?key=5303976-fd6581ad4ac165d1b75cc15b3&q=kitten&image_type=photo&pretty=true";

    JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, null,
            new Response.Listener<JSONObject>() {
                @Override
                public void onResponse(JSONObject response) {
                    try {
                        JSONArray jsonArray = response.getJSONArray("hits");

                        for (int i = 0; i < jsonArray.length(); i++) {
                            JSONObject hit = jsonArray.getJSONObject(i);

                            String userName = hit.getString("user");
                            String imageUrl = hit.getString("webformatURL");
                            int likeCount = hit.getInt("likes");

                            mExampleList.add(new ExampleItem(imageUrl, userName, likeCount));
                        }

                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            error.printStackTrace();
        }
    });

    mRequestQueue.add(request);
}
}

另外在这里设置适配器的合适位置在哪里?我应该在解析数据后直接在 parseJSON 方法中设置它吗?还是应该像现在这样设置,然后调用 notifyDataSetChanged?

【问题讨论】:

    标签: android json android-recyclerview android-volley


    【解决方案1】:

    我在调用 parseJSON() 之前创建了 Adapter,并为其设置了一个新的空 ArrayList。我不调用 notifyDataSetChanged 并且仍然显示项目。为什么不是空的?

    我没有你的适配器代码,所以我不能肯定地说,但我敢打赌你的适配器和你的活动正在共享对 mExampleList 的引用。想象一下您的适配器如下所示:

    public class ExampleAdapter ... {
    
        private ArrayList<ExampleItem> list;
    
        public ExampleAdapter(Context context, ArrayList<ExampleItem> list) {
            ...
            this.list = list;
            ...
        }
    }
    

    当您调用 new ExampleAdapter(MainActivity.this, mExampleList) 并稍后将项目添加到 mExampleList 时,您还将向适配器添加项目。如果您希望适配器不与传入列表的任何人共享列表,则应在适配器的构造函数中制作副本:

    this.list = new ArrayList<>(list);
    

    另外在这里设置适配器的合适位置在哪里?我应该在解析数据后直接在 parseJSON 方法中设置它吗?还是应该像现在这样设置,然后调用 notifyDataSetChanged?

    您现在将适配器分配给 recyclerview 的方式很好。只要您将更改通知适配器,您就可以在分配适配器后更新支持列表。

    更新

    注意我解析后没有调用notifyDataSetChanged,所以我很困惑

    如果您的JsonObjectRequest 完成得足够快,那没关系。只要列表在 RecyclerView 首次绘制自身时有数据,就会显示该数据。

    作为证明,我编写了这个小应用程序,它创建一个空字符串列表,将其传递给适配器,然后再更新它:

    strings = new ArrayList<>();
    
    RecyclerView recycler = findViewById(R.id.recycler);
    recycler.setAdapter(new MyAdapter(strings));
    
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            strings.add("Hello");
            strings.add("world!");
        }
    }, 30);
    

    30 毫秒的延迟足以跳过至少一帧绘图,但 RecyclerView 仍然显示我的“hello world”消息。

    【讨论】:

    • 感谢您的回答。但是请注意,我解析后没有调用 notifyDataSetChanged,这就是我如此困惑的原因。
    • @FlorianWalther 我更新了我的答案来解决这个问题。
    • 非常感谢。我假设是这样的。但我还是应该在添加后通知适配器,对吧?以及解析完成后在jsonParse方法中设置适配器的做法你怎么看?
    • @FlorianWalther 将适配器分配给 recyclerview 后,您应该在更改支持数据结构时始终通知它。您可以随时随意设置适配器,无论是在 onCreate() 还是其他地方;唯一真正要遵循的最佳实践是通知适配器更改总是比重新设置新适配器到 recyclerview 更有效。
    • 非常感谢,您的帮助非常迅速。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-06
    • 2018-11-12
    • 1970-01-01
    • 1970-01-01
    • 2019-10-15
    • 2016-04-19
    • 2013-04-20
    相关资源
    最近更新 更多