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;
}
}
Related
XML files
Here is the activity_main.xml file. that contains two fragments fragment_list.xml and fragment_deatails.xml
<androidx.fragment.app.FragmentContainerView
android:id="#+id/fragmentContainerView"
android:name="com.udemy.fragmentsapp.ListFrag"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
tools:layout="#layout/fragment_list" />
<androidx.fragment.app.FragmentContainerView
android:id="#+id/fram2"
android:name="com.udemy.fragmentsapp.DetailFrag"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
tools:layout="#layout/fragment_detail" />
Here is the fragment_list.xml file. that contain ListView
<ListView
android:id="#+id/lvList"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Here is the fragment_details.xml file. that contains one TextView
<TextView
android:id="#+id/tvDescription"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/textview"
android:layout_marginTop="20dp"
android:layout_marginRight="20dp"
android:layout_marginLeft="20dp"
android:textSize="18dp"
android:textStyle="bold"
android:textColor="#color/black"/>
Java Files
Here is the ListFrag.java file.
ItemSelected activity;
public interface ItemSelected
{
void onItemSelected(int index);
}
public ListFrag() {
// Required empty public constructor
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
activity = (ItemSelected) context;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ArrayList<String> data = new ArrayList<>();
for (int i = 1; i < 6; i++) {
data.add(i + ". This is item " + i);
}
setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1,data));
}
#Override
public void onListItemClick(#NonNull ListView l, #NonNull View v, int position, long id) {
super.onListItemClick(l, v, position, id);
activity.onItemSelected(position);
}
Here is the DeatailFrag.java file.
public DetailFrag(){
super(R.layout.fragment_detail);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_detail, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
}
Here is the MainActivity.java file. when I want to access the ID "tvDescription" then it's showing ERROR: #layout/activity_main does not contain a declaration with id tvDescription.
Please help me. How can I access the ID? Tell me which one is the way to find IDs.
TextView tvDescription;
ArrayList<String> description;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvDescription = findViewById(R.id.tvDescription);
for (int i = 1; i < 6; i++) {
description.add("Description for item " + i);
}
}
#Override
public void onItemSelected(int index) {
tvDescription.setText(description.get(index));
}
Please run this code in your IDE.
The problem is that your activity and fragment are different classes. And although it is obvious that they represent a single view tree, in fact, in each component class, you should refer to the elements of only its layout.
Thus you need to use
TextView tvDescription = findViewById(R.id.tvDescription);
Directly in the DeatailFrag.onViewCreated after super.onViewCreated
And then, somehow pass the received value back to the activity, if necessary
Happy learning
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
In this fragment,
public class BlankFragment extends Fragment {
public BlankFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
final View rootView = inflater.inflate(R.layout.fragment_blank, container, false);
RecyclerView rv = rootView.findViewById(R.id.rv_recycler_view);
rv.setNestedScrollingEnabled(false);
SimpleDateFormat localDateFormat = new SimpleDateFormat("HH:mm");
SunTimes suntime = SunTimes.compute().at(latlang.Lat,latlang.Lang).today().execute();
String sun_rise = localDateFormat.format(suntime.getRise());
String sun_set = localDateFormat.format(suntime.getSet());
Date sunnoon = suntime.getNoon();
System.out.println("SUNRISE "+ sun_rise);
TextView cityField = rootView.findViewById(R.id.tv_city);
TextView sunrise = rootView.findViewById(R.id.tv_sunrt);
TextView sunset = rootView.findViewById(R.id.tv_sunst);
cityField.setText("Hello World"); //Line 45
sunrise.setText(sun_rise);
sunset.setText(sun_set);
return rootView;
}
I am getting error:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
at com.example.phocast.BlankFragment.onCreateView(BlankFragment.java:45)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:2354)
The question is while I have a normal string as a text, how it can get null point exception?
What am I doing wrong?
Update
the fragment_blank does not have the id, as its just an inflater:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/swiperefresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>
</RelativeLayout>
That id is in item_blank.xml as:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="120sp" >
<android.support.v7.widget.CardView
android:id="#+id/card_view"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_margin="10dp"
android:layout_height="120sp"
card_view:cardCornerRadius="4dp"
card_view:elevation="14dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/iv_image"
android:layout_width="120sp"
android:layout_height="fill_parent"
android:scaleType="fitStart"
card_view:srcCompat="#drawable/property_image_3">
</ImageView>
<TextView
android:id="#+id/tv_city"
android:layout_width="wrap_content"
android:layout_height="30sp"
android:layout_marginBottom="1sp"
android:layout_toRightOf="#+id/iv_image"
android:gravity="top"
android:paddingLeft="5sp"
android:text="Hello World"
android:textAppearance="#style/TextAppearance.AppCompat.Large">
</TextView>
.....
and which is defined in the Adapter:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private String[] mDataset;
// 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 MyViewHolder extends RecyclerView.ViewHolder {
public CardView mCardView;
public TextView mTextView;
public MyViewHolder(View v) {
super(v);
mCardView = (CardView) v.findViewById(R.id.card_view);
mTextView = (TextView) v.findViewById(R.id.tv_city);
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(String[] myDataset) {
mDataset = myDataset;
}
// Create new views (invoked by the layout manager)
#Override
public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.card_item, parent, false);
// set the view's size, margins, paddings and layout parameters
MyViewHolder vh = new MyViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
holder.mTextView.setText(mDataset[position]);
holder.mCardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String currentValue = mDataset[position];
Log.d("CardView", "CardView Clicked: " + currentValue);
}
});
}
#Override
public int getItemCount() {
return mDataset.length;
}
}
So I am expecting the cardview to be read from the adapter, as it is working for this case:
public class BlankFragment extends Fragment {
public BlankFragment() {
// Required empty public constructor
}
//
// #Override
// public void onCreate(Bundle savedInstanceState) {
// super.onCreate(savedInstanceState);
//
// }
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
final View rootView = inflater.inflate(R.layout.fragment_blank, container, false);
RecyclerView rv = rootView.findViewById(R.id.rv_recycler_view);
rv.setNestedScrollingEnabled(false);
Weather_OWM.placeIdTask asyncTask = new Weather_OWM.placeIdTask(new Weather_OWM.AsyncResponse() {
public void processFinish(String weather_city, String weather_description, String weather_temperature, String weather_humidity, String weather_pressure, String weather_updatedOn, String weather_iconText, String sun_rise, String sun_set) {
TextView cityField = rootView.findViewById(R.id.tv_city);
TextView sunrise = rootView.findViewById(R.id.tv_sunrt);
TextView sunset = rootView.findViewById(R.id.tv_sunst);
cityField.setText(weather_city);
sunrise.setText(sun_rise);
sunset.setText(sun_set);
}
});
asyncTask.execute(Double.toString(latlang.Lat), Double.toString(latlang.Lang)); // asyncTask.execute("Latitude", "Longitude")
rv.setHasFixedSize(true);
MyAdapter adapter = new MyAdapter(new String[]{"Today", "Golden Hour", "Blue Hour", "Civil Twilight", "Nautical Twilight", "Astronomical Twilight", "Hello", "World"});
rv.setAdapter(adapter);
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
rv.setLayoutManager(llm);
return rootView;
}
}
It's not about the string argument but the cityField TextView you're calling setText() on. You're initialising it with
rootView.findViewById(R.id.tv_city);
which returns null if the view is not found. So your fragment_blank layout does not have a view with id tv_city.
I am attempting to use the Swipecards library (https://github.com/Diolor/Swipecards) to build a tinder-esqe application. I am using a BaseAdapter to populate a layout with two text views and an image view that will be provided to the main SwipeFlingAdapterView. While both of the text fields are populated, I cannot get the image to appear on the cards. I have tried this implementation with both an ArrayAdapter and a BaseAdapter and the results are the same.
The activity layout (deal_page_layout)
<FrameLayout
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_height="match_parent"
android:layout_width="match_parent">
<com.lorentzos.flingswipe.SwipeFlingAdapterView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/swipe_fling_view"
app:rotation_degrees="10"
tools:context=".DealPage"
android:alpha="1.0"
app:max_visible="2"
app:min_adapter_stack="5"/>
</FrameLayout>
The layout being populated by the BaseAdapter (deal_card)
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="#+id/deal_card_image">
</ImageView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/deal_card_title"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_margin="15dp"
android:gravity="center"
android:textSize="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/deal_card_description"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_margin="15dp"
android:gravity="center"
android:textSize="20dp"/>
</RelativeLayout>
BaseAdapter class
public class DealBaseAdapter extends BaseAdapter {
private Context context;
private List<GrubbyDeal> dealList;
private LayoutInflater li;
public DealBaseAdapter(Context context, LayoutInflater li, ArrayList<GrubbyDeal> dealList){
this.context = context;
this.dealList = dealList;
this.li = li;
}
#Override
public int getCount(){
return dealList.size();
}
#Override
public Object getItem(int position){
return dealList.get(position);
}
#Override
public long getItemId(int position){
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
ViewHolder viewHolder;
//resuse a view if possible
if(convertView == null){
convertView = li.inflate(R.layout.deal_card,parent,false);
viewHolder = new ViewHolder();
viewHolder.img = (ImageView) convertView.findViewById(R.id.deal_card_image);
viewHolder.title = (TextView) convertView.findViewById(R.id.deal_card_title);
viewHolder.desc = (TextView) convertView.findViewById(R.id.deal_card_description);
convertView.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder) convertView.getTag();
}
GrubbyDeal curDeal = dealList.get(position);
viewHolder.img.setImageURI(curDeal.getImageUri());
viewHolder.title.setText(curDeal.getTitle());
viewHolder.desc.setText(curDeal.getDescription());
return convertView;
}
//view holder class to hold cached findViewByID results
private static class ViewHolder {
public ImageView img;
public TextView title;
public TextView desc;
}
And the main activity (DealPage)
public class DealPage extends Activity {
private ArrayList<GrubbyDeal> dealList;
private DealBaseAdapter dealAdapter;
SwipeFlingAdapterView flingContainer;
#Override
public void onCreate(Bundle sis){
super.onCreate(sis);
setContentView(R.layout.deal_page_layout);
//add some awesome cat deals to the adapter
dealList = new ArrayList<>();
for(int i=0; i < 5; i++){
GrubbyDeal tmp = new GrubbyDeal(i);
dealList.add(tmp);
}
//add another type of cat deal to the list
dealList.add(new GrubbyDeal());
dealAdapter = new DealBaseAdapter(this, getLayoutInflater(), dealList);
flingContainer = (SwipeFlingAdapterView) findViewById(R.id.swipe_fling_view);
flingContainer.setAdapter(dealAdapter);
flingContainer.setFlingListener(new SwipeFlingAdapterView.onFlingListener() {
#Override
public void removeFirstObjectInAdapter() {
// this is the simplest way to delete an object from the Adapter (/AdapterView)
Log.d("LIST", "removed object!");
GrubbyDeal popped = dealList.remove(0);
dealList.add(popped);
dealAdapter.notifyDataSetChanged();
}
#Override
public void onLeftCardExit(Object dataObject) {
makeToast(DealPage.this, "Left!");
}
#Override
public void onRightCardExit(Object dataObject) {
makeToast(DealPage.this, "Right!");
}
#Override
public void onAdapterAboutToEmpty(int itemsInAdapter) {
dealList.add(new GrubbyDeal());
dealAdapter.notifyDataSetChanged();
Log.d("LIST", "notified");
}
#Override
public void onScroll(float scrollProgressPercent) {
View view = flingContainer.getSelectedView();
}
});
flingContainer.setOnItemClickListener(new SwipeFlingAdapterView.OnItemClickListener() {
#Override
public void onItemClicked(int itemPosition, Object dataObject) {
makeToast(DealPage.this, "Clicked!");
}
});
}
}
Am I missing something obvious? Is there some vastly superior library that I should be using? Thanks,
Ian
I would recommend using Picasso to load images into your imageview.
Picasso.with(context).load(imgurl).into(viewHolder.img);
The problem was formatting. I was attempting to use
Uri.parse("android.resource://com.thepackage.theapp/R.drawable.cat4.jpg");
but wasn't getting a valid Uri back. So instead I am using resource ids with picasso and the card works great!
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