我知道之前曾多次询问过这个问题,但我很困惑为什么有时会加载数据,有时候一旦到达列表末尾就没有加载数据。此外,当我快速滚动列表,并且已加载新数据时,但立即将其返回到列表中的第一项并从服务器中删除下一页中的所有新加载项。这是第二个问题,第三个问题是当我使用SwipeRefreshLayout加载项目时,当我到达列表末尾时,我也没有获得新项目。
我已在我的项目中实现了这个:https://gist.github.com/ssinss/e06f12ef66c51252563e
list.setLayoutManager(manager);
list.setEmptyView(emptyView);
list.setItemAnimator(new DefaultItemAnimator());
list.setAdapter(mAdapter);
loadJokes(1);
list.addOnScrollListener(new EndlessRecyclerOnScrollListener(manager) {
@Override
public void onLoadMore(final int current_page) {
loadMoreJokes(current_page);
}
});
以下是我从服务器加载更多项目的方法:
private void loadMoreJokes(int current_page) {
StringRequest request = new StringRequest(Request.Method.GET, AppConfig.URL_GET_ALL_JOKES + current_page,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
hideDialog();
try {
JSONObject object = new JSONObject(response);
boolean error = object.getBoolean("error");
JSONArray jokes = object.getJSONArray("jokes");
if (!error) {
for (int i = 0; i < jokes.length(); i++) {
JSONObject object1 = jokes.getJSONObject(i);
Joke joke = new Joke();
joke.setId(object1.optInt("id"));
joke.setLikes(object1.optInt("likes"));
joke.setComments(object1.optInt("comments"));
joke.setJoke(object1.optString("joke"));
joke.setCreatedAt(object1.optString("created_at"));
joke.setName(object1.optString("user_name"));
joke.setImagePath(object1.optString("image_path"));
joke.setFacebookUserId(object1.optString("facebook_user_id"));
joke.setCategory(object1.optString("category"));
mJokes.add(joke);
}
menu.showMenu(true);
}
// Notify adapter that data has changed
mAdapter.notifyDataSetChanged();
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
hideDialog();
Toast.makeText(getActivity(), error.getMessage(), Toast.LENGTH_SHORT).show();
}
});
AppController.getInstance().addToRequestQueue(request);
}
以下是当有人启动应用时我正在加载第一个可见项目的方法:
private void loadJokes(int page) {
pDialog.setMessage("Loading..");
showDialog();
StringRequest request = new StringRequest(Request.Method.GET, AppConfig.URL_GET_ALL_JOKES + page,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
mJokes.clear();
hideDialog();
try {
JSONObject object = new JSONObject(response);
boolean error = object.getBoolean("error");
JSONArray jokes = object.getJSONArray("jokes");
if (!error) {
for (int i = 0; i < jokes.length(); i++) {
JSONObject object1 = jokes.getJSONObject(i);
Joke joke = new Joke();
joke.setId(object1.optInt("id"));
joke.setLikes(object1.optInt("likes"));
joke.setComments(object1.optInt("comments"));
joke.setJoke(object1.optString("joke"));
joke.setCreatedAt(object1.optString("created_at"));
joke.setName(object1.optString("user_name"));
joke.setImagePath(object1.optString("image_path"));
joke.setFacebookUserId(object1.optString("facebook_user_id"));
joke.setCategory(object1.optString("category"));
mJokes.add(joke);
}
menu.showMenu(true);
}
// Notify adapter that data has changed
mAdapter.notifyDataSetChanged();
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
hideDialog();
menu.showMenu(true);
Toast.makeText(getActivity(), error.getMessage(), Toast.LENGTH_SHORT).show();
}
});
AppController.getInstance().addToRequestQueue(request);
}
这是onRefresh()
方法:
@Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
refreshItems();
}
}, 5000);
}
private void refreshItems() {
loadJokes(1);
mSwipeRefreshLayout.setRefreshing(false);
}
如果我需要发布更多代码,请告诉我。我真的需要尽快解决这个问题。所以问题如下:
当快速滚动列表时,正在加载新项目,但在此之后它立即返回到列表的开头,当我再次返回列表末尾时,加载更多不响应。
使用SwipRefreshLayout
刷新列表后,滚动也不会在最后响应。
注意:只有当我慢慢浏览列表并且我没有刷到刷新列表时,滚动和加载新项目才有效。
修改
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_jokes, container, false);
mContext = getActivity();
mView = (CoordinatorLayout) view.findViewById(R.id.coordinatorLayout);
TextView tvEmptyText = (TextView) view.findViewById(R.id.tv_empty);
ImageView ivSignal = (ImageView) view.findViewById(R.id.iv_signal);
if (!ConnectionDetector.getInstance(getActivity()).isOnline() && mAdapter == null) {
tvEmptyText.setVisibility(View.VISIBLE);
ivSignal.setVisibility(View.VISIBLE);
showNoInternetSnackbar();
}
// INITIALIZE RECYCLER VIEW
EmptyRecyclerView list = (EmptyRecyclerView) view.findViewById(R.id.list);
mJokes = new ArrayList<>();
mAdapter = new RecyclerJokesAdapter(getActivity(), mJokes, JokesFragment.this, null);
// Progress dialog
pDialog = new ProgressDialog(getActivity());
pDialog.setMessage("Please wait");
pDialog.setIndeterminate(true);
pDialog.setCancelable(false);
showDialog();
View emptyView = inflater.inflate(R.layout.layout_empty_view, container, false);
FloatingActionButton fab1 = (FloatingActionButton) view.findViewById(R.id.fab_funny);
FloatingActionButton fab2 = (FloatingActionButton) view.findViewById(R.id.fab_good_morning);
FloatingActionButton fab3 = (FloatingActionButton) view.findViewById(R.id.fab_good_night);
FloatingActionButton fab4 = (FloatingActionButton) view.findViewById(R.id.fab_all);
menu = (FloatingActionMenu) view.findViewById(R.id.menu_sort_jokes);
fab1.setOnClickListener(this);
fab2.setOnClickListener(this);
fab3.setOnClickListener(this);
fab4.setOnClickListener(this);
mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_container);
mSwipeRefreshLayout.setOnRefreshListener(this);
mSwipeRefreshLayout.setColorSchemeResources(
R.color.refresh_progress_1,
R.color.refresh_progress_2,
R.color.refresh_progress_3);
LinearLayoutManager manager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
list.setLayoutManager(manager);
list.setEmptyView(emptyView);
list.setItemAnimator(new DefaultItemAnimator());
list.setAdapter(mAdapter);
if (ConnectionDetector.getInstance(mContext).isOnline()) {
loadJokes(1);
} else {
showNoInternetSnackbar();
hideDialog();
}
list.addOnScrollListener(new EndlessRecyclerOnScrollListener(manager) {
@Override
public void onLoadMore(final int current_page) {
loadMoreJokes(current_page);
}
});
return view;
}
答案 0 :(得分:1)
在onCreate方法中初始化你的适配器,recyclerView和List
List<MyObject> myList = new ArrayList<>();
recyclerViewAdapter = new RecyclerViewAdapter(context, myList)
myRecyclerView.setAdapter(recyclerViewAdapter);
现在,无论何时加载数据。将数据添加到myList并在adpater上调用notifyDataSetChange
myList.add(data);
recyclerViewAdapter.notifyDataSetChange();
答案 1 :(得分:0)
使用此包装类
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import java.util.List;
public abstract class RecyclerWrapperAdapter<E> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
protected Context context;
protected List<E> objects;
public void setContext(Context context) {
this.context = context;
}
public void setObjects(List<E> objects) {
this.objects = objects;
notifyDataSetChanged();
}
public void add(@NonNull E object) {
objects.add(object);
notifyDataSetChanged();
}
public void add(int position, @NonNull E object) {
if (position < objects.size() && position >= 0) {
objects.add(position, object);
notifyItemChanged(position);
notifyDataSetChanged();
} else if (position >= objects.size()) {
objects.add(object);
notifyDataSetChanged();
}
}
public void set(int position, @NonNull E object) {
if (position < objects.size() && position >= 0) {
objects.set(position, object);
notifyItemChanged(position);
} else if (position >= objects.size()) {
objects.add(object);
notifyDataSetChanged();
}
}
public void remove(@NonNull E object) {
objects.remove(object);
notifyDataSetChanged();
}
public void remove(int position) {
if (position >=0 && position < objects.size()) {
objects.remove(position);
notifyDataSetChanged();
}
}
public void removeAll() {
objects.clear();
notifyDataSetChanged();
}
public E getItem(int position) {
return objects.get(position);
}
@Override
public int getItemCount() {
return objects.size();
}
}
答案 2 :(得分:0)
我这样做了:
MainActivity .java
public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener, onRecyclerViewListener {
private RecyclerView mRecyclerView;
private TextView tvEmptyView;
private LinearLayoutManager mLayoutManager;
private List<Object> studentList;
protected Handler handler;
private int count = 0;
private SwipeRefreshLayout swipeRefreshLayout;
private MyRecycleAdapter myRecycleAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
swipeRefreshLayout = (SwipeRefreshLayout)findViewById(R.id.swiperefresh);
swipeRefreshLayout.setOnRefreshListener(this);
swipeRefreshLayout.setColorSchemeResources(R.color.blue, R.color.purple, R.color.green, R.color.orange);
tvEmptyView = (TextView) findViewById(R.id.empty_view);
mRecyclerView = (RecyclerView)findViewById(R.id.recyclerView);
studentList = new ArrayList<Object>();
handler = new Handler();
loadData();
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(this);
mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
// use a linear layout manager
mRecyclerView.setLayoutManager(mLayoutManager);
myRecycleAdapter = new MyRecycleAdapter(mRecyclerView, studentList, R.layout.list_row, R.layout.progressbar_item, this);
myRecycleAdapter.setLoadMoreEnable(true);
myRecycleAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
@Override
public void onLoadMore() {
count++;
if (count == 4) {
count = 0;
myRecycleAdapter.setLoadMoreEnable(false);
} else {
myRecycleAdapter.setLoadMoreEnable(true);
}
//add null , so the adapter will check view_type and show progress bar at bottom
studentList.add(null);
myRecycleAdapter.notifyItemInserted(studentList.size() - 1);
handler.postDelayed(new Runnable() {
@Override
public void run() {
// remove progress item
studentList.remove(studentList.size() - 1);
myRecycleAdapter.notifyItemRemoved(studentList.size());
//add items one by one
int start = studentList.size();
int end = start + 20;
for (int i = start + 1; i <= end; i++) {
studentList.add(new Student("Student " + i, "AndroidStudent" + i + "@gmail.com"));
myRecycleAdapter.notifyItemInserted(studentList.size());
}
myRecycleAdapter.setLoaded();
//or you can add all at once but do not forget to call mAdapter.notifyDataSetChanged();
}
}, 1000);
}
});
ItemViewHolderNew.setRecyclerListener(this);
mRecyclerView.setAdapter(myRecycleAdapter);
if (studentList.isEmpty()) {
mRecyclerView.setVisibility(View.GONE);
tvEmptyView.setVisibility(View.VISIBLE);
} else {
mRecyclerView.setVisibility(View.VISIBLE);
tvEmptyView.setVisibility(View.GONE);
}
}
private void loadData() {
for (int i = 1; i <= 20; i++) {
studentList.add(new Student("Student " + i, "androidstudent" + i + "@gmail.com"));
}
}
@Override
public void onRefresh() {
swipeRefreshLayout.setRefreshing(true);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
swipeRefreshLayout.setRefreshing(false);
}
},5000);
}
@Override
public void onBindView(View view, final ItemViewHolderNew itemViewHolder) {
itemViewHolder.tvName = (TextView) view.findViewById(R.id.tvName);
itemViewHolder.tvEmailId = (TextView) view.findViewById(R.id.tvEmailId);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position, Object object, ItemViewHolderNew itemViewHolder) {
Student studentObj = (Student)object;
itemViewHolder.tvName.setText(studentObj.getName());
itemViewHolder.tvEmailId.setText(studentObj.getEmailId());
itemViewHolder.student= studentObj;
}
@Override
public void setClickListener(View view, ItemViewHolderNew itemViewHolder) {
Toast.makeText(view.getContext(), "OnClick :" + itemViewHolder.student.getName() + " \n " + itemViewHolder.student.getEmailId(), Toast.LENGTH_SHORT).show();
}
public static class ItemViewHolderNew extends RecyclerView.ViewHolder{
public TextView tvName, tvEmailId;
public Student student;
private static onRecyclerViewListener mListener;
public static void setRecyclerListener(onRecyclerViewListener listener){
mListener = listener;
}
public ItemViewHolderNew(View itemView) {
super(itemView);
mListener.onBindView(itemView, this);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setClick(v);
}
});
}
private void setClick(View v) {
mListener.setClickListener(v, this);
}
}
}
添加 OnLoadMoreListener.java 界面
public interface OnLoadMoreListener {
void onLoadMore();
}
将 Student.java 添加为模型类
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String emailId;
public Student(String name, String emailId) {
this.name = name;
this.emailId = emailId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmailId() {
return emailId;
}
public void setEmailId(String emailId) {
this.emailId = emailId;
}
}
<强> activity_main.xml中强>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context=".MainActivity"
tools:showIn="@layout/activity_main">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swiperefresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
</android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>
<TextView
android:id="@+id/empty_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="No Records Here !"
android:visibility="gone" />
</RelativeLayout>
<强> list_row.xml 强>
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent"
android:padding="5dp"
android:background="?android:selectableItemBackground">
<TextView
android:id="@+id/tvName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="Name"
android:textColor="@android:color/black"
android:textSize="18sp" />
<TextView
android:id="@+id/tvEmailId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/tvName"
android:layout_margin="5dp"
android:text="Email Id"
android:textColor="@android:color/black"
android:textSize="12sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="Name"
android:textColor="@android:color/black"
android:textSize="18sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/tvName"
android:layout_margin="5dp"
android:text="Email Id"
android:textColor="@android:color/black"
android:textSize="12sp" />
</LinearLayout>
</android.support.v7.widget.CardView>
<强> progressbar_item.xml 强>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:gravity="center"
android:layout_width="match_parent" android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progressBar1"
android:layout_width="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_height="wrap_content" />
</LinearLayout>
使用Endless正常工作,滑动刷新,加载更多RecyclerView。
希望这会对你有所帮助。
答案 3 :(得分:0)
Volley RequestQueue使用线程池进行网络请求。
/** Number of network request dispatcher threads to start. */
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
显然,当你fast scrolling through the list
快速连续生成多个请求时。
有可能异步/不按顺序接收响应。此外,“没有更多数据”响应/错误响应等可能会在下一页数据的响应之前到达,这可能会导致您的应用出现意外行为。
特别注意这将如何影响您的mJokes
ArrayList成员变量。