我正在使用this Retrofit Demo来解析JSON和this,以在RecyclerView中实现无限滚动
我已经成功解析了JSON数据,但无法将该数据填充到RecyclerView
中您可以下载完整代码here以查看结尾
日志说:
03-10 18:15:39.872 24744-24766/app.retrofit_chucknorries D/Retrofit: <--- HTTP 200 http://api.icndb.com/jokes/jokenumber (7112ms)
03-10 18:15:39.873 24744-24766/app.retrofit_chucknorries D/Retrofit: Date: Thu, 10 Mar 2016 12:45:40 GMT
03-10 18:15:39.873 24744-24766/app.retrofit_chucknorries D/Retrofit: Server: Apache
03-10 18:15:39.873 24744-24766/app.retrofit_chucknorries D/Retrofit: Access-Control-Allow-Origin: *
03-10 18:15:39.873 24744-24766/app.retrofit_chucknorries D/Retrofit: Access-Control-Allow-Methods: GET
03-10 18:15:39.874 24744-24766/app.retrofit_chucknorries D/Retrofit: Transfer-Encoding: chunked
03-10 18:15:39.874 24744-24766/app.retrofit_chucknorries D/Retrofit: Content-Type: application/json
03-10 18:15:39.875 24744-24766/app.retrofit_chucknorries D/Retrofit: OkHttp-Selected-Protocol: http/1.1
03-10 18:15:39.876 24744-24766/app.retrofit_chucknorries D/Retrofit: OkHttp-Sent-Millis: 1457613939563
03-10 18:15:39.876 24744-24766/app.retrofit_chucknorries D/Retrofit: OkHttp-Received-Millis: 1457613939824
03-10 18:15:40.860 24744-24766/app.retrofit_chucknorries D/Retrofit: { "type": "success", "value": [ { "id": 1, "joke": "Chuck Norris uses ribbed condoms inside out, so he gets the pleasure.", "categories": ["explicit"] }, { "id": 2, "joke": "MacGyver can build an airplane out of gum and paper clips. Chuck Norris can kill him and take it.", "categories": [] }, { "id": 584, "joke": "Only Chuck Norris shuts down websites without due process, not SOPA or PIPA.", "categories": [] } ] }
03-10 18:15:40.871 24744-24766/app.retrofit_chucknorries D/Retrofit: <--- END HTTP (79106-byte body)
03-10 18:15:41.740 24744-24744/app.retrofit_chucknorries D/list::-: [app.retrofit_chucknorries.model.Value@420c3388, app.retrofit_chucknorries.model.Value@420c3730, app.retrofit_chucknorries.model.Value@420c3a10, app.retrofit_chucknorries.model.Value@420c3ce8, app.retrofit_chucknorries.model.Value@420c4060, app.retrofit_chucknorries.model.Value@420c43a0, app.retrofit_chucknorries.model.Value@420c4690, app.retrofit_chucknorries.model.Value@420c4900, app.retrofit_chucknorries.model.Value@420c4d40, app.retrofit_chucknorries.model.Value@420c4ff8, app.retrofit_chucknorries.model.Value@420c52f0, app.retrofit_chucknorries.model.Value@420c5650, app.retrofit_chucknorries.model.Value@420c59a0, app.retrofit_chucknorries.model.Value@420c5d40, app.retrofit_chucknorries.model.Value@420c6c58, app.retrofit_chucknorries.model.Value@420c7080, app.retrofit_chucknorries.model.Value@420c7310, app.retrofit_chucknorries.model.Value@420c75a0, app.retrofit_chucknorries.model.Value@420c7930, app.retrofit_chucknorries.model.Value@420c7c88, app.retrofit_chucknorries.model.Value@420c8320, app.retrofit_chucknorries.model.Value@420c8690, app.retrofit_chucknorries.model.Value@420c8940, app.retrofit_chucknorries.model.Value@420c8cc8, app.retrofit_chucknorries.model.Value@420c9048, app.retrofit_chucknorries.model.Value@420c92c0, app.retrofit_chucknorries.model.Value@420c95d8, app.retrofit_chucknorries.model.Value@420c9908, app.retrofit_chucknorries.model.Value@420c9ca0, app.retrofit_chucknorries.model.Value@420ca160, app.retrofit_chucknorries.model.Value@420ca3f0, app.retrofit_chucknorries.model.Value@420ca6e0, app.retrofit_chucknorries.model.Value@420ca9a0, app.retrofit_chucknorries.model.Value@420cad98, app.retrofit_chucknorries.model.Value@420cb030, app.retrofit_chucknorries.model.Value@420cb310, app.retrofit_chucknorries.model.Value@420cb5c0, app.retrofit_chucknorries.model.Value@420cb878, app.retrofit_chucknorries.model.Value@420cbb50, app.retrofit_chucknorries.model.Value@420cbf08, app.retrofit_chucknorries.model.Value@420cc208, app.retrofit_chucknorries.model.Value@420cc5b0, app.retrofit_chucknorries.model.Value@420cc8d0, app.retrofit_chucknorries.model.Value@420ccc18, app.retrofit_chucknorries.model.Value@420cceb0, app.retrofit_chucknorries.model.Value@420cd228, app.retrofit_chucknorries.model.Value@420cd500, app.retrofit_chucknorries.model.Value@420cd878, app.retrofit_chucknorries.model.Value@420cdb50, app.retrofit_chucknorries.model.Value@420cde28, app.retrofit_chucknorries.model.Value@420ce138, app.retrofit_chucknorries.model.Value@420ce410, app.retrofit_chucknorries.model.Value@420ce798, app.retrofit_chucknorries.model.Value@420ceac0, app.retrofit_chucknorries.model.Value@420ceda0, app.retrofit_chucknorries.model.Value@420cf070, app.retrofit_chucknorries.model.Value@420cf368, app.retrofit_chucknorries.model.Value@420cf6a0, app.retrofit_chucknorries.model.Value@420cf9f8, app.retrofit_chucknorries.model.Value@420cfd88, app.retrofit_chucknorries.model.Value@420d0058, app.retrofit_chucknorries.model.Value@420d05b0, app.retrofit_chucknorries.model.Value@420d0858, app.retrofit_chucknorries.model.Value@420d0c10, app.retrofit_chucknorries.model.Value@420d0ed8, app.retrofit_chucknorries.model.Value@420d11a0, app.retrofit_chucknorries.model.Value@420d15e8, app.retrofit_chucknorries.model.Value@420d1858, app.retrofit_chucknorries.model.Value@420d1b30, app.retrofit_chucknorries.model.Value@420d1d90, app.retrofit_chucknorries.model.Value@420d20d8, app.retrofit_chucknorries.model.Value@420d2f38, app.retrofit_chucknorries.model.Value@420d31e8, app.retrofit_chucknorries.model.Value@420d3660, app.retrofit_chucknorries.model.Value@420d3908, app.retrofit_chucknorries.model.Value@420d3b90, app.retrofit_chucknorries.model.Value@420d3e88, app.retrofit_chucknorries.model.Value@420d41b0, app.retrofit_chucknorries.model.Value@420d4468, app.retrofit_chucknorries.model.Value@420d4768, app.retrofit_chucknorries.model.Value@420d5640, app.retrofit_chucknorries.model.Value@420d58e0, app.retrofit_chucknorries.model.Value@420d5bc0, app.retrofit_chucknorries.model.Value@420d5ed8, app.retrofit_chucknorries.model.V
03-10 18:15:41.751 24744-24744/app.retrofit_chucknorries D/OpenGLRenderer: Flushing caches (mode 0)
03-10 18:15:41.752 24744-24744/app.retrofit_chucknorries D/GraphicBuffer: close handle(0x54f4e008) (w:480 h:144 f:1)
03-10 18:15:41.752 24744-24744/app.retrofit_chucknorries D/GraphicBuffer: close handle(0x555eab38) (w:480 h:144 f:1)
03-10 18:15:41.753 24744-24744/app.retrofit_chucknorries D/GraphicBuffer: close handle(0x55631d30) (w:480 h:144 f:1)
03-10 18:15:41.754 24744-24744/app.retrofit_chucknorries D/GraphicBuffer: close handle(0x55499d60) (w:480 h:144 f:1)
03-10 18:15:41.801 24744-24744/app.retrofit_chucknorries D/app.retrofit_chucknorries.MainActivity$3: Called unsubscribe OnPause()
03-10 18:15:41.826 24744-24744/app.retrofit_chucknorries V/InputMethodManager: onWindowFocus: android.support.v7.widget.RecyclerView{41e54a80 VFED.... .F....I. 0,0-480,678 #7f0c005d app:id/list} softInputMode=272 first=true flags=#1810100
03-10 18:15:41.828 24744-24744/app.retrofit_chucknorries V/InputMethodManager: START INPUT: android.support.v7.widget.RecyclerView{41e54a80 VFED.... .F....I. 0,0-480,678 #7f0c005d app:id/list} ic=null tba=android.view.inputmethod.EditorInfo@421b0f98 controlFlags=#105
03-10 18:15:59.036 24744-24744/app.retrofit_chucknorries D/app.retrofit_chucknorries.MainActivity: Called unsubscribe OnPause() done
03-10 18:15:59.037 24744-24744/app.retrofit_chucknorries D/ActivityThread: ACT-AM_ON_PAUSE_CALLED ActivityRecord{41e15050 token=android.os.BinderProxy@41e147d0 {app.retrofit_chucknorries/app.retrofit_chucknorries.MainActivity}}
03-10 18:15:59.051 24744-24744/app.retrofit_chucknorries D/ActivityThread: ACT-PAUSE_ACTIVITY handled : 0 / android.os.BinderProxy@41e147d0
03-10 18:15:59.056 24744-24744/app.retrofit_chucknorries V/InputMethodManager: START INPUT: android.support.v7.widget.RecyclerView{41e54a80 VFED.... .F....I. 0,0-480,678 #7f0c005d app:id/list} ic=null tba=android.view.inputmethod.EditorInfo@421b44b0 controlFlags=#100
03-10 18:15:59.157 24744-24744/app.retrofit_chucknorries V/ActivityThread: Finishing stop of ActivityRecord{41e15050 token=android.os.BinderProxy@41e147d0 {app.retrofit_chucknorries/app.retrofit_chucknorries.MainActivity}}: show=true win=com.android.internal.policy.impl.PhoneWindow@41e21f50
03-10 18:15:59.157 24744-24744/app.retrofit_chucknorries D/ActivityThread: ACT-STOP_ACTIVITY_SHOW handled : 0 / android.os.BinderProxy@41e147d0
03-10 18:16:40.820 24744-24812/app.retrofit_chucknorries D/dalvikvm: threadid=14: exiting
03-10 18:16:40.821 24744-24812/app.retrofit_chucknorries D/dalvikvm: threadid=14: bye!
03-10 18:16:41.702 24744-24766/app.retrofit_chucknorries D/dalvikvm: threadid=13: exiting
03-10 18:16:41.711 24744-24766/app.retrofit_chucknorries D/dalvikvm: threadid=13: bye!
03-10 18:21:54.022 24744-24744/app.retrofit_chucknorries D/GraphicBuffer: create handle(0x554a7630) (w:480, h:800, f:1)
我可以知道我在做什么吗?
public class MainActivity extends AppCompatActivity {
private ProgressDialog pDialog;
private RecyclerView mRecyclerView;
IJokes apiJokes;
private DemoAdapter mAdapter;
private List<Value> mJokestList;
private Subscription resumeSub;
private Handler mHandler;
@Override
protected void onResume() {
super.onResume();
resumeSub= apiJokes.getJokes()
.cache()
.timeout(5000, TimeUnit.MILLISECONDS)
.retry(1)
.doOnUnsubscribe(new Action0() {
@Override
public void call() {
Log.d(getClass().getName(), "Called unsubscribe OnPause()");
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<JokesModel>() {
@Override
public void call(JokesModel jokesModel) {
mJokestList = jokesModel.getValue();
Log.d("list::-", String.valueOf(mJokestList));
displayGistList(mJokestList);
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
Log.e(getClass().getName(), "ERROR: " + throwable.getMessage());
throwable.printStackTrace();
}
}
);
}
private void createGithubClient() {
if (apiJokes == null) {
apiJokes = new RestAdapter.Builder()
.setEndpoint(Constants.BASE_URL)
.setLogLevel(RestAdapter.LogLevel.FULL)
.build()
.create(IJokes.class);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recycler_main);
mHandler = new Handler();
pDialog = new ProgressDialog(this);
pDialog.setMessage("Loading...");
pDialog.show();
mRecyclerView = (RecyclerView)findViewById(R.id.list);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mRecyclerView.addOnScrollListener(new RecyclerViewScrollListener() {
@Override
public void onScrollUp() {
}
@Override
public void onScrollDown() {
}
@Override
public void onLoadMore() {
loadMoreData();
}
});
createGithubClient();
}
public void displayGistList(final List<Value> gists) {
if (gists.size()>0 && mRecyclerView!=null) {
mAdapter = new DemoAdapter(MainActivity.this);
mRecyclerView.setAdapter(mAdapter);
hidePDialog();
}
}
private void hidePDialog() {
if (pDialog != null) {
pDialog.dismiss();
pDialog = null;
}
}
@Override
protected void onPause() {
super.onPause();
Log.d(getClass().getName(), "Called unsubscribe OnPause() done");
resumeSub.unsubscribe();
}
private void loadMoreData() {
mAdapter.showLoading(true);
mAdapter.notifyDataSetChanged();
// Load data after delay
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
Log.d("size::-", ""+mJokestList.size());
List<Value> newItems = getData(mJokestList.size());
mJokestList.addAll(newItems);
mAdapter.setItems(mJokestList); // No need of this
mAdapter.showLoading(false);
mAdapter.notifyDataSetChanged();
}
}, 1500);
}
// I GUESS HERE I HAVE TO MAKE CHANGE
private List<Value> getData(int start) {
List<Value> items = new ArrayList<>();
for (int i=start; i<start+12; i++) {
items.add(new Value(i, "user " + i));
}
return items;
}
}
Value.java:
public class Value {
@SerializedName("id")
@Expose
private Integer id;
@SerializedName("joke")
@Expose
private String joke;
@SerializedName("categories")
@Expose
private List<String> categories = new ArrayList<String>();
// unable to understand this -- I forced to create this one
public Value(int i, String s) {
}
/**
*
* @return
* The id
*/
public Integer getId() {
return id;
}
/**
*
* @param id
* The id
*/
public void setId(Integer id) {
this.id = id;
}
/**
*
* @return
* The joke
*/
public String getJoke() {
return joke;
}
/**
*
* @param joke
* The joke
*/
public void setJoke(String joke) {
this.joke = joke;
}
/**
*
* @return
* The categories
*/
public List<String> getCategories() {
return categories;
}
/**
*
* @param categories
* The categories
*/
public void setCategories(List<String> categories) {
this.categories = categories;
}
}
更新
根据 @ david.mihola 的建议,我在displayGistList(...)
使用了 mAdapter.setItems(gists); ,现在我getting data
RecyclerView
问题
尽管如此,我在onCreate()
收到所有584条记录,而我想在onCreate()
中显示前20条记录然后使用每次通话时无限滚动next 10 records
最后它显示了进展,我明白了:
03-11 10:23:14.061 13211-13211/app.retrofit_chucknorries E/AndroidRuntime: FATAL EXCEPTION: main
Process: app.retrofit_chucknorries, PID: 13211
java.lang.NullPointerException: println needs a message
at android.util.Log.println_native(Native Method)
at android.util.Log.d(Log.java:139)
at app.retrofit_chucknorries.adapter.DemoAdapter.bindYourViewHolder(DemoAdapter.java:38)
at app.retrofit_chucknorries.adapter.FooterLoaderAdapter.onBindViewHolder(FooterLoaderAdapter.java:58)
at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:5277)
at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:5310)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4568)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4461)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1962)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1371)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1334)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:563)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:2847)
at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3145)
at android.view.View.layout(View.java:15140)
at android.view.ViewGroup.layout(ViewGroup.java:4866)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1888)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1742)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1651)
at android.view.View.layout(View.java:15140)
at android.view.ViewGroup.layout(ViewGroup.java:4866)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:515)
at android.widget.FrameLayout.onLayout(FrameLayout.java:450)
at android.view.View.layout(View.java:15140)
at android.view.ViewGroup.layout(ViewGroup.java:4866)
at android.support.v7.internal.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:437)
at android.view.View.layout(View.java:15140)
at android.view.ViewGroup.layout(ViewGroup.java:4866)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:515)
at android.widget.FrameLayout.onLayout(FrameLayout.java:450)
at android.view.View.layout(View.java:15140)
at android.view.ViewGroup.layout(ViewGroup.java:4866)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1888)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1742)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1651)
at android.view.View.layout(View.java:15140)
at android.view.ViewGroup.layout(ViewGroup.java:4866)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:515)
at android.widget.FrameLayout.onLayout(FrameLayout.java:450)
at android.view.View.layout(View.java:15140)
at android.view.ViewGroup.layout(ViewGroup.java:4866)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2336)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2042)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1208)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6274)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:788)
at android.view.Choreographer.doCallbacks(Choreographer.java:591)
at android.view.Choreographer.doFrame(Choreographer.java:560)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:774)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5299)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:829)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:645)
at dalvik.system.NativeStart.main(Native Method)
FooterLoaderAdapter.java:
public abstract class FooterLoaderAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
protected boolean showLoader;
private static final int VIEWTYPE_ITEM = 1;
private static final int VIEWTYPE_LOADER = 2;
protected List<T> mItems;
protected LayoutInflater mInflater;
public FooterLoaderAdapter(Context context) {
mInflater = LayoutInflater.from(context);
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
if (viewType == VIEWTYPE_LOADER) {
// Your Loader XML view here
View view = mInflater.inflate(R.layout.loader_item_layout, viewGroup, false);
// Your LoaderViewHolder class
return new LoaderViewHolder(view);
} else if (viewType == VIEWTYPE_ITEM) {
return getYourItemViewHolder(viewGroup);
}
throw new IllegalArgumentException("Invalid ViewType: " + viewType);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
// Loader ViewHolder
if (viewHolder instanceof LoaderViewHolder) {
LoaderViewHolder loaderViewHolder = (LoaderViewHolder)viewHolder;
if (showLoader) {
loaderViewHolder.mProgressBar.setVisibility(View.VISIBLE);
} else {
loaderViewHolder.mProgressBar.setVisibility(View.GONE);
}
return;
}
bindYourViewHolder(viewHolder, position);
}
@Override
public int getItemCount() {
// If no items are present, there's no need for loader
if (mItems == null || mItems.size() == 0) {
return 0;
}
// +1 for loader
return mItems.size() + 1;
}
@Override
public long getItemId(int position) {
// loader can't be at position 0
// loader can only be at the last position
if (position != 0 && position == getItemCount() - 1) {
// id of loader is considered as -1 here
return -1;
}
return getYourItemId(position);
}
@Override
public int getItemViewType(int position) {
// loader can't be at position 0
// loader can only be at the last position
if (position != 0 && position == getItemCount() - 1) {
return VIEWTYPE_LOADER;
}
return VIEWTYPE_ITEM;
}
public void showLoading(boolean status) {
showLoader = status;
}
public void setItems(List<T> items) {
mItems = items;
}
public abstract long getYourItemId(int position);
public abstract RecyclerView.ViewHolder getYourItemViewHolder(ViewGroup parent);
public abstract void bindYourViewHolder(RecyclerView.ViewHolder holder, int position);
}
DemoAdapter.java:
public class DemoAdapter extends FooterLoaderAdapter<Value> {
...
@Override
public long getYourItemId(int position) {
return mItems.get(position).getId();
}
@Override
public RecyclerView.ViewHolder getYourItemViewHolder(ViewGroup parent) {
return new DemoViewHolder(mInflater.inflate(R.layout.card_row, parent, false));
}
@Override
public void bindYourViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof DemoViewHolder) {
DemoViewHolder viewHolder = (DemoViewHolder)holder;
Log.d("title::-", mItems.get(position).getJoke());
viewHolder.mUsernameView.setText(mItems.get(position).getJoke());
}
}
public class DemoViewHolder extends RecyclerView.ViewHolder {
@Bind(R.id.name) TextView mUsernameView;
public DemoViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
答案 0 :(得分:1)
哇。很多事情都在继续。你正在使用RxJava,Retrofit和更多的东西来混搭一些东西。你有无限加载器的整个概念不正确。有两种情况。
我建议的是这样的。
public interface ApiProvider {
Observable<List<MyData>> getData(int offset, int limit);
}
基于REST Api的数据提供程序的实现,
public class RESTApiProvider implements ApiProvider {
public RESTApiProvider() {
// Initialize Retrofit service provider
}
@Override
public Observable<List<MyData>> getData(int offset, int limit) {
// Retrofit provides data
}
}
在您的活动中,
private void loadMoreData(int offset, int limit) {
mAdapter.showLoading(true);
mAdapter.notifyDataSetChanged();
Observable<List<MyData>> observable = restApiProvider.getData(offset, limit);
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<MyData>() {
@Override
public void call(List<MyData> data) {
mItems.addAll(data);
mAdapter.setData(mItems);
mAdapter.showLoading(false);
mAdapter.notifyDatasetChanged();
}
});
}