RecyclerView: No adapter attached - android

I know that this question has been already asked, but having checked the answers, I still can't figure out the solution. This is my adapter:
public static class StarredReposViewHolder extends RecyclerView.ViewHolder {
LinearLayout starredReposLayout;
TextView starredRepoName;
public StarredReposViewHolder(View v) {
super(v);
starredReposLayout = (LinearLayout) v.findViewById(R.id.repo_starred_item_layout);
starredRepoName = (TextView) v.findViewById(R.id.starredepoName);
}
}
public StarredReposAdapter(List<GitHubstarredRepos> repos, int rowLayout, Context context) {
this.starredRepos = repos;
this.rowLayout = rowLayout;
this.context = context;
}
#Override
public StarredReposAdapter.StarredReposViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(rowLayout, parent, false);
return new StarredReposViewHolder(view);
}
#Override
public void onBindViewHolder(StarredReposViewHolder holder, int position) {
holder.starredRepoName.setText(starredRepos.get(position).getStarredName());
}
#Override
public int getItemCount() {
return starredRepos.size();
}
And this is the method I load it in:
public void loadStarredRepos (View view){
final RecyclerView recyclerViewSt = (RecyclerView) findViewById(R.id.starred_repos_recycler_view);
recyclerViewSt.setLayoutManager(new LinearLayoutManager(this));
GitHubStarredRepoAPI apiService =
ApiClient.getClient().create(GitHubStarredRepoAPI.class);
Call<List<GitHubstarredRepos>> call = apiService.getStarredRepoName(newString);
call.enqueue(new Callback<List<GitHubstarredRepos>>() {
#Override
public void onResponse(Call<List<GitHubstarredRepos>> call, Response<List<GitHubstarredRepos>>
response) {
recyclerViewSt.setAdapter(new StarredReposAdapter(response.body(), R.layout.list_item_starred_repo,
getApplicationContext()));
}
#Override
public void onFailure(Call<List<GitHubstarredRepos>> call, Throwable t) {
// Log error here since request failed
Log.e("Repos", t.toString());
}
});
}
The body of onResponse is entered correctly. The problem cannot be that it is on defined in the onCreate, as I have anther Recycle View, on the same screen, loaded from a different method. Thank you!
PS: The response of response.body()

Well, from the practice, you should have your RecyclerView#setAdapter() in mainThread in #onCreate()
public void onCreate() {
recyclerViewSt.setAdapter(myAdapter);
}
What you need to update inside the onResponse() is the dataSet that is used to feed your Adapter.
You can extract your response.body() which returns an array of object (List repos) into a global variable in your activity. Like:
List<GitHubstarredRepos> myDatasource = new ArrayList<>();
Then use it:
myAdapter = new StarredReposAdapter(myDatasource, R.layout.list_item_starred_repo, getApplicationContext()));
Next, inside the callback of network call:
onResponse(response) {
myDatasource.clear();
myDatasource.addAll(response.body());
myRecyclerview.notifyDatasetChanged();
}
Voila, my psedocode code, not sure about the syntax ;)

Related

why RecycleView items is not displayed?

I have a problem. When I use newsPojo at first - all displayed ok (but swipe to refresh is not work, when I use postAdapter.notifyDataSetChanged() - my items is not displayed. How can I fix it?
This is my Activity class
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private NewsApi newsApi;
private NewsPojo fromRetrofit;
private MainAdapter postAdapter;
#BindView(R.id.activity_main_swipe_to_refresh) SwipeRefreshLayout swipeRefreshLayout;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
fromRetrofit = new NewsPojo();
fromRetrofit.setArticles(new ArrayList<Article>());
response();
initRecycleView();
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
response();
swipeRefreshLayout.setRefreshing(false);
}
});
}
private void response() {
newsApi = RitApplication.getApi();
newsApi.getData().enqueue(new Callback<NewsPojo>() {
#Override
public void onResponse(Call<NewsPojo> call, Response<NewsPojo> response) {
fromRetrofit.getArticles().clear();
fromRetrofit = response.body();
postAdapter.notifyDataSetChanged();
}
}
#Override
public void onFailure(Call<NewsPojo> call, Throwable t) {
}
});
}
public void initRecycleView() {
recyclerView = findViewById(R.id.activity_main_recycle_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
postAdapter = new MainAdapter(fromRetrofit, new OnIteamClickListener() {
#Override
public void onItemClick(View itemView) {
}
}, getApplicationContext());
recyclerView.setAdapter(postAdapter);
}
}
Here you can see my Adapter class
public class MainAdapter extends RecyclerView.Adapter<MainAdapter.ViewHolder> {
private NewsPojo newsPojo;
private OnIteamClickListener listener;
private Context mContext;
public MainAdapter(NewsPojo newsPojo, OnIteamClickListener listener, Context mContext) {
this.newsPojo = newsPojo;
this.listener = listener;
this.mContext = mContext;
}
public void clear(){
newsPojo.getArticles().clear();
notifyDataSetChanged();
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_news, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.bind(newsPojo.getArticles().get(position));
}
#Override
public int getItemCount() {
if (newsPojo != null) {
return newsPojo.getArticles().size();
} else {
return 0;
}
}
Why postAdapter.notifyDataSetChanged(); is not working?
I suggest the following:
Change the following lines:
fromRetrofit.getArticles().clear();
fromRetrofit = response.body();
postAdapter.notifyDataSetChanged();
For this:
postAdapter.cleanAddArticles(response.body());
and in the adapter add the following:
public void cleanAddArticles(NewsPojo newsPj){
this.newsPojo.getArticles().clear();
this.newsPojo.getArticles().addAll(newsPj.getArticles());
notifyDataSetChanged();
}
Note: Error depending on the circumstances must be going through object references.
When you get new values by calling response() method, then you must call initRecycleView() to set the new values to the adapter, then use notifyDataSetChanged()
#Override
public void onResponse(Call<NewsPojo> call, Response<NewsPojo> response) {
fromRetrofit.getArticles().clear();
fromRetrofit = response.body();
initRecycleView() //*** Add this.
postAdapter.notifyDataSetChanged();
}
}
first of check when you swipe refresh that time your postAdapter not getting null other wise your code is ok.
if you want to make one separate method for adapter like below..
private void setAdater(){
if (postAdapter==null) {
postAdapter = new MainAdapter(fromRetrofit, new OnIteamClickListener() {
#Override
public void onItemClick(View itemView) {
}
}, getApplicationContext());
recyclerView.setAdapter(postAdapter);
}
else{
postAdapter.notifyDataSetChanged();
}
}
and also check your from fromRetrofit object what value have. i think adapter not getting any value bacause only clear article but object has some value there for i think you make object null when getting data...
fromRetrofit=null;
fromRetrofit = response.body();

Paging library is not sending any data to my PagedListAdapter

I have an Android To-do list app with SQLite database accessed using Room. Then I wanted to make a list of available lists in navigation drawer. So I used Paging Library. Now the RecyclerView is empty and I don't know why. BTW: none of my lists work. I am a beginner, so I stick to the official tutorial. I've already found out, that they are wrong and that ViewModel needs an empty constructor. Now the situation looks like this: the method, that sets up the adapter is called successfully (8), ViewModel is created (7) Adapter is created (1), the setList() method is called (9), but no Holder is being created (4), no onCreateViewHolder or onBindViewHolder are called (2,3), no DiffCalback methods are called (5,6) and just an empty Recycler view is displayed. The PagedList<SQLList> contains right information, but no information is being passed to the adapter. Has anybody any idea why?
//Sorry for my English.
Adapter class:
//this is my Adapter. SQLList is my object (Equivalent to the User object in
the tutorial)
public class ListsAdapter extends PagedListAdapter<SQLList,ListsAdapter.Holder> {
private Context context;
public ListsAdapter(Context context) {
//1
super(DIFF_CALLBACK);
this.context = context;
}
#Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
//2
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.list_item,null);
return new Holder(view);
}
#Override
public void onBindViewHolder(Holder holder, int position) {
//3
SQLList item = getItem(position);
if (item == null){
holder.clear();
}else {
holder.bindTo(item);
}
}
public static class Holder extends RecyclerView.ViewHolder {
public TextView textView;
public int id;
public TextView idView;
public Holder(View itemView) {
//4
super(itemView);
textView = itemView.findViewById(R.id.textView);
idView = itemView.findViewById(R.id.idTextView);
}
public void bindTo(SQLList list) {
textView.setText(list.getName());
id = list.getId();
idView.setText(Integer.toString(list.getId()));
}
public void clear() {
textView.setText("");
id = 0;
idView.setText("0");
}
}
private static final DiffCallback<SQLList> DIFF_CALLBACK = new DiffCallback<SQLList>() {
#Override
public boolean areItemsTheSame(#NonNull SQLList oldItem, #NonNull SQLList newItem) {
//5
return oldItem.getId() == newItem.getId();
}
#Override
public boolean areContentsTheSame(#NonNull SQLList oldItem, #NonNull SQLList newItem) {
//6
return oldItem.getName().equals(newItem.getName());
}
};
}
View Model:
public static class ListViewModel extends ViewModel {
public final LiveData<PagedList<SQLList>> listsList;
public ListViewModel(){
//7
listsList = new LivePagedListBuilder<>(DMO.getDao().loadListFactory(),20).build();
}
}
Part of Fragment the RecyclerView is placed in:
...
//8
ListViewModel listViewModel = ViewModelProviders.of(this).get(ListViewModel.class);
adapter = new ListsAdapter(context);
listViewModel.listsList.observe(this, new Observer<PagedList<SQLList>>() {
#Override
public void onChanged(#Nullable PagedList<SQLList> sqlLists) {
//9
adapter.setList(sqlLists);
}
});
recyclerView.setAdapter(adapter);
...
Problem found: I forgot to set layout manager!
I had the same problem but I accidentally added-
RecyclerView.setHasFixedSize(true);
After removing this, It worked.
Same issue I had and I just removed RecyclerView.setHasFixedSize(true) then it started working fine.
I had to set the adapter. recyclerView.setAdapter(adapter);

RecycleView displays data only first time

I have a RecycleView to which I give an Array of Post objects. When it's loaded first time, everything works fine but trying to replace the data or just entering in the Fragment again then the RecycleView does not show anything. Also I have checked the size of the new data and it's different from zero. Here is my code:
// Init the list
list = (RecyclerView) view.findViewById(R.id.list);
list.setLayoutManager(new LinearLayoutManager(mContext));
...
if (adapter != null) {
adapter.replaceCurrentPosts(new ArrayList<>(postList));
}
else {
adapter = new PostAdapter(mContext, new ArrayList<>(postList), this);
list.setAdapter(adapter);
}
...
public PostAdapter(Context context, List<Post> posts, onPostElementClickListener listener) {
this.context = context;
this.posts = posts;
this.mListener = listener;
}
public void replaceCurrentPosts(List<Post> newPosts) {
this.posts.clear();
this.posts.addAll(newPosts);
this.notifyDataSetChanged();
}
#Override
public int getItemCount() {
return posts.size();
}
package com.example.jiteshmohite.myapplication;
public class PostAdapter extends RecyclerView.Adapter {
private Context context;
private List<Post> posts;
private onPostElementClickListener mListener;
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView mTextView;
public ViewHolder(View v) {
super(v);
mTextView = (TextView) v.findViewById(R.id.info_text);
}
}
public PostAdapter(Context context, List<Post> posts, onPostElementClickListener listener) {
this.context = context;
this.posts = posts;
this.mListener = listener;
}
public void replaceCurrentPosts(List<Post> newPosts) {
posts.clear();
posts = newPosts;
this.notifyDataSetChanged();
}
#Override
public PostAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.my_text_view, parent, false);
// set the view's size, margins, paddings and layout parameters
ViewHolder vh = new ViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(PostAdapter.ViewHolder holder, final int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
holder.mTextView.setText(posts.get(position).getName());
holder.mTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mListener.onClick(position);
}
});
}
#Override
public int getItemCount() {
return posts.size();
}
interface onPostElementClickListener {
public void onClick(int pos);
}
}
private RecyclerView list;
private PostAdapter postAdapter;
private RecyclerView.LayoutManager layoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler_example);
list = (RecyclerView) findViewById(R.id.list);
layoutManager = new LinearLayoutManager(getApplicationContext());
list.setLayoutManager(layoutManager);
postAdapter = new PostAdapter(getApplicationContext(), getPostData(), listener);
list.setAdapter(postAdapter);
}
private PostAdapter.onPostElementClickListener listener = new PostAdapter.onPostElementClickListener() {
#Override
public void onClick(int pos) {
Toast.makeText(getApplicationContext(), pos + "" , Toast.LENGTH_SHORT).show();
List<Post> posts = getPostData();
posts.get(pos).setName("abc");
postAdapter.replaceCurrentPosts(posts);
}
};
// get post list which contains name
public List<Post> getPostData() {
Post post = new Post();
post.setName("xyz");
List<Post> posts = new ArrayList<Post>();
posts.add(post);
posts.add(post);
posts.add(post);
posts.add(post);
posts.add(post);
return posts;
}
}
I suggesting rather then notifyDataSetChanged() you should refer notifyItemChange which modify specific positions.
please let me know if it is not work for you.
why don't you try to add one element (or maybe more) instead of remove all and re-add all items?

Why is this custom listener null?

I am trying to create an interface between my Recyclerview Adapter and an Activity, so that when an item in the adapter is clicked, the Activity will react accordingly but the listener is always null.
Interface
public interface UrlTagCatClickedListener {
public void onUrlTagCatClicked (String chemicalURL);
}
Adapter
public class TagCatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context mContext;
private List<TagCatItem> mTagCatItems;
private int lastPosition = -1;
private UrlTagCatClickedListener mTagCatClickedListener;
public TagCatAdapter(List<TagCatItem> tagCatItems, Context context) {
super();
this.mTagCatItems = tagCatItems;
this.mContext = context;
this.mTagCatClickedListener = null;
}
public void setTagCatClickedListener (UrlTagCatClickedListener tagCatClickedListener) {
this.mTagCatClickedListener = tagCatClickedListener;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.tag_cat_item, parent, false);
return new ItemViewHolder(v);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final TagCatItem tagCatItem = mTagCatItems.get(position);
((ItemViewHolder) holder).chemicalTitle.setText(Html.fromHtml(tagCatItem.getChemicalTitle()));
((ItemViewHolder) holder).chemicalDate.setText(tagCatItem.getChemicalDate());
((ItemViewHolder) holder).chemicalTitle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mTagCatClickedListener != null) { // mTagCatClickedListener is always null
mTagCatClickedListener.onUrlTagCatClicked(tagCatItem.getChemicalURL());
}
}
});
}
public class ItemViewHolder extends RecyclerView.ViewHolder{
public TextView chemicalTitle, chemicalDate;
public ItemViewHolder(final View mView) {
super(mView);
chemicalTitle = (TextView) mView.findViewById(R.id.tagcat_title);
chemicalDate = (TextView) mView.findViewById(R.id.tagcat_date);
}
}
#Override
public int getItemCount() {
return mTagCatItems.size();
}
}
Activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate called")
//Skipped a lot of codes that doesn't relate to the queation
List<TagCatItem> mTagCatItems = new ArrayList<>();
TagCatAdapter tagCatAdapter = new TagCatAdapter(mTagCatItems, this);
tagCatAdapter.setTagCatClickedListener(new UrlTagCatClickedListener() {
#Override
public void onUrlTagCatClicked(String chemicalURL) {
Log.d(TAG, "I go the url!!!!!!!!!! and it is + " + chemicalURL);
}
});
}
Please, do you have an idea why it's null and how I can fix it?
You have two different instances of TagCatAdapter in your given setup; one in the Activity, and one in the Fragment. You're setting the UrlTagCatClickedListener you've posted on the one created in the Activity, but it's the Fragment's TagCatAdapter instance that you're setting on the RecyclerView. That one doesn't have the listener set, so its mTagCatClickedListener is always null.
You just need to move the given UrlTagCatClickedListener to the TagCatAdapter in the Fragment, and remove the TagCatAdapter from the Activity, as you're not using that one anyway.

How to Load Json in Endless Recycler Veiw with Retrofit

I try to implement Endless Recycler View with my Json Response .
This is My Json Response Link
I Generate my models with jsonschema2pojo.org and I load the data in my recyclerview successfully .
But I need to implement endless recycler view :
This is my RecyclerAdapter :
public class AparatAdapter extends RecyclerView.Adapter<AparatAdapter.ViewHolder> {
private Context context;
private ArrayList<Categoryvideo> categoryVideos;
//=============================constructor
public AparatAdapter(Context context, ArrayList<Categoryvideo> categoryVideos) {
this.context = context;
this.categoryVideos = categoryVideos;
}
//=============================viewholder
public class ViewHolder extends RecyclerView.ViewHolder{
private TextView txtTitle ,txtCount ,txtSender ,txtDate;
private ImageView imgRow;
public ViewHolder(View itemView) {
super(itemView);
txtTitle = (TextView)itemView.findViewById(R.id.txt_title_row);
txtCount = (TextView)itemView.findViewById(R.id.txt_count_dynamic_row);
txtSender = (TextView)itemView.findViewById(R.id.txt_sender_dynamic_row);
txtDate = (TextView)itemView.findViewById(R.id.txt_date_dynamic_row);
imgRow = (ImageView)itemView.findViewById(R.id.img_row);
}
}
//================================oncreateviewholder
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_layout, parent,false);
return new ViewHolder(view);
}
//================================= onbindviewholder
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.txtTitle.setText(categoryVideos.get(position).getTitle());
holder.txtCount.setText(categoryVideos.get(position).getVisitCnt().toString());
holder.txtSender.setText(categoryVideos.get(position).getSenderName());
holder.txtDate.setText(categoryVideos.get(position).getSdate().toString());
Glide.with(holder.itemView.getContext()).load(categoryVideos.get(position).getSmallPoster())
.into(holder.imgRow);
}
//==================================getitemcount
#Override
public int getItemCount() {
return categoryVideos.size();
}
}
And This is the activity where i load the json in that with retrofit :
public class SargarmiActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private AparatAdapter adapter;
private LinearLayoutManager layoutManager;
private ArrayList<Categoryvideo> categoryvideos;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sargarmi);
initViews();
}
//=================================================
private void initViews() {
recyclerView = (RecyclerView) findViewById(R.id.recycler_sargarmi);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(SargarmiActivity.this);
recyclerView.setLayoutManager(layoutManager);
sendRequest();
}
//=================================================
private void sendRequest() {
recyclerView.addOnScrollListener(new EndlessRecyclerViewScrollListener(layoutManager) {
#Override
public void onLoadMore(int page, int totalItemsCount) {
loadMore();
}
});
getData();
}
//=======================================================
private void getData() {
//1
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.aparat.com/etc/api/")
.addConverterFactory(GsonConverterFactory.create())
.build();
//2
ApiInterface request = retrofit.create(ApiInterface.class);
//3
Call<JSONResponse> call = request.getJsonResponse();
//4
call.enqueue(new Callback<JSONResponse>() {
#Override
public void onResponse(Call<JSONResponse> call, Response<JSONResponse> response) {
if (response.isSuccessful()) {
JSONResponse jsonResponse = response.body();
categoryvideos = new ArrayList<>(jsonResponse.getCategoryvideos());
adapter = new AparatAdapter(SargarmiActivity.this, categoryvideos);
recyclerView.setAdapter(adapter);
} else {
Toast.makeText(SargarmiActivity.this, "Error darim else onresponse", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<JSONResponse> call, Throwable t) {
Toast.makeText(SargarmiActivity.this, "Error darim onFailure()", Toast.LENGTH_SHORT).show();
}
});
}
//=============== Load more Endless =====================
private void loadMore() {
}
}
As you can see in json my pagination url embed in ui object . and i don't know what should i write in the loadmore() method in my activity.
When you download the initial load of categoryvideos, there is also an elementcalled: pagingForward. This contains the url for you to download the next 20 items.
So what you want to do is:
When downloading the first videos, fetch the pagingForward value
and store this somewhere.
When you call loadMore() you make another download with Retrofit
with the url.
Retrofit will download the objects and you will get another
pagingForward url that will then point to the next 20 items.
This can keep on going until there are no more objects to fetch
(Not sure how the API respons then, you need to check with the
persons who wrote the API)

Categories

Resources