我正在构建一个具有用户评论页面的Android应用程序,该页面可能包含多达1,000条评论。尝试一次全部获取所有注释并将其加载到recyclerView中,这不是一个好习惯。因此,我想要一种可以批量加载评论的方法,一次可以加载10条,并且当用户滚动recylcerView时,它应该加载另外10条,等等。
问题是我正在使用Volley将注释作为JSON对象获取,我不认为Volley具有批处理功能。我也不确定是否会对我的PHP文件进行某些分页。我已经看过YouTube上的一些教程,并在Stack Overflow上检查了答案,包括This和This 但是他们并没有真正解决我的问题。
这是我的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());
}
$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);
任何有关如何实现这一目标或提供正确方法的解决方案都将受到高度赞赏。 谢谢。
答案 0 :(得分:1)
这是上面史蒂夫·卡莫建议的修改后的代码。这就是我修改代码的方式:
我修改的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);
然后我初始化了两个Integer值:
int limit = 10;
int offset = 0;
然后,我为我的recyclerView创建了一个OnscrollListener,并创建了另一个方法来测试用户是否滚动到最后一项:
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;
}
});
}
答案 1 :(得分:0)
我以前使用REST api进行分页。 但是对于您而言,最简单的方法是这样做:
当您第一次调用以获取前10个参数时,请在https://example.com/index.php?limit=10这样的api参数查询中附加初始值10。
在您的php代码中,接收值'limit'并将其附加到您的sql查询中,如下所示:
SELECT *从comments_table中,在comments_table.story_id = '$ storyID'ORDER BY create_date DESC LIMIT 10 OFFSET'$ limit'
在LIMIT and 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