I'm trying to FirestoreRecyclerAdapter, and the data is loading and can be seen in the debugger just fine. However, when I try to set a TextView equal to some of the data it crashes because the the TextView is null.
When debugging it does first try to set the TextView using findViewById, but it fails and it is set to null.
I've seen suggestions of using onFinishInflate, but am unsure of where I can override that function in this scenario.
public class PostAdapter extends FirestoreRecyclerAdapter<Post, PostAdapter.PostHolder> {
public PostAdapter(#NonNull FirestoreRecyclerOptions<Post> options) {
super(options);
}
#NonNull
#Override
public PostHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.post_layout,
viewGroup, false);
return new PostHolder(v);
}
class PostHolder extends RecyclerView.ViewHolder {
TextView tvTitle;
TextView tvPitch;
public PostHolder(#NonNull View itemView) {
super(itemView);
tvTitle = itemView.findViewById(R.id.etTitle);
tvPitch = itemView.findViewById(R.id.etPitch);
}
}
#Override
protected void onBindViewHolder(#NonNull PostHolder holder, int position, #NonNull Post model) {
holder.tvTitle.setText(model.title);
holder.tvPitch.setText(model.pitch);
}
}
_________________________________________________
<?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">
<TextView
android:id="#+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="#+id/tvPitch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
You are using wrong reference to TextView i.e
etTitle
while your XML shows tvTitle
And Also the second textview is referring to wrong Id. So your code should be like this
tvTitle = itemView.findViewById(R.id.tvTitle);
tvPitch = itemView.findViewById(R.id.tvPitch);
Use this etPitch = itemView.findViewById(R.id.tvPitch); code.
Related
I have a custom RecycleView and I am able to display the data in the RecycleViewsuccessfully. Now, I want to access the text view from the custom layout in order to make the change in later part of my code. I have provided the layout, RecycleViewadapter and the method I have tried to access the TextView. But I am getting NullPointerException with the view is null. How can I access the textview((R.id.zb) from Mylayout.xml in my main activity to modify RecycleView items?
My layout:
<android.support.v7.widget.CardView android:id="#+id/card_view1"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardBackgroundColor="#color/cardview_light_background"
card_view:cardCornerRadius="5dp"
card_view:cardUseCompatPadding="true"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="3"
android:orientation="horizontal"
android:id="#+id/z">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Z "
style="#style/Base.TextAppearance.AppCompat.Large.Inverse"
android:layout_weight="1"
android:textColor="#color/colorPrimary"
android:gravity="center"
android:id="#+id/zn"/>
<TextView
android:id="#+id/zb"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="buy"
android:textColor="#333"
style="#style/Base.TextAppearance.AppCompat.Medium.Inverse"/>
<TextView
android:id="#+id/zs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="Sell"
android:textColor="#333"
style="#style/Base.TextAppearance.AppCompat.Medium.Inverse"/>
</LinearLayout>
</android.support.v7.widget.CardView>
RecycleView Adapter:
public class Adapter extends RecyclerView.Adapter<Adapter.Viewholder> {
private List<dispitems> m;
#NonNull
#Override
public Adapter.Viewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list1, parent, false);
return new Viewholder(itemView);
}
#Override
public void onBindViewHolder(#NonNull Adapter.Viewholder holder, int position) {
dispitems d = m.get(position);
holder.zb.setText(d.getZb());
holder.zs.setText(d.getZs());
holder.zn.setText(d.getZn());
}
#Override
public int getItemCount() {
return m.size();
}
Adapter(List<dispitems> m) {
this.m = m;
}
public class Viewholder extends RecyclerView.ViewHolder {
public TextView zb,zs,zn;
Viewholder(View itemView) {
super(itemView);
zn = (TextView) itemView.findViewById(R.id.zn);
zb = (TextView) itemView.findViewById(R.id.zb);
zs = (TextView) itemView.findViewById(R.id.zs);
}
}
}
I've tried the below options but it is showing the null pointer exception
Adapter.Viewholder row = (Adapter.Viewholder) recyclerView.findViewHolderForAdapterPosition(getCategoryPos(device));
row.zs.setTextColor(ContextCompat.getColor(this, R.color.colorAccent));
I have received the following exception.
java.lang.NullPointerException: Attempt to read from field 'android.widget.TextView cti.cryptotrackerindia.Adapter$Viewholder.zsell' on a null object reference
tried the below as well
View row = recyclerView.getLayoutManager().getChildAt(getCategoryPos(device));
Maybe I am not getting the question, but you should be able to just get the textview on onCreateViewHolder after you inflated the view.
public Adapter.Viewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list1, parent, false);
TextView txtView = (TextView )itemView.findViewById(R.id.zb);
return new Viewholder(itemView);
}
and then just store it as a member in the adapter.
If you want to update data displayed in RecyclerView, you should use notifyItemChanged(position, payload) to perform partial re-bind of ViewHolder.
Modifying layout of ViewHolder directly without referencing represented data can lead to discrepancy in displayed views, especially when You start scrolling your list and ViewHolders start being recycled and reused for other items.
I am new to android I have created recycler view with its adapter but it is not working. check the following code.
I tried to debug this activity but there is no error. and also in OtherOfferingAdapter program don't execute further after getItemCount().
File OtherOfferingAdapter.java
public class OtherOfferingAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private LayoutInflater inflater;
List<OtherOfferingData> data = Collections.emptyList();
OtherOfferingData current;
int currentPos=0;
//Create constructor to innitilize context and data sent from MainActivity
public OtherOfferingAdapter(Context context,List<OtherOfferingData> data){
this.context=context;
inflater = LayoutInflater.from(context);
this.data=data;
}
//Inflate the layout when viewholder created
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
View view = inflater.inflate(R.layout.container_offerings, parent, false);
MyHolder holder = new MyHolder(view);
return holder;
}
//Bind Data
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position){
MyHolder myHolder = (MyHolder) holder;
current = data.get(position);
myHolder.inputOfferingName.setText(current.offeringname);
myHolder.inputOfferingPrice.setText(current.price);
myHolder.inputOfferingRating.setRating(Float.parseFloat(current.rating));
Picasso.with(context).load(current.imageUrl).into(myHolder.inputOfferingImage);
if(current.dietType.equals("1")){
myHolder.inputDietType.setBackgroundResource(R.drawable.veg);
}else{
myHolder.inputDietType.setBackgroundResource(R.drawable.nonveg);
}
}
#Override
public int getItemCount(){
return data.size();
}
class MyHolder extends RecyclerView.ViewHolder{
ImageView inputOfferingImage, inputDietType;
TextView inputOfferingPrice, inputOfferingName;
RatingBar inputOfferingRating;
public MyHolder(View itemView){
super(itemView);
inputOfferingImage = (ImageView) itemView.findViewById(R.id.otherimage);
inputDietType = (ImageView) itemView.findViewById(R.id.otherdietType);
inputOfferingPrice = (TextView) itemView.findViewById(R.id.otherprice);
inputOfferingName = (TextView) itemView.findViewById(R.id.otherofferingnanme);
inputOfferingRating = (RatingBar) itemView.findViewById(R.id.otherrating);
}
}
}
File OtherOfferingData
public class OtherOfferingData {
public String imageUrl;
public String offeringname;
public String price;
public String dietType;
public String rating;
}
And I am calling adapter like this
recyclerView = (RecyclerView) findViewById(R.id.recycle_view);
offeringAdapter = new OtherOfferingAdapter(ProductDescriptionActivity.this, data);
recyclerView.setAdapter(offeringAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(ProductDescriptionActivity.this));
container_offerings.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:layout_marginBottom="30dp"
android:background="#color/lightGray"
android:paddingLeft="15dp"
android:paddingRight="15dp">
Activity Page
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/tools"
xmlns:design="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycle_view"
android:layout_width="0dp"
android:layout_height="0dp"
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#color/lightGray"
android:layout_marginBottom="90dp"/>
ThankYou
The size of your recycler view in the relative layout is 0dp try to change
android:layout_width="0dp"
android:layout_height="0dp"
both to match parent
android:layout_width="match_parent"
android:layout_height="match_parent"
Your recycler view and its adapter seems to be fine. But they don't appear on screen as they have 0dp as dimension.
I'm trying to follow the Android official doc for Creating Lists and Cards.
I found here that it was necessary to cast in TextView the ViewHolder but when I do it I have the following error: java.lang.ClassCastException: android.widget.LinearLayout cannot be cast to android.widget.TextView
My Adapter
public class CardsViewAdapter extends RecyclerView.Adapter<CardsViewAdapter.ViewHolder> {
private Game[] 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 ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView mTextView;
public ViewHolder(TextView v) {
super(v);
mTextView = (TextView) v.findViewById(R.id.textViewName);
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public CardsViewAdapter(Game[] myDataset) {
mDataset = myDataset;
}
// Create new views (invoked by the layout manager)
#Override
public CardsViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.cards_resume_game, parent, false);
// set the view's size, margins, paddings and layout parameters
//...
ViewHolder vh = new ViewHolder((TextView) v);
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
holder.mTextView.setText(mDataset[position].getId_game());
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return mDataset.length;
}
}
My Custom View 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"
android:tag="cards main container">
<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_height="wrap_content"
card_view:cardBackgroundColor="#color/blue_50"
card_view:cardCornerRadius="10dp"
card_view:cardElevation="5dp"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView
android:id="#+id/textViewName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge"/>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
You have those 2 mixed up. Assuming that in
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.cards_resume_game, parent, false);
the R.layout.cards_resume_game is LinearLayout, you should then have:
ViewHolder vh = new ViewHolder(v);
and have ViewHolder constructor accept a view:
public ViewHolder(View v) {
mTextView = (TextView) v.findViewById(R.id.some_text_view_id);
}
where some_text_view_id is a TextView in said layout, which will be fetched by findViewById()
In your adapter you are casting TextView to ViewHolder which isn't necessary, and you are also calling ViewHolder in a redundant way. Try this:
return new ViewHolder(v) instead of ViewHolder vh = new ViewHolder((TextView)
The reason you do not need this cast is because you are already casting mView under your ViewHolder constructor, or rather you're already defining the view it should expect.
I have two recyclerViews (say A and B) in the same layout that have an adapter which for both the recyclerViews look like this:
public class ChapterListAdapter extends RecyclerView.Adapter<ChapterListAdapter.ChapterListViewHolder>{
private final ArrayList<ChapterObj> mChapterListObj;
private final Context mContext;
public ChapterListAdapter(ArrayList<ChapterObj> chapterObj, Context c) {
mChapterListObj = chapterObj;
mContext = c;
}
#Override
public ChapterListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.chapter_list_item, parent, false);
ChapterListViewHolder vh = new ChapterListViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(ChapterListViewHolder holder, int position) {
holder.chapterNumber.setText(mChapterListObj.get(position).getChapterNumber());
}
#Override
public int getItemCount() {
return mChapterListObj.size();
}
public class ChapterListViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnTouchListener {
private TextView chapterNumber;
public ChapterListViewHolder(View itemView) {
super(itemView);
chapterNumber = (TextView) itemView.findViewById(R.id.chapter_number);
itemView.setOnClickListener(this);
itemView.setOnTouchListener(this);
}
#Override
public void onClick(View v) {
Log.d("hello", "hello");
}
}
}
}
Both A and B have click listeners. Independently, both work fine. But when both are in the same layout, whenever I click on an item of 'A', the click listener of 'B' gets triggered.
If you need to see more code, tell me which file you want to see, I'll add their code too.
Edit: The xml layout file in which I've used them together looks like this:
<RelativeLayout 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"
tools:context=".VerseActivity">
<android.support.v7.widget.RecyclerView
android:id="#+id/chapter_list_menu"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
xmlns:android="http://schemas.android.com/apk/res/android"
>
</android.support.v7.widget.RecyclerView>
<android.support.v7.widget.RecyclerView
android:id="#+id/verse_list_menu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_alignParentTop="true"
xmlns:android="http://schemas.android.com/apk/res/android"
>
</android.support.v7.widget.RecyclerView>
</RelativeLayout>
You can do same thing with Sectioned recycler view. which will even load faster and let you display as many sectioned as you want. (removes hurdle of 2-3 recyclerview in same page or view)
If you want to create your own you can check this - https://gist.github.com/gabrielemariotti/4c189fb1124df4556058
or you can find many libraries for that also.
I have this weird issue with my adapter that no methods are called.. The constructor works, it stops there if I have a breakpoint but from there, nothing.. onCreateViewHolder doesn't get called and neither onBindViewHolder and not even getItemCount.. I tried everything I could find online but nothing seems to be working so I don't know what to do. Any suggestions? Here's my code:
Fragment:
public class FragmentPackageDetails extends Fragment {
//other vars
RecyclerView rvPackageDetails;
DatabaseHandler database;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Bundle args = getArguments();
String temp = args.getString(KEY_TRACKER_CODE);
View v = inflater.inflate(R.layout.fragment_package_details_new, container, false);
return v;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
rvPackageDetails = (RecyclerView) view.findViewById(R.id.rvPackageDetails);
rvPackageDetails.setLayoutManager(new LinearLayoutManager(getActivity()));
database = new DatabaseHandler(getActivity());
selectedPackage = database.getPackage(trackerCode);
RecyclerView.Adapter adapter = new MyAdapter(selectedPackage.getRecords());
rvPackageDetails.setAdapter(adapter);
}
//other methods in class
}
MyAdapter
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private ArrayList<TrackingRecordCheckedOut> 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 class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView tvPackageDetailsRowDayOfWeek, tvPackageDetailsRowDayOfMonth, tvPackageDetailsRowNameOfMonth,
tvPackageDetailsRowDetailsTitle, tvPackageDetailsRowDetailsDescription, tvPackageDetailsRowDetialsTime;
public ViewHolder(View v) {
super(v);
tvPackageDetailsRowDayOfWeek = (TextView) v.findViewById(R.id.tvPackageDetailsRowDayOfWeek);
tvPackageDetailsRowDayOfMonth = (TextView) v.findViewById(R.id.tvPackageDetailsRowDayOfMonth);
tvPackageDetailsRowNameOfMonth = (TextView) v.findViewById(R.id.tvPackageDetailsRowNameOfMonth);
tvPackageDetailsRowDetailsTitle = (TextView) v.findViewById(R.id.tvPackageDetailsRowDetialsTime);
tvPackageDetailsRowDetailsDescription = (TextView) v.findViewById(R.id.tvPackageDetailsRowDetailsDescription);
tvPackageDetailsRowDetialsTime = (TextView) v.findViewById(R.id.tvPackageDetailsRowDetialsTime);
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(ArrayList<TrackingRecordCheckedOut> myDataset) {
mDataset = myDataset;
}
// Create new views (invoked by the layout manager)
#Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_list_item, parent, false);
// set the view's size, margins, paddings and layout parameters
ViewHolder vh = new ViewHolder(v);
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
TrackingRecordCheckedOut tr = mDataset.get(position);
holder.tvPackageDetailsRowDayOfWeek.setText(tr.getDayOfWeek());
holder.tvPackageDetailsRowDayOfMonth.setText(tr.getDayOfWeek());
holder.tvPackageDetailsRowNameOfMonth.setText(tr.getMonthOfYear());
holder.tvPackageDetailsRowDetailsTitle.setText(tr.getTitle());
holder.tvPackageDetailsRowDetailsDescription.setText(tr.getDetails());
holder.tvPackageDetailsRowDetialsTime.setText(tr.getTimeOfDay());
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return mDataset.size();
}
}
Fragment Layout:
<?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">
<android.support.v7.widget.RecyclerView
android:id="#+id/rvPackageDetails"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
RecyclerView Row Layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/llPackageDetailsRecyclerViewRow"
android:layout_width="match_parent"
android:layout_height="96dip"
android:orientation="horizontal"
android:weightSum="100">
<LinearLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="20"
android:orientation="vertical"
android:weightSum="10">
<TextView
android:id="#+id/tvPackageDetailsRowDayOfWeek"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="3"/>
<TextView
android:id="#+id/tvPackageDetailsRowDayOfMonth"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="4"/>
<TextView
android:id="#+id/tvPackageDetailsRowNameOfMonth"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="3"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="80"
android:orientation="vertical">
<TextView
android:id="#+id/tvPackageDetailsRowDetailsTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="3"/>
<TextView
android:id="#+id/tvPackageDetailsRowDetailsDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="4"/>
<TextView
android:id="#+id/tvPackageDetailsRowDetialsTime"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="3"/>
</LinearLayout>
</LinearLayout>
I had this same issue where neither onCreateViewHolder or onBindViewHolder were being called. Saving a reference to Context in the constructor of your Adapter, and then changing your onCreateViewHolder method to use the saved reference to Context instead of doing parent.getContext() should fix it:
private Context mContext;
public MyAdapter(Context context, ArrayList<TrackingRecordCheckedOut> myDataset) {
mDataset = myDataset;
mContext = context;
}
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view using saved reference to Context (mContext)
View v = LayoutInflater.from(mContext).inflate(R.layout.recyclerview_list_item, parent, false);
// set the view's size, margins, paddings and layout parameters
ViewHolder vh = new ViewHolder(v);
return vh;
}
I looked at your code don't really see an issue unfortunately. One thing that might be problematic is that in you ViewHolder constructor you call super(v). You might need to call super((LinearLayout)v). That might not make a difference though.
Good luck!