Как использовать Android Pagination с Volley при получении данных JSON - PullRequest
2 голосов
/ 29 октября 2019

Я создаю приложение для Android, которое имеет страницу комментариев пользователя, которая может содержать до 1000 комментариев. Это не будет хорошей практикой пытаться получить и загрузить все комментарии в recyclerView сразу. Итак, я хочу подход, который будет загружать комментарии в пакетном режиме, может быть по 10 за раз, и когда пользователь прокручивает recylcerView, он должен загрузить еще 10 и т. Д.

Проблема в том, что я использую Volley дляполучить комментарии как объекты JSON, и я не думаю, что у Volley есть пакетная обработка. Я также не уверен, что некоторые из страниц будут сделаны в моем PHP-файле. Я просмотрел несколько руководств на Youtube и проверил на переполнение стека ответы, включая Это и Это Но они не решают мою проблему.

Это мой PHPcode:

<?php

    define('DB_HOST','*******');
    define('DB_USER','********');
    define('DB_PASS','********');
    define('DB_NAME','***********');

    $conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);

    if(mysqli_connect_errno()){
        die('Unable to connect to database '.mysqli_connect_error());
    }

        $conn->set_charset("utf8mb4");

        $storyID = $_GET["storyid"];

    $stmt = $conn->prepare("SELECT comments_table.comment_id, comments_table.username, comments_table.comment, comments_table.date_time, comments_table.story_id, comments_table.imageURL, comments_table.number_of_likes, users.title, comments_table.is_reply, comments_table.reply_username, comments_table.reply_comment, comments_table.reply_id  FROM comments_table INNER JOIN users ON comments_table.username = users.username WHERE comments_table.story_id = '$storyID'");

    $stmt->execute();

    $stmt->bind_result($comment_id, $username, $comment, $date_time, $story_id, $imageURL, $number_of_likes, $title, $is_reply, $reply_username, $reply_comment, $reply_id);

    $comments = array();

    while($stmt->fetch()){
        $temp = array();
        $temp['comment_id'] = $comment_id;
        $temp['username'] = $username;
        $temp['comment'] = $comment;
                $temp['date_time'] = $date_time;
                $temp['story_id'] = $story_id;
                $temp['imageURL'] = $imageURL;
                $temp['number_of_likes'] = $number_of_likes;
                $temp['title'] = $title;
                $temp['is_reply'] = $is_reply;
                $temp['reply_username'] = $reply_username;
                $temp['reply_comment'] = $reply_comment;
                $temp['reply_id'] = $reply_id;

        array_push($comments, $temp);

    }

    echo json_encode($comments);

Это фрагмент кода, который я использовал при получении комментариев с помощью Volley:

private void loadComments() {
        progressBar.setVisibility(View.VISIBLE);
        StringRequest stringRequest = new StringRequest(Request.Method.GET, URL_COMMENTS + String.valueOf(storyID),
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        try {
                            JSONArray array = new JSONArray(response);
                            for (int i = 0; i < array.length(); i++) {
                                JSONObject comment = array.getJSONObject(i);

                                if (comment.getInt("story_id") == storyID) {
                                    commentList.add(new GetComments(
                                            comment.getInt("comment_id"),
                                            comment.getString("username"),
                                            comment.getString("comment"),
                                            comment.getInt("story_id"),
                                            comment.getString("imageURL"),
                                            comment.getString("date_time"),
                                            comment.getInt("number_of_likes"),
                                            comment.getString("title"),
                                            comment.getInt("is_reply"),
                                            comment.getInt("reply_id"),
                                            comment.getString("reply_username"),
                                            comment.getString("reply_comment")
                                    ));

                                }

                            }

                            if (commentList.isEmpty()){
                                noCommentTextView.setVisibility(View.VISIBLE);
                            }
                            //creating adapter object and setting it to recyclerview
                            adapterJSON = new CommentAdapter(getApplicationContext(), commentList, Comment.this, rootView, storyID);
                            recyclerView.setAdapter(adapterJSON);

                        } catch (JSONException e) {
                            progressBar.setVisibility(View.GONE);
                            Toast.makeText(Comment.this,"Error loading comments: Check internet connection...",Toast.LENGTH_LONG).show();
                            e.printStackTrace();
                        }
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        progressBar.setVisibility(View.GONE);
                        Toast.makeText(Comment.this,"Error loading comments: Check internet connection...",Toast.LENGTH_LONG).show();
                    }
                });


        final RequestQueue requestQueue = Volley.newRequestQueue(Comment.this);
        requestQueue.add(stringRequest);
        requestQueue.start();

        requestQueue.addRequestFinishedListener(new RequestQueue.RequestFinishedListener<Object>() {
            @Override
            public void onRequestFinished(Request<Object> request) {
                progressBar.setVisibility(View.GONE);
            }
        });

    }

А это мои элементы recyclerView и layoutManager:

        recyclerView = findViewById(R.id.recyclerView);
        linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setReverseLayout(true);
        linearLayoutManager.setStackFromEnd(true);
        recyclerView.setLayoutManager(linearLayoutManager);

Будем весьма благодарны за любые решения о том, как этого добиться или предложить правильный подход. Спасибо.

Ответы [ 2 ]

1 голос
/ 29 октября 2019

Вот модифицированный код, предложенный Стивом Камау выше. Вот как я изменил свой код:

Мой модифицированный код PHP:

<?php

    define('DB_HOST','*******');
    define('DB_USER','*******');
    define('DB_PASS','******');
    define('DB_NAME','*********');

    $conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);

    if(mysqli_connect_errno()){
        die('Unable to connect to database '.mysqli_connect_error());
    }

        //mysqli_set_charset($conn,"utf8mb4_unicode_ci");
        $conn->set_charset("utf8mb4");

        $storyID = $_GET["storyid"];
        $limit = $_GET["limit"];
        $offset = $_GET["offset"];

    $stmt = $conn->prepare("SELECT comments_table.comment_id, comments_table.username, comments_table.comment, comments_table.date_time, comments_table.story_id, comments_table.imageURL, comments_table.number_of_likes, users.title, comments_table.is_reply, comments_table.reply_username, comments_table.reply_comment, comments_table.reply_id  FROM comments_table INNER JOIN users ON comments_table.username = users.username WHERE comments_table.story_id = '$storyID' ORDER BY comments_table.date_time DESC LIMIT $limit OFFSET $offset");

    $stmt->execute();

    $stmt->bind_result($comment_id, $username, $comment, $date_time, $story_id, $imageURL, $number_of_likes, $title, $is_reply, $reply_username, $reply_comment, $reply_id);

    $comments = array();

    while($stmt->fetch()){
        $temp = array();
        $temp['comment_id'] = $comment_id;
        $temp['username'] = $username;
        $temp['comment'] = $comment;
                $temp['date_time'] = $date_time;
                $temp['story_id'] = $story_id;
                $temp['imageURL'] = $imageURL;
                $temp['number_of_likes'] = $number_of_likes;
                $temp['title'] = $title;
                $temp['is_reply'] = $is_reply;
                $temp['reply_username'] = $reply_username;
                $temp['reply_comment'] = $reply_comment;
                $temp['reply_id'] = $reply_id;

        array_push($comments, $temp);

    }

    echo json_encode($comments);

Затем я инициализировал два целочисленных значения:

int limit = 10;
int offset = 0;

Затем я создал OnscrollListenerдля моего recyclerView и создал еще один метод для проверки прокрутки пользователем до последнего элемента:

private RecyclerView.OnScrollListener endOnScrollListener = new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
        }

        @Override
        public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);

            if(isLastItemDisplaying(recyclerView)){
                Log.i("Reached end: ", "Load more");
                loadMoreComments();
            }
        }
    };

    private boolean isLastItemDisplaying(RecyclerView recyclerView){
        //Check if the adapter item count is greater than 0
        if(recyclerView.getAdapter().getItemCount() != 0){
            //get the last visible item on screen using the layout manager
            int lastVisibleItemPosition = ((LinearLayoutManager)recyclerView.getLayoutManager()).findLastCompletelyVisibleItemPosition();

            if(lastVisibleItemPosition != RecyclerView.NO_POSITION && lastVisibleItemPosition == recyclerView.getAdapter().getItemCount()-1){
                return true;
            }

        }
        return false;

    }

И, наконец, вот мой метод loadMoreComments ():

private void loadMoreComments() {
        refreshLayout.setRefreshing(true);
        StringRequest stringRequest = new StringRequest(Request.Method.GET, URL_COMMENTS + String.valueOf(storyID)+"&limit="+String.valueOf(limit)
                +"&offset="+String.valueOf(offset),
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        try {
                            JSONArray array = new JSONArray(response);
                            for (int i = 0; i < array.length(); i++) {
                                JSONObject comment = array.getJSONObject(i);

                                if (comment.getInt("story_id") == storyID) {

                                    commentList.add(adapterJSON.getItemCount(), (new GetComments(
                                            comment.getInt("comment_id"),
                                            comment.getString("username"),
                                            comment.getString("comment"),
                                            comment.getInt("story_id"),
                                            comment.getString("imageURL"),
                                            comment.getString("date_time"),
                                            comment.getInt("number_of_likes"),
                                            comment.getString("title"),
                                            comment.getInt("is_reply"),
                                            comment.getInt("reply_id"),
                                            comment.getString("reply_username"),
                                            comment.getString("reply_comment")
                                    )));
                                    adapterJSON.notifyItemInserted(adapterJSON.getItemCount());
                                }


                            }


                        } catch (JSONException e) {
                            progressBar.setVisibility(View.GONE);
                            Toast.makeText(Comment.this,"Error loading comments: Check internet connection...",Toast.LENGTH_LONG).show();
                            e.printStackTrace();
                            Log.i("Error:", e.getMessage());
                        }
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        progressBar.setVisibility(View.GONE);
                        Toast.makeText(Comment.this,"Error loading comments: Check internet connection...",Toast.LENGTH_LONG).show();
                        Log.i("Error:", error.getMessage());
                    }
                });


        final RequestQueue requestQueue = Volley.newRequestQueue(Comment.this);
        requestQueue.add(stringRequest);
        requestQueue.start();

        requestQueue.addRequestFinishedListener(new RequestQueue.RequestFinishedListener<Object>() {
            @Override
            public void onRequestFinished(Request<Object> request) {
                refreshLayout.setRefreshing(false);
                offset = offset + 5;
            }
        });

    }
0 голосов
/ 29 октября 2019

Я раньше работал с нумерацией страниц с REST apis. Но для вашего случая самый простой способ сделать это:

Когда вы делаете первый вызов, чтобы получить первые 10, добавьте начальное значение 10 в запрос вашего параметра API, например, https://example.com/index.php?limit=10;

В вашем php-коде получите значение 'limit' и добавьте его в свой sql-запрос следующим образом:

SELECT * from comments_table WHERE comments_table.story_id = '$ storyID' ORDER BY create_date DESC LIMIT 10OFFSET '$ limit'

Проверьте больше в LIMIT и OFFSET

Это означает, что ваше приложение для Android будет держать счетчик сортов для лимита. Вы можете легко достичь этого:

int limit = 10; //initial limit

//after success result from your api, just append a count
limit = limit + 10;
//and use this new limit in subsequent api calls to fetch comments

Наиболее важным из них является, конечно, отслеживание событий прокрутки, чтобы узнать, достиг ли пользователь конца списка комментариев, легко сделать этот пользователь https://stackoverflow.com/a/46342525/4209724

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...