Getting a null pointer exception on a RecyclerView layout manager - java

Hi guys I have the following error I cannot seem to resolve.
I have
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.setLayoutManager(android.support.v7.widget.RecyclerView$LayoutManager)' on a null object reference
The code I have is slightly different than from regular examples since I am doing this in a Fragment rather than in a Activity.
This is my code.
I have an xml for the whole Fragment:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
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"
tools:context="mtr.MainActivityFragmentTwo">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/grades"
android:textStyle="bold"
android:textSize="40dp"
android:gravity="center_horizontal"
android:layout_gravity="center"
/>
</FrameLayout>
Then I have a content_fragment which holds the RecyclerView
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<android.support.v7.widget.RecyclerView
android:id="#+id/realm_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
Then my code in my Fragments looks as follows
public class MainActivityFragmentTwo extends Fragment {
private Realm realm;
private RecyclerView recyclerView;
public MainActivityFragmentTwo() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_main_activity_fragment_two, container, false);
}
#Override
public void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
realm.init(getActivity());
realm = Realm.getDefaultInstance();
recyclerView = (RecyclerView) getActivity().findViewById(R.id.realm_recycler_view);
setupRecyclerView();
}
public void setupRecyclerView() {
Log.d("Found grades", "not showing grades tho");
recyclerView.setLayoutManager(new LinearLayoutManager(this.getContext()));
recyclerView.setAdapter(new gradeRealmAdapter(this, realm.where(Grade.class).findAllAsync()));
recyclerView.setHasFixedSize(true);
}
}
the Adapter I created is
public class gradeRealmAdapter extends RealmRecyclerViewAdapter<Grade, gradeRealmAdapter.GradeViewHolder> {
private final MainActivityFragmentTwo activity;
public gradeRealmAdapter (MainActivityFragmentTwo activity, RealmResults<Grade> realmResults) {
super(activity.getActivity(), realmResults, true);
this.activity = activity;
}
#Override
public GradeViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new GradeViewHolder(inflater.inflate(R.layout.gradeitem, parent, false));
}
#Override
public void onBindViewHolder(GradeViewHolder holder, int position) {
Grade grade = getData().get(position);
holder.title.setText(grade.toString());
}
class GradeViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener {
public TextView title;
public Grade grade;
public GradeViewHolder(View view) {
super(view);
title = (TextView) view.findViewById(R.id.grade_text_view);
view.setOnLongClickListener(this);
}
public boolean onLongClick(View v) {
activity.deleteItem(grade);
return true;
}
}
}
The error comes from the Fragment class on the following line
recyclerView.setLayoutManager(new LinearLayoutManager(this.getContext()));
I can't seem to resolve this.
Can anyone see what I am doing wrong?

I have an content_fragment which holds the recyclerview
Then you need to findViewById on that layout, not the Activity's.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_activity_fragment_two, container, false);
// Don't use getActivity().findViewById
recyclerView = (RecyclerView) rootView.findViewById(R.id.realm_recycler_view);
setupRecyclerView();
return rootView;
}
Then, you also have the realm initialization backwards.
realm.init(getActivity()); // This throws an exception as well
realm = Realm.getDefaultInstance(); // It is initialized afterwards
So, fix that too within onAttach, where you are guaranteed to have some Context
#Override
public void onAttach(Context context) {
super.onAttach(context);
realm = Realm.getDefaultInstance();
realm.init(context);
}

let's try to change
recyclerView.setLayoutManager(new LinearLayoutManager(this.getContext()));
with
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
And make some update for onCreateView:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView =inflater.inflate(R.layout.fragment_main_activity_fragment_two,container, false);
recyclerView = (RecyclerView) rootView.findViewById(R.id.realm_recycler_view);
setupRecyclerView();
return rootView;
}

Inflate your recycler view on onViewCreated()
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView =inflater.inflate(R.layout.fragment_main_activity_fragment_two,container, false);
recyclerView = (RecyclerView) rootView.findViewById(R.id.realm_recycler_view);
setupRecyclerView();
return rootView;
}
Not in onCreate

Related

Fragment with RecyclerView, no adapter attached error

I'm making a tabbed activity with different fragments and one of them contains a recyclerview with just some names at the moment. I have no idea what I've done wrong, I get a warning every time on starting the app that says no adapter attached, skipping layout. I've created and set the adapter to the recyclerview in my fragment, created an adapter with viewholder, and created a class to set the name on the recyclerview.
Here is my fragment class:
public class fragment_main extends Fragment {
View view;
private RecyclerView mainrecyclerview;
private List<MainSchedule> listStr;
public fragment_main() {}
#NonNull
#Override
public View onCreateView(LayoutInflater inflater, #NonNull ViewGroup container, #NonNull Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_main, container, false);
mainrecyclerview = (RecyclerView) view.findViewById(R.id.todayRecyclerView);
MainRecyclerViewAdapter mainAdapter = new MainRecyclerViewAdapter(getActivity(), listStr);
mainrecyclerview.setLayoutManager(new LinearLayoutManager(getActivity()));
mainrecyclerview.setAdapter(mainAdapter);
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
listStr = new ArrayList<>();
listStr.add(new MainSchedule("one"));
listStr.add(new MainSchedule("two"));
listStr.add(new MainSchedule("three"));
}
}
fragment.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".fragment_main">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/todayRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="32dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="32dp"
android:layout_marginBottom="250dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
recyclerviewadapter class:
public class MainRecyclerViewAdapter extends RecyclerView.Adapter<MainRecyclerViewAdapter.ViewHolder> {
Context mContext;
List<MainSchedule> mData;
public MainRecyclerViewAdapter(Context context, List<MainSchedule> data){
this.mContext = context;
this.mData = data;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.mainschedule_cards, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.textView.setText(mData.get(position).getName());
}
#Override
public int getItemCount() {
return mData.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private TextView textView;
public ViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.textViewClass);
}
}
}
I've tried many ways of creating the adapter and binding the layout manager to the recyclerview, but nothing seems to work and I get the same error each time.
Problem seems with onCreateView because you're supposed to return view
Replace your fragment_main with code below
public class fragment_main extends Fragment {
private RecyclerView mainrecyclerview;
private List<MainSchedule> listStr;
public fragment_main() {
}
#NonNull
#Override
public View onCreateView(LayoutInflater inflater, #NonNull ViewGroup container, #NonNull Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_main, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
listStr = new ArrayList<>();
listStr.add(new MainSchedule("one"));
listStr.add(new MainSchedule("two"));
listStr.add(new MainSchedule("three"));
mainrecyclerview = (RecyclerView) view.findViewById(R.id.todayRecyclerView);
MainRecyclerViewAdapter mainAdapter = new MainRecyclerViewAdapter(getActivity(), listStr);
mainrecyclerview.setLayoutManager(new LinearLayoutManager(getActivity()));
mainrecyclerview.setAdapter(mainAdapter);
}
}

Null Pointer Exception in RecyclerView within Fragment with Firestore

I am trying to populate recyclerView with Java objects using Firestore. The RecyclerView is within a fragment. I am using a recyclerViewAdapter which extends the FirestoreRecyclerAdapter class. When I run the code, the app crashes immediately.
Here's the error.
.NullPointerException: Attempt to invoke virtual method 'void androidx.recyclerview.widget.RecyclerView.setLayoutManager(androidx.recyclerview.widget.RecyclerView$LayoutManager)' on a null object reference
Here's some of the fragment Java code:
public class EventsFragment extends Fragment{
private FirebaseFirestore db = FirebaseFirestore.getInstance();
private CollectionReference eventRef = db.collection("Events");
private EventRecyclerAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final ViewGroup rootView = (ViewGroup) inflater.inflate(
R.layout.events_fragment, container, false);
setUpRecyclerView();
return rootView;
}
private void setUpRecyclerView(){
Query query = eventRef.limit(8);
FirestoreRecyclerOptions<Event> options = new FirestoreRecyclerOptions.Builder<Event>()
.setQuery(query, Event.class)
.build();
adapter = new EventRecyclerAdapter(options);
RecyclerView recyclerView = (RecyclerView) getActivity().findViewById(R.id.events_recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
}
}
Here's the fragment xml:
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="Upcoming Events"
app:menu="#menu/main_menu"
android:background="#android:color/white"
/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="8dp"
android:clipToPadding="false"
android:divider="#null"
android:id="#+id/events_recycler_view"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Here's the RecyclerAdapter code:
public class EventRecyclerAdapter extends FirestoreRecyclerAdapter<Event, EventRecyclerAdapter.EventHolder> {
public EventRecyclerAdapter(#NonNull FirestoreRecyclerOptions<Event> options) {
super(options);
}
#Override
protected void onBindViewHolder(#NonNull EventHolder holder, int position, #NonNull Event model) {
holder.textViewTitle.setText(model.getTitle());
holder.textViewDescription.setText(model.getDescription());
}
#NonNull
#Override
public EventHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.events_list_item,
parent, false);
return new EventHolder(v);
}
class EventHolder extends RecyclerView.ViewHolder {
TextView textViewTitle;
TextView textViewDescription;
public EventHolder(#NonNull View itemView) {
super(itemView);
textViewTitle = itemView.findViewById(R.id.title);
textViewDescription = itemView.findViewById(R.id.description);
}
}
}
I believe the problem lies somewhere with the RecyclerView. I've been trying to find the problem for hours now. Is there something I'm overlooking? I just need it to run.
You already noticed that recyclerView is null when you try to set the LayoutManager in setUpRecyclerView()
This happens because you are trying to "find" the RecyclerView in the Activity's View tree before the Fragment's View has actually been attached to it:
RecyclerView recyclerView = (RecyclerView) getActivity().findViewById(R.id.events_recycler_view);
The first Fragment lifecycle method where you can put this statement is onResume() (at least in my example app on an emulator running Android 9)
But you can configure the RecyclerView much earlier because you can "find" it in the Fragment's own View for example in onViewCreated():
#Override
public void onViewCreated(View view, Bundle savedInstanceState){
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.events_recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(view.getContext());
// etc.
}
Please note that the view parameter in onViewCreated() represents the View which you can get everywhere in the Fragment by calling getView(). But only after onCreateView() has finished, because the purpose of this method is creating and "publishing" the Fragment's View in the first place.
Last not least, inside of onCreateView() you can "find" the RecyclerView by means of the newly inflated View:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final ViewGroup rootView = (ViewGroup) inflater.inflate(
R.layout.events_fragment, container, false);
//setUpRecyclerView();
RecyclerView recyclerView = (RecyclerView) rootView .findViewById(R.id.events_recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(rootView.getContext());
// etc.
return rootView;
}
So maybe you'd best pass the root View as parameter into setUpRecyclerView() and use it as follows:
private void setUpRecyclerView(ViewGroup root){
Query query = eventRef.limit(8);
FirestoreRecyclerOptions<Event> options = new FirestoreRecyclerOptions.Builder<Event>()
.setQuery(query, Event.class)
.build();
adapter = new EventRecyclerAdapter(options);
RecyclerView recyclerView = (RecyclerView) root.findViewById(R.id.events_recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(root.getContext()));
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
}

Android studio null object reference error while changing component visibility

I'm making an app that displays the same menus for different users, each menu being a fragment, but depending on the user certain things are visible and others aren't.
However, when I try to set a component's visibility as GONE I get a null pointer exception error, I'm still testing so I'm only using a textView on the fragment xml.
I've already tried initializing both the TextView and the FragmentMenuEncomenda, the class of the fragment I'm using, objects, both inside the if clause before the onCreate() method, and after the setContentView(), like the tabLayout and viewPager.
The if clause was only to make sure the user type was correct and the code in question is as follows:
public class PaginaInicialCliente extends AppCompatActivity {
private SharedPreferences sharedpreferences;
private TabLayout tabLayout;
private ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pagina_inicial_cliente);
tabLayout = findViewById(R.id.tabLayoutCliente);
viewPager = findViewById(R.id.viewPagerCliente);
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
//fragments a adicionar
adapter.addFragment(new FragmentMenuEncomendas(), "Encomendas");
adapter.addFragment(new FragmentMenuOpcoes(), "Opções");
//inicializar o tab layout
viewPager.setAdapter(adapter);
tabLayout.setupWithViewPager(viewPager);
sharedpreferences = getSharedPreferences("user", Context.MODE_PRIVATE);
if (sharedpreferences.getInt("tipo",0)==3) {
Log.d("USER_DEBUG","Cliente");
FragmentMenuEncomendas fragmentMenuEncomendas = new FragmentMenuEncomendas();
//THE ERROR IS HERE
fragmentMenuEncomendas.getActivity().findViewById(R.id.textViewEncomendas).setVisibility(View.GONE);
}
}
}
The FragmentMenuEncomenda class:
public class FragmentMenuEncomendas extends Fragment {
View v;
public FragmentMenuEncomendas(){
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
v = inflater.inflate(R.layout.encomendas_fragment, container, false);
return v;
}
}
The xml file:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textViewEncomendas"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/app_name"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
All the answers I've searched didn't work, I don't know if it's because I'm trying to change the visibility inside the on create method.
Because view is not created when you call the function.
public class FragmentMenuEmpresas extends Fragment {
View v;
View textView;
boolean isTextViewShow = false;
boolean isViewCreated = false;
public FragmentMenuEmpresas() {
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
v = inflater.inflate(R.layout.empresas_fragment, container, false);
textView = v.findViewById(R.id.textViewEncomendas);
return v;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (isTextViewShow) {
textView.setVisibility(View.VISIBLE);
} else {
textView.setVisibility(View.GONE);
}
isViewCreated = true;
}
void setIsTextViewShow() {
if (isViewCreated) {
textView.setVisibility(View.VISIBLE);
} else {
isTextViewShow = true;
}
}
void setIsTextViewGone() {
if (isViewCreated) {
textView.setVisibility(View.GONE);
} else {
isTextViewShow = false;
}
}
}
then you can call the setIsTextViewShow or setIsTextViewGone anytime you want
FragmentMenuEncomendas fragmentMenuEncomendas = new FragmentMenuEncomendas();
fragmentMenuEncomendas.setIsTextViewShow();//show
fragmentMenuEncomendas.setIsTextViewGone();//gone

RecyclerView Overriden methods not called and getItemCount always return 0

I know that my question has been asked several times but i have been searching for a while and none of all the answers fixed my problem.
The issue is that when i create the recyclerview adapter and all the stuff in the method "onViewCreated" in my "HomeFragment" i am not having any compilation error but my recyclerview doesn't load any image since none of the methods Overriden in recyclerview adapter are called even when i call "mAdapter.notifyDataSetChanged()"
HomeFragment.java
public class HomeFragment extends Fragment implements Response.Listener<GalleryItem[]>, Response.ErrorListener {
RequestQueue requestQueue;
List<GalleryItem> myDataset = new ArrayList<>();
RecyclerView mRecyclerView;
RecyclerView.Adapter mAdapter;
RecyclerView.LayoutManager mLayoutManager;
CustomJsonObjectRequest jsonObjectRequest;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.home_fragment, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
mRecyclerView = view.findViewById(R.id.my_recycler_view);
mRecyclerView.setHasFixedSize(true);
mAdapter = new GalleryAdapter(myDataset);
mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mRecyclerView.setAdapter(mAdapter);
jsonObjectRequest = new CustomJsonObjectRequest(Constants.HOME_URL, GalleryItem[].class, this, this);
requestQueue = VolleySingleton.getInstance(this.getContext()).getRequestQueue();
VolleySingleton.getInstance(this.getContext()).addToRequestQueue(jsonObjectRequest, "headerRequest");
}
#Override
public void onResponse(GalleryItem[] response) {
myDataset = Arrays.asList(response);
mAdapter.notifyDataSetChanged();
}
#Override
public void onErrorResponse(VolleyError error) {
Log.d(Constants.API_ERROR_TAG, error.getMessage());
}
GalleryAdapter.java
public class GalleryAdapter extends RecyclerView.Adapter<GalleryAdapter.MyViewHolder> {
private List<GalleryItem> mDataset;
public static class MyViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
Log.d("tagdetest2","myviewholder");
imageView = itemView.findViewById(R.id.gallery_image);
}
}
public GalleryAdapter(List<GalleryItem> myDataset) {
mDataset = myDataset;
}
#NonNull
#Override
public GalleryAdapter.MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int i) {
Log.d("tagdetest2","onCreateViewHolder");
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_gallery, parent, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull GalleryAdapter.MyViewHolder myViewHolder, int i) {
Log.d("tagdetest2", mDataset.get(i).link);
Glide.with(myViewHolder.itemView.getContext()).load(mDataset.get(i).link).into(myViewHolder.imageView);
}
#Override
public int getItemCount() {
Log.d("tagdetest", "size = " + mDataset.size());
return mDataset.size();
}
item_gallery.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="#+id/gallery_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
home_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.constraint.ConstraintLayout>
myDataset = Arrays.asList(response);
overrides the reference, in your Fragment not in your adapter.
Try with
mDataset.addAll(Arrays.asList(response));
insetad

RecyclerView No adapter attached; skipping layout, Data not showing

I'm making a music player application where I'm using a loader to load song data to the adapter which is to be shown using a RecyclerView. However, I'm getting this weird error of my adapter methods not working. Only the constructor method of adapter is getting called.
I'm also getting "No adapter attached; skipping layout" despite going through all the available solutions here in stack overflow.
Few points to be noted:
I've tried all the solutions for "No adapter attached; skipping layout" in
recyclerview No adapter attached; skipping layout thread and all associated duplicate threads.
The RecyclerView I'm using is not the regular one but FastScrollRecyclerView, but since it extends from the regular RecyclerView and there are no relatable issues mentioned on github so I'm convinced that using this library is not an issue here
I've also tried all solutions for the adapter methods not being called from this thread but no luck.
Here's the code:
SongsFragment.java
public class SongsFragment extends Fragment
implements LoaderManager.LoaderCallbacks<List<Song>>{
public static final String LOG_TAG = SongsFragment.class.getSimpleName();
private static final int LOADER_ID = 1;
private ContentResolver mContentResolver;
private SongListAdapter mSongListAdapter;
private List<Song> mSongs;
#BindView(R.id.rvSongs) FastScrollRecyclerView mRecyclerView;
public SongsFragment() {}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ButterKnife.bind(getActivity());
mSongs = new ArrayList<>();
mRecyclerView = new FastScrollRecyclerView(getContext());
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setHasFixedSize(true);
mSongListAdapter = new SongListAdapter(getContext(), mSongs);
mRecyclerView.setAdapter(mSongListAdapter);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getLoaderManager().initLoader(LOADER_ID, null, this).forceLoad();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_songs, container, false);
}
#Override
public Loader<List<Song>> onCreateLoader(int id, Bundle args) {
mContentResolver = getActivity().getContentResolver();
return new SongsLoader(getContext(), mContentResolver);
}
#Override
public void onLoadFinished(Loader<List<Song>> loader, List<Song> data) {
mSongs = data;
mSongListAdapter.setData(mSongs);
}
#Override
public void onLoaderReset(Loader<List<Song>> loader) {
mSongListAdapter.setData(new ArrayList<Song>());
}
}
SongsListAdapter.java
public class SongListAdapter
extends FastScrollRecyclerView.Adapter<SongListAdapter.SongItemViewHolder>
implements FastScrollRecyclerView.SectionedAdapter{
public static final String LOG_TAG = SongListAdapter.class.getSimpleName();
private Context mContext;
private List<Song> mSongList = new ArrayList<>();
public SongListAdapter(Context context, List<Song> songList) {
Log.d(LOG_TAG, "Constructor called");
mContext = context;
mSongList = songList;
}
#NonNull
#Override
public String getSectionName(int position) {
return String.valueOf(mSongList.get(position).getTitle().charAt(0)).toUpperCase();
}
#Override
public SongItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Log.d(LOG_TAG, "onCreateViewHolder called");
View view = LayoutInflater.from(mContext).inflate(R.layout.list_item_song, null);
return new SongItemViewHolder(view);
}
#Override
public void onBindViewHolder(SongItemViewHolder holder, int position) {
Log.d(LOG_TAG, "onBindViewHolder called");
Uri albumArtUri = mSongList.get(position).getAlbumArtUri();
Glide.with(mContext)
.load(albumArtUri)
.into(holder.albumArt);
holder.titleText.setText(mSongList.get(position).getTitle());
holder.artistText.setText(mSongList.get(position).getArtistName());
Log.d("Data", albumArtUri.toString() + "\n" + mSongList.get(position).getTitle() + "\n" + mSongList.get(position).getArtistName());
}
#Override
public int getItemCount() {
Log.d(LOG_TAG, "getItemCount called");
return (mSongList != null ? mSongList.size() : 0);
}
public void setData(List<Song> songs){
mSongList = songs;
notifyDataSetChanged();
}
public class SongItemViewHolder extends FastScrollRecyclerView.ViewHolder {
ImageView albumArt;
TextView titleText;
TextView artistText;
SongItemViewHolder(View view) {
super(view);
Log.d(LOG_TAG, "SongItemViewHolder called");
albumArt = (ImageView) view.findViewById(R.id.item_song_image);
titleText = (TextView) view.findViewById(R.id.item_song_title);
artistText = (TextView) view.findViewById(R.id.item_song_artist_name);
}
}
}
fragment_songs.xml (SongsFragment is inflating this layout)
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
android:id="#+id/rvSongs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:fastScrollPopupBgColor="#color/colorAccent"
app:fastScrollPopupTextColor="#android:color/primary_text_dark"
app:fastScrollThumbColor="#color/colorAccent"/>
</ScrollView>
list_item_song.xml (Individual item in recycler view)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_gravity="center_horizontal"
android:layout_marginStart="12dp"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
android:background="#FFFFFF"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingBottom="10dp"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingStart="8dp"
android:paddingTop="10dp">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/item_song_image"
android:layout_width="64dp"
android:src="#drawable/music_placeholder"
android:layout_height="64dp"/>
</FrameLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:orientation="vertical">
<TextView
android:id="#+id/item_song_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:text="Song_Title"/>
<TextView
android:id="#+id/item_song_artist_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:textSize="12sp"
android:text="Song_Artist"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
This has been really frustrating. Please review the code and help me with this. I think I've done everything correctly but I may be wrong. I know scrollview and recyclerview don't go that well but I've seen the preview and the recycler view shows. Any help will be appreciated. Thanks!
Try setting adapter in onLoadFinished() and also use getActivity() for context in adapter object
#Override
public void onLoadFinished(Loader<List<Song>> loader, List<Song> data) {
mSongs = data;
mSongListAdapter = new SongListAdapter(getActivity(), mSongs);
mRecyclerView.setAdapter(mSongListAdapter);
}
also in this
mRecyclerView = new FastScrollRecyclerView(getContext()); to
mRecyclerView = new FastScrollRecyclerView(getActivity());
Basically use getActivity() for context in fragment class
Ugh! I wasted a lot of time in this but finally came out with the solution. I removed Butterknife binding and used conventional findViewById inside onCreateView() of SongsFragment after capturing the view instance by changing the onCreateView() to this:
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_songs, container, false);
mRecyclerView = (FastScrollRecyclerView) rootView.findViewById(R.id.rvSongs);
//Rest of the things
}
Turns out I was using ButterKnife the wrong way so the instance mRecyclerView was null but later with line
mRecyclerView = new FastScrollRecyclerView(getContext()); it wasn't null anymore but it still wasn't connected to the view so I didn't get NullPointerException and the code didn't work.
I know it was a noob mistake :D
Correct way to use ButterKnife with fragments as picked up from official website is:
public class FancyFragment extends Fragment {
#BindView(R.id.button1) Button button1;
#BindView(R.id.button2) Button button2;
#Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
ButterKnife.bind(this, view);
// TODO Use fields...
return view;
}
}

Categories

Resources