Setting Adapter in recyclerview - android

I am trying to use recyclerview and setting up adapter but I am getting error :-
No adapter attached; skipping layout
So please help me how to solve this problem
public class FragmentTwo extends Fragment {
private AppAdapter mAppAdapter;
private ArrayList<Model> mModel;
#Bind(R.id.recycler_view)
RecyclerView recyclerView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_two, container, false);
ButterKnife.bind(this, v);
recyclerView.setHasFixedSize(true);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(mAppAdapter);
parseData();
return v;
}
private void parseData() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("url")
.addConverterFactory(GsonConverterFactory.create())
.build();
ReqInterface reqInterface = retrofit.create(ReqInterface.class);
Call<Model> call = reqInterface.getAdvanceData("france");
call.enqueue(new Callback<Model>() {
#Override
public void onResponse(Call<Model> call, Response<Model> response) {
Model model = response.body();
mModel = new ArrayList<Model>(Arrays.asList(model));
mAppAdapter = new AppAdapter(mModel);
recyclerView.setAdapter(mAppAdapter);
mAppAdapter.notifyDataSetChanged();
}
#Override
public void onFailure(Call<Model> call, Throwable t) {
}
});
}
}
Here is my Recyclerview Adapter class:-
public class AppAdapter extends RecyclerView.Adapter<AppAdapter.ViewHolder> {
private ArrayList<Model> mModel;
TextView highTemp;
public AppAdapter(ArrayList<Model> model) {
mModel = model;
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView highTemp;
public ViewHolder(View view) {
super(view);
highTemp = (TextView) view.findViewById(R.id.card_view_tv_hightemp);
}
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.fragment_two, viewGroup, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
viewHolder.highTemp.setText(String.valueOf(mModel.getName);
}
#Override
public int getItemCount() {
return mModel.size();
}
}
Thanks in advance

You never initialize the adapter mAppAdapter so it's null at runtime. You're missing something like mAppAdapter = new AppAdapter(yourdata);
before the call to setAdapter.

Your adapter mAppAdapter is never initialised i.e. it is null.
Therefore recyclerView.setAdapter(mAppAdapter); is the same as recyclerView.setAdapter(null); so you aren't actually ever setting an adapter!
Remember to initialise your fields:
mAppAdapter = new AppAdapter(mModel); // or whatever constructor you want
recyclerView.setAdapter(mAppAdapter);

Change
recyclerView.setAdapter(mAppAdapter);
to
recyclerView.setAdapter(new AppAdapter(model));

You never create your mAppAdapter.
To solve this, create a new instance of your adapter and pass that in the parameters of .setAdapter.
In other words, you should use .setAdapter(new AppAdapter(...)) where ... is replaced with the parameters that you have created in AppAdapter.

I usually do the retrofit call in an asynctask, then when you get the response from the server, you create a new adapter and set it to the recyclerview.
Anyway, try removing the .setAdapter line from the onCreate() method and just leave it as you have it.
It works and it doesn't crash, the reason it crashes it's because the adapter is null (it has no elements).
I hope it helps!

Related

Adapter in FirebaseUI is getting null

I've used firebase Recycler Adapter to get data. But always getting error,
Attempt to invoke virtual method 'void
androidx.recyclerview.widget.RecyclerView.setAdapter(androidx.recyclerview.widget.RecyclerView$Adapter)'
on a null object reference
My fragment is
public class MyBooksFragment extends BaseFragment {
private ShimmerFrameLayout mShimmerViewContainer;
private RecyclerView recyclerView ;
private FirebaseRecyclerAdapter adapter;
private FirebaseUser user= FirebaseAuth.getInstance().getCurrentUser();
#Override
public BaseFragment provideFragment() {
return new MyBooksFragment();
}
#Override
public View provideFragmentView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_my_books,parent,false);
mShimmerViewContainer=view.findViewById(R.id.mybook_shimmer_view_container);
RecyclerView recyclerView = view.findViewById(R.id.recycler_view_books);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
fetchBooks(1);
FloatingActionButton fab = view.findViewById(R.id.addBookFab_);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), BookAdder.class);
startActivity(intent);
}
});
return view;
}
private FirebaseRecyclerOptions<Book> queryBuilderParser(){
Query bookQuery= FirebaseDatabase
.getInstance()
.getReference()
.child("Books")
.orderByChild("ownerID")
.equalTo(user.getUid());
FirebaseRecyclerOptions<Book> options =
new FirebaseRecyclerOptions.Builder<Book>()
.setQuery(bookQuery,Book.class)
.build();
return options;
}
protected void fetchBooks(int type)
{
Log.e("profile",type+" ");
FirebaseRecyclerOptions<Book> options;
Query bookQuery= FirebaseDatabase
.getInstance()
.getReference()
.child("Books")
.orderByChild("ownerID")
.equalTo(user.getUid());
options = new FirebaseRecyclerOptions.Builder<Book>()
.setQuery(bookQuery,Book.class)
.build();
Log.e("profile","inside fetchReviw "+options.getSnapshots());
adapter= new FirebaseRecyclerAdapter<Book, BookViewHolder>(options) {
#NonNull
#Override
public BookViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.book_row_item, parent, false);
return new BookViewHolder(view);
}
#Override
protected void onBindViewHolder(#NonNull BookViewHolder bookViewHolder, int i, #NonNull Book book) {
bookViewHolder.book_name.setText(book.getBookName());
bookViewHolder.book_author.setText(book.getAuthors());
bookViewHolder.book_category.setText(book.getCategory());
bookViewHolder.book_rating.setText(book.getRating()+"");
Glide.with(getActivity()).load(book.getThumbnail()).into(bookViewHolder.img_thumbnail);
}
#Override
public void onDataChanged() {
if(getItemCount()>0 && mShimmerViewContainer!=null){
mShimmerViewContainer.stopShimmerAnimation();
mShimmerViewContainer.setVisibility(View.GONE);
}
}
#Override
public void onError(DatabaseError e) {
// Called when there is an error getting data. You may want to update
// your UI to display an error message to the user.
// ...
Log.e("profile","database error");
}
};
recyclerView.setAdapter(adapter);
}
}
Here, I've extended a base fragment which extends Fragment.
You haven't put the right arguments into the adapter. The adapter takes 4 arguments in:
Object class
List item layout resource
Viewholder Class
Query/firebase reference
Here is how it should look, also the adapter does a lot of the hard word so you only need to use the populateViewHolder function:
FirebaseRecyclerViewAdapter<Object, ObjectViewHolder> adapter = new FirebaseRecyclerViewAdapter<Object, ObjectViewHolder>
(Object.class, android.R.layout.*list_item_layout*, ObjectViewHolder.class, objectQuery) {
public void populateViewHolder(ObjectViewHolder ObjectViewHolder, Object Object) {
//in your case the following lines:
bookViewHolder.book_name.setText(book.getBookName());
bookViewHolder.book_author.setText(book.getAuthors());
bookViewHolder.book_category.setText(book.getCategory());
bookViewHolder.book_rating.setText(book.getRating()+"");
Glide.with(getActivity()).load(book.getThumbnail()).into(bookViewHolder.img_thumbnail);
}
};
recycler.setAdapter(mAdapter);

Displaying RecyclerView into fragment

I've got methods:
private void initImageBitmaps() {
mImageUrls.add("imageUrl");
mNames.add("abcd");
initRecyclerView();
}
private void initRecyclerView() {
Log.d(TAG, "initRecyclerView: init recyclerview.");
RecyclerView recyclerView = findViewById(R.id.recyclerv_view);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, mNames, mImageUrls);
recyclerView.setAdapter(adapter);
//recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setLayoutManager(new GridLayoutManager(this, 2));
}
Which add images to my recyclerview.
If it was in activity I would call initImageBitmaps() inside OnCreate. Unfortunately I have to use it in fragment and the question is: how to implement these methods to class which extends Fragment? Of course everything will be displayed into RecyclerView with recycler_view id in xml.
EDIT:
My Adapter:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>{
private static final String TAG = "RecyclerViewAdapter";
private ArrayList<String> mImageNames = new ArrayList<>();
private ArrayList<String> mImages = new ArrayList<>();
private Context mContext;
public RecyclerViewAdapter(WallpapersFragment context, ArrayList<String> imageNames, ArrayList<String> images ) {
mImageNames = imageNames;
mImages = images;
mContext = context;
//Rquired is android.content.context and found is WallpapersFragment from my project
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_listitem, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position) {
Log.d(TAG, "onBindViewHolder: called.");
Glide.with(mContext)
.asBitmap()
.load(mImages.get(position))
.into(holder.image);
holder.imageName.setText(mImageNames.get(position));
holder.parentLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(mContext, GalleryActivity.class);
intent.putExtra("image_url", mImages.get(position));
intent.putExtra("image_name", mImageNames.get(position));
mContext.startActivity(intent);
}
});
}
#Override
public int getItemCount() {
return mImageNames.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
ImageView image;
TextView imageName;
RelativeLayout parentLayout;
public ViewHolder(View itemView) {
super(itemView);
image = itemView.findViewById(R.id.image);
imageName = itemView.findViewById(R.id.image_name);
parentLayout = itemView.findViewById(R.id.parent_layout);
}
}
}
It compiles only when I comment mContext = context; in adapter. Then the error is:
java.lang.NullPointerException: You cannot start a load on a not yet attached View or a Fragment where getActivity() returns null (which usually occurs when getActivity() is called before the Fragment is attached or after the Fragment is destroyed).
There is an onCreate() method in the Fragment class, but that method is different from activity's onCreate().
public static class ExampleFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.example_fragment, container, false);
}
#Override
public void onViewCreated (View view, Bundle savedInstanceState) {
initRecyclerView();
}
}
Read more about fragments here: Fragments
initRecyclerView(view);
And then:
recyclerView = view.findViewById(R.id.recyclerv_view);
You can initialize your recycler view in following lifecycle callback:
onViewCreated()
and can also populate data method here like
initRecyclerView()
initImageBitmaps()
and for data refresh you can call notifyDatasetChanged() on adapter.
try this...
public class ExampleFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view= inflater.inflate(R.layout.example_fragment, container, false);
initImageBitmaps(view);
return view;
}
private void initImageBitmaps(View view) {
mImageUrls.add("imageUrl");
mNames.add("abcd");
initRecyclerView(View view);
}
private void initRecyclerView(View view) {
Log.d(TAG, "initRecyclerView: init recyclerview.");
RecyclerView recyclerView = view.findViewById(R.id.recyclerv_view); // init recyclerview
GridLayoutManager layoutManager = new GridLayoutManager(getContext(), 2);// declare layoutmanager
recyclerView.setLayoutManager(layoutManager); // set layoutmanager
RecyclerViewAdapter adapter = new RecyclerViewAdapter(getContext(), mNames, mImageUrls); // init adapter
recyclerView.setAdapter(adapter); // set adapter in recyclerveiw
}
EDIT
Replace WallpapersFragment with Context in adapter
public RecyclerViewAdapter(Context context, ArrayList<String> imageNames, ArrayList<String> images ) {
mImageNames = imageNames;
mImages = images;
mContext = context;
//Rquired is android.content.context and found is WallpapersFragment from my project
}

RecyclerView not visible

I have this code in MainActivity
public class MainActivity extends AppCompatActivity implements MainViewInterface{
RecyclerView rvMovies;
private String TAG = "MainActivity";
MoviesAdapter adapter;
MainPresenter mainPresenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupMVP();
mainPresenter.getMovies();
rvMovies = (RecyclerView)findViewById(R.id.rvMovies);
LinearLayoutManager manager = new LinearLayoutManager(this);
manager.setOrientation(LinearLayoutManager.VERTICAL);
rvMovies.setLayoutManager(manager);
//rvMovies.setHasFixedSize(true);
}
private void setupMVP() {
mainPresenter = new MainPresenter(this);
}
#Override
public void showToast(String s) {
Toast.makeText(MainActivity.this,s,Toast.LENGTH_LONG).show();
}
#Override
public void displayMovies(MovieResponse moviesResponse) {
if(moviesResponse!=null) {
Log.d(TAG,moviesResponse.getResults().get(1).getTitle());
adapter = new MoviesAdapter(moviesResponse.getResults(), MainActivity.this);
rvMovies.setAdapter(adapter);
adapter.notifyDataSetChanged();
}else{
Log.d(TAG,"Movies response null");
}
}
#Override
public void displayError(String s) {
showToast(s);
}
}
But I get this
E/RecyclerView: No adapter attached; skipping layout
I know other people asked the same question. I tried their solutions but didn't work. What am I missing?
This is my adapter code.
public class MoviesAdapter extends RecyclerView.Adapter<MoviesAdapter.MoviesHolder> {
List<Result> movieList;
Context context;
public MoviesAdapter(List<Result> movieList, Context context){
this.movieList = movieList;
this.context = context;
}
#Override
public MoviesHolder onCreateViewHolder( ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.row_movies,parent,false);
MoviesHolder mh = new MoviesHolder(v);
return mh;
}
#Override
public void onBindViewHolder( MoviesHolder holder, int position) {
holder.tvTitle.setText(movieList.get(position).getTitle());
holder.tvOverview.setText(movieList.get(position).getOverview());
holder.tvReleaseDate.setText(movieList.get(position).getReleaseDate());
Glide.with(context).load("https://image.tmdb.org/t/p/w500/"+movieList.get(position).getPosterPath()).into(holder.ivMovie);
}
#Override
public int getItemCount() {
return movieList.size();
}
public class MoviesHolder extends RecyclerView.ViewHolder {
TextView tvTitle,tvOverview,tvReleaseDate;
ImageView ivMovie;
public MoviesHolder(View itemView) {
super(itemView);
tvTitle = (TextView) itemView.findViewById(R.id.tvTitle);
tvOverview = (TextView) itemView.findViewById(R.id.tvOverView);
tvReleaseDate = (TextView) itemView.findViewById(R.id.tvReleaseDate);
ivMovie = (ImageView) itemView.findViewById(R.id.ivMovie);
}
}
Thanks,
Theo.
SOLVED
In my activivity_main.xml I had both height and with equal to 0dp!!! I honestly don't know how and who put those values in!! That's why the recycler view was not visible!!!
I think you should call rvMovies.setAdapter(new MoviesAdapter(new ArrayList<>())) on your RecyclerView during onCreate - there is nothing bad about setting an empty (from items perspective) adapter on RecyclerView, it will simply show an empty list. Then once you have your data ready (downloaded/loaded from any source you are loading from) you will simply call something like adapter.setItems(newItemsList) and adapter.notifyDataSetChanged().
Also one more note: you should not store Context in class member fields as leaks might occur (I am pretty sure your Android Studio must complain about that as well in a form of a Lint Warning check). You actually don't even need that Context instance passing to your adapter as you can simply retrieve a Context instance from parent View in onCreateViewHolder - rewrite it like this:
#Override
public MoviesHolder onCreateViewHolder( ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_movies,parent,false);
MoviesHolder mh = new MoviesHolder(v);
return mh;
}
These 2 lines:
setupMVP();
mainPresenter.getMovies();
must be written after:
rvMovies = (RecyclerView)findViewById(R.id.rvMovies);
you need to set adapter after you set the views.
rvMovies = (RecyclerView)findViewById(R.id.rvMovies);
LinearLayoutManager manager = new LinearLayoutManager(this);
manager.setOrientation(LinearLayoutManager.VERTICAL);
rvMovies.setLayoutManager(manager);
//rvMovies.setHasFixedSize(true);
//call after setting the view
mainPresenter.getMovies();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupMVP();
rvMovies = (RecyclerView)findViewById(R.id.rvMovies);
LinearLayoutManager manager = new LinearLayoutManager(this);
manager.setOrientation(LinearLayoutManager.VERTICAL);
rvMovies.setLayoutManager(manager);
rvMovies.setVisibility(View.VISIBLE);
mainPresenter.getMovies(); <== put this line in last
}

E/RecyclerView: No adapter attached; skipping layout

I have been reading different answers here on stackoverflow and i tried to implement the solution but I am still getting the same error, I don't know why ! :/
This is my Adapter Class :
public class RecipesAdapter extends RecyclerView.Adapter <RecipesAdapter.RecipeHolder>{
private List<Recipes> recipesList;
private static Recipes recipe;
private static Intent intent;
private Context context;
private View row;
private RecipeHolder holder;
//Conctructor
public RecipesAdapter(List<Recipes> recipesList)
{
this.recipesList=recipesList;
}
//create holder (view)
#Override
public RecipeHolder onCreateViewHolder(ViewGroup parent, int viewType) {
row= LayoutInflater.from(parent.getContext()).inflate(R.layout.recipe_row, parent,false);
//Call constructor : Holder
holder=new RecipeHolder(row);
return holder;
}
#Override
public void onBindViewHolder(RecipeHolder holder, int position) {
recipe= recipesList.get(position);
holder.recipe_title.setText(recipe.getTitle());
Picasso.with(holder.recipe_image.getContext()).load(recipe.getImage_url()).into(holder.recipe_image);
holder.recipe_rank.setText(recipe.getSocial_rank().split("\\.",2)[0]);
holder.recipe_publisher.setText(recipe.getPublisher());
}
#Override
public int getItemCount() {
return recipesList.size();
}
/*To avoid calling methods findViewById for each view, Android has added a concept called ViewHolder
to change 'the values' of each View => concept of Recycling */
public class RecipeHolder extends RecyclerView.ViewHolder
{
private ImageView recipe_image;
private TextView recipe_title,recipe_rank,recipe_publisher;
public RecipeHolder(View itemView) {
super(itemView);
recipe_image=(ImageView) itemView.findViewById(R.id.recipe_img);
recipe_title=(TextView) itemView.findViewById(R.id.recipe_title);
recipe_rank=(TextView) itemView.findViewById(R.id.recipe_rank);
recipe_publisher=(TextView) itemView.findViewById(R.id.recipe_publisher);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
context = v.getContext();
intent = new Intent(context, DetailRecipe.class);
intent.putExtra("url",recipesList.get(getAdapterPosition()).getF2f_url());
intent.putExtra("image",recipesList.get(getAdapterPosition()).getImage_url());
Log.e("log","url is : "+recipe.getF2f_url());
context.startActivity(intent);
}});
}
}
}
onCreate Method
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.cookingrecipes);
// Adding Toolbar to Main screen
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
Connection_GetData();
}
onResponse Method : when the connection was successful
I used Retrofit library to get data, I called Display_Recipes() to set Adapter
`#Override
public void onResponse(Call<ResultRecipes> call, Response<ResultRecipes> response) {
recipesList = response.body().getRecipes();
//Recycler View
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
/*Performance*/
recyclerView.setItemViewCacheSize(24);
recyclerView.setDrawingCacheEnabled(true);
recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
recyclerView.setLayoutManager(new GridLayoutManager(CookingRecipes.this, 2));
/*Treatment - Display*/
Display_Recipes();
}`
Display_Recipes() Method
`public void Display_Recipes() {
//Setup Adapter
this.recipeAdapter = new RecipesAdapter(recipesList);
recyclerView.setAdapter(recipeAdapter);
}`
Image Log
Many Thanks,
It's necessary to set LayoutManager on main thread instead of calling inside any callback.
Update your onCreate method as per below :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.cookingrecipes);
// Adding Toolbar to Main screen
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//Shifted your recycler view code here
//Recycler View
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
/*Performance*/
recyclerView.setItemViewCacheSize(24);
recyclerView.setDrawingCacheEnabled(true);
recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
recyclerView.setLayoutManager(new GridLayoutManager(CookingRecipes.this, 2));
// Only pass context to your adapter
recyclerView.setAdapter(new RecipesAdapter(CookingRecipes.this);
Connection_GetData();
}
And update your onResponse Callback :
#Override
public void onResponse(Call<ResultRecipes> call, Response<ResultRecipes> response) {
recipesList = response.body().getRecipes();
/*Treatment - Display*/
Display_Recipes();
}
Create method to update list in your adapter whenever you need to pass updated list :
public void udpateList(List<Recipes> recipesList){
this.recipesList = recipesList;
notifyDataSetChanged();
}
Now call this method from your Display_Recipes method
public void Display_Recipes() {
//Update Adapter
udpateList(recipesList);
}
Thank you all my friends, I was discovered the error, the code is correct but to avoid this warning, we need to set an empty adapter in onCreate method. After inside the method that you want to get the data, in my case with Retrofit library : Connection_GetData();
1 - create class Adapter like that
public class AdapterFirstUse extends RecyclerView.Adapter {
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
}
#Override
public int getItemCount() {
return 0;
}
}
2 - Inside onCreate(Bundle savedInstanceState) method
recyclerView.setAdapter(new AdapterFirstUse());
3 - Inside Connection_GetData()
Setup our Adapter
//Setup Adapter
recipeAdapter = new RecipesAdapter(recipesList);
recyclerView.setAdapter(recipeAdapter);
That's all, Thanks.
The problem might be the adapter is not telling the RecyclerView to update its content.
Add a method in your RecipeAdapter:
public void refresh() {
notifyDataSetChanged();
}
Then call it after binding the adapter to the RecyclerView;
recyclerView.setAdapter(recipeAdapter);
recipeAdapter.update();
Mine was solved by inputting an empty list data first upon initialisation of the adapter, and update data later, example:
initialise adapter in onCreate():
onCreate() {
...
initRecyclerView();
...
}
initRecyclerView() :
public void initRecyclerView() {
//setup recyclerview
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
/*Performance*/
recyclerView.setItemViewCacheSize(24);
recyclerView.setDrawingCacheEnabled(true);
recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
recyclerView.setLayoutManager(new GridLayoutManager(CookingRecipes.this, 2));
//Setup Adapter
this.recipeAdapter = new RecipesAdapter(new List());//try to set an empty adapter here first
recyclerView.setAdapter(recipeAdapter);
}
then inside onResponse:
#Override
public void onResponse(Call<ResultRecipes> call, Response<ResultRecipes> response) {
//only do data update inside onResponse
recipesList = response.body().getRecipes();
recipeAdapter.recipesList = recipesList;
notifyDataSetChanged();
}

Custom methods in adapter are not resolving in android

I have 2 methods inside of adapter class.
addValues(brandMap);
setBrandMap(brandMap);
that I'm trying to call after async call. However, the compiler is complaining that it cannot resolve these methods. What is the issue?
This is complete class.
public class FragmentBrandList extends ListFragment {
private String TAG = getClass().getSimpleName();
private Map<String, Brand> brandMap = new ConcurrentHashMap<>();
private RecyclerView.Adapter adapter;
private FirebaseDatabase database = FirebaseDatabase.getInstance();
private RecyclerView recyclerView;
private Query query = database.getReference("brands").orderByChild("name");
public FragmentBrandList() {
}
public static FragmentBrandList newInstance(int num) {
FragmentBrandList f = new FragmentBrandList();
// Supply num input as an argument.
Bundle args = new Bundle();
args.putInt("num", num);
f.setArguments(args);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.recycler_list, container, false);
recyclerView = (RecyclerView) v.findViewById(R.id.recycler_view);
RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(getActivity(), 3);
RecyclerView.setLayoutManager(mLayoutManager);
adapter = new FragmentBrandList.MyAdapter(Utility.getBrandMap(), getActivity());
recyclerView.setAdapter(adapter);
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), recyclerView, new ClickListener() {
#Override
public void onClick(View view, int position) {
Brand brand = Utility.getBrands().get(position);
Intent intent = new Intent(getActivity(), ActivityProductList.class);
intent.putExtra("BrandId", brand.getId());
startActivity(intent);
}
#Override
public void onLongClick(View view, int position) {
}
}));
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
Brand brand = dataSnapshot1.getValue(Brand.class);
brandMap.put(brand.getId(), brand);
}
Utility.setBrandMap(brandMap);
adapter.addValues(brandMap);
adapter.setBrandMap(brandMap);
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
Utility.displayToast("Failed to read value." + error.toException());
}
});
return v;
}
Adapter class
private class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private List<Brand> brandList = new ArrayList<>();
private Context context;
public class MyViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
public MyViewHolder(View view) {
super(view);
imageView = (ImageView) view.findViewById(R.id.thumbnail);
}
}
public MyAdapter(Map<String, Brand> brands, Context context) {
//public MyAdapter(List<Brand> brands, Context context) {
this.brandList = new ArrayList<>(brandMap.values());
//this.brandList = brands;
this.context = context;
}
public void setBrandMap(Map<String, Brand> brandMap){
this.brandList = new ArrayList<>(brandMap.values());
notifyDataSetChanged();
}
public void addValues(Map<String, Brand> brands){
brandList.clear();
brandList.addAll(brands.values());
notifyDataSetChanged();
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.card_brand, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
if (brandList != null && brandList.size() > 0) {
Brand brand = brandList.get(position);
Glide.with(context).load(String.valueOf(brand.getImage()))
.error(R.drawable.placeholder)
.placeholder(R.drawable.placeholder)
.into(holder.imageView);
}
}
#Override
public int getItemCount() {
return brandList.size();
}
}
You have declared your adapter field as:
private RecyclerView.Adapter adapter;
That means wherever you use it, you'll see it as just a RecyclerView.Adapter, which doesn't have your custom methods on it. It doesn't matter that you've assigned there a subclass of RecyclerView.Adapter that has extra methods. It is because you might've assigned there a different subclass that didn't have those methods.
If you want to use your custom methods then change the declaration to:
private MyAdapter adapter;
Then you can use all methods declared in MyAdapter and inherited from superclasses. The tradeoff is that you cannot assign there any other subclass of RecyclerView.Adapter, but thanks to that compiler can know you can always use your extra methods.
The problem is this line.
private RecyclerView.Adapter adapter;
As you are holding your custom adapter object in the Base reference, hence those methods of your custom adapter is not visible to you. Change the reference to the type of your Custom Adapter and it should work fine.

Categories

Resources