Fragment.java
public class RuteEfectuateFragment extends Fragment {
View v;
RecyclerView mRecyclerView;
FirebaseDatabase mFirebaseDatabase;
DatabaseReference mRef;
private FirebaseRecyclerAdapter<Model, ViewHolder> firebaseRecyclerAdapter;
final Context context = this.getContext();
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
((ProfileActivity) Objects.requireNonNull(getActivity())).setActionBarTitle("Rute efectuate");
v = inflater.inflate(R.layout.fragment_rute_efectuate, container, false);
mRecyclerView = v.findViewById(R.id.recyclerView);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mFirebaseDatabase = FirebaseDatabase.getInstance();
mRef = mFirebaseDatabase.getReference("Rute");
return v;
}
#Override
public void onStart() {
super.onStart();
firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Model, ViewHolder>(Model.class, R.layout.card_layout, ViewHolder.class, mRef){
#Override
protected void populateViewHolder(ViewHolder viewHolder, Model model, final int position) {
viewHolder.setDetails(getContext(), model.getTaraPlecare(), model.getTaraDestinatie());
viewHolder.itemView.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
// Intent intent = new Intent(Fridge.this, Show.class);
// startActivity(intent);
}
});
}
};
RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(getActivity(), 1);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(firebaseRecyclerAdapter);
}}
Viewholder.java
public class ViewHolder extends RecyclerView.ViewHolder {
private View mView;
public ViewHolder(View itemView) {
super(itemView);
mView = itemView;
}
public void setDetails(Context ctx, String TaraPlecare, String TaraDestinatie){
TextView mTaraPlecare = mView.findViewById(R.id.rTitleTv);
TextView mTaraDestinatie = mView.findViewById(R.id.rDateTv);
mTaraPlecare.setText(TaraPlecare);
mTaraDestinatie.setText(TaraDestinatie);
}}
Can you tell me please why RecyclerView doesn't appear? It appears just when keyboard is opened and I close it and I can't find the reason. If it is necessary I can record how the RecyclerView appears by hiding the keyboard. I tried also tu find a similar question, but I couldn't find.
When using Firebase database and RecyclerView, Firebase database requires to fixed size of RecyclerView be false. I think because Firebase Database is asynchronous and that means RecyclerView will get first an empty adapter and after data is fetched from database, it will be than populated with data.
That affects the size, so if you put fixed size to true it will fail to calculate the size, so that is why it needs false in fixed size. So solution is: mRecyclerView.setHasFixedSize(false);
Related
I'm new to android studio . I'm trying to display items in RecycleView but it's doesn't show anything.
This is what android studio says:
E/RecyclerView: No layout manager attached; skipping layout
My Fragment :
public class Articles extends Fragment {
View root;
RecyclerView recyclerView;
NewsList[] myListData = new NewsList[] {
new NewsList("Article 1", "Some Author"),
new NewsList("Article2", "Some Author"),
new NewsList("Article3", "Some Author"),
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
root = inflater.inflate(R.layout.fragment_articles, container, false);
recyclerView = root.findViewById(R.id.recyclerView);
NewsAdapter adapter = new NewsAdapter(myListData);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
return root;
}
Here is the code of my Adapter class :
public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {
private NewsList[] listdata;
// RecyclerView recyclerView;
public NewsAdapter(NewsList[] listdata) {
this.listdata = listdata;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View listItem= layoutInflater.inflate(R.layout.list_item, parent, false);
ViewHolder viewHolder = new ViewHolder(listItem);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
final NewsList myListData = listdata[position];
holder.textView1.setText(listdata[position].getTitle());
holder.textView2.setText(listdata[position].getAuthor());
holder.relativeLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(view.getContext(),"click on item: "+myListData.getTitle(),Toast.LENGTH_LONG).show();
}
});
}
#Override
public int getItemCount() {
return listdata.length;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView textView1;
public TextView textView2;
public RelativeLayout relativeLayout;
public ViewHolder(View itemView) {
super(itemView);
this.textView1 = (TextView) itemView.findViewById(R.id.textView1);
this.textView2 = (TextView) itemView.findViewById(R.id.textView2);
relativeLayout = (RelativeLayout)itemView.findViewById(R.id.relativeLayout);
}
}
Previously I had an error where the app crashed when opened the fragment but now it's skips the RecyclerView.
I will be gratefull if you help me to resolve this issue.
You need to add a layoutManager to your recycler view:
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
root = inflater.inflate(R.layout.fragment_articles, container, false);
recyclerView = root.findViewById(R.id.recyclerView);
NewsAdapter adapter = new NewsAdapter(myListData);
recyclerView.setHasFixedSize(true);
// Add this line
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()))
recyclerView.setAdapter(adapter);
return root;
}
It's mandatory to have a Layout manager for your Recyclerview. For example, you can use a linear one by adding this after inflating your view :
recyclerView.setLayoutManager(new LinearLayoutManager( context ));
where context is whatever your context is
This question already has an answer here:
showing RecyclerView on fragment with data from Firebase
(1 answer)
Closed 3 years ago.
I am not able to attach the Firestore Recycler Adapter in the fragment.
I googled many things but no good yet.
The fragment is one of the tabs of the bottomtablayout.
The data is retrieved from a single collection. I want represent the list of multlipe-user post in a single view.
I have tried the below code but to no good yet.
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
//just change the fragment_dashboard
//with the fragment you want to inflate
//like if the class is HomeFragment it should have R.layout.home_fragment
//if it is DashboardFragment it should have R.layout.fragment_dashboard
View view = inflater.inflate(R.layout.fragment_home, container, false);
final FragmentActivity c = getActivity();
LinearLayoutManager layoutManager = new LinearLayoutManager(c);
Query query = PostsRef.orderBy("timestamp", Query.Direction.DESCENDING);
FirestoreRecyclerOptions<PostsModel> options = new FirestoreRecyclerOptions.Builder<PostsModel>()
.setQuery(query, PostsModel.class)
.build();
adapter = new PostsAdapter(options);
recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(c));
recyclerView.setAdapter(adapter);
mParent =view.findViewById(R.id.relative_home);
return inflater.inflate(R.layout.fragment_home, null);
}
Adapter Code
public class PostsAdapter extends FirestoreRecyclerAdapter<PostsModel, PostsAdapter.PostsHolder> {
private OnItemClickListener listener;
public PostsAdapter(#NonNull FirestoreRecyclerOptions<PostsModel> options) {
super(options);
}
#Override
protected void onBindViewHolder(#NonNull PostsHolder holder, int position, #NonNull PostsModel model) {
//retrieve the fields here
holder.textViewTitle.setText(model.getPostTitle());
holder.textViewDescription.setText(model.getPostContent());
holder.textViewPriority.setText(String.valueOf(model.getSpinnerC()));
holder.AuthorName.setText(model.getName());
holder.AuthorGender.setText(model.getGender());
}
#NonNull
#Override
public PostsHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.post_list_layout,
parent, false);
return new PostsHolder(v);
}
public void deleteItem(int position) {
getSnapshots().getSnapshot(position).getReference().delete();
}
class PostsHolder extends RecyclerView.ViewHolder {
TextView textViewTitle;
TextView textViewDescription;
TextView textViewPriority;
TextView AuthorName;
TextView AuthorGender;
public PostsHolder(View itemView) {
super(itemView);
textViewTitle = itemView.findViewById(R.id.quote1);
textViewDescription = itemView.findViewById(R.id.name1);
textViewPriority = itemView.findViewById(R.id.timestamp1);
}
}
}
You're inflating the other view in the onCreateView method.
return inflater.inflate(R.layout.fragment_home, null);
I am facing these problem about Recyclerview No adapter attached.
This is my Locat:
E/RecyclerView: No adapter attached; skipping layout
D/OpenGLRenderer: eglDestroySurface = 0x730c9a02d0
D/ViewRootImpl#8aa7e83[AddPostActivity]: Relayout returned: old=[0,0]
[1080,1920] new=[0,0][1080,1920] result=0x5 surface={valid=false 0}
changed=true
W/ClassMapper: No setter/field for YtyKXov13lReyirA8U4iritiUs6220-July-
201910: 39 found on class gurungdinesh.com.sisapen.ModelPost
W/ClassMapper: No setter/field for pdMZtSaxkzd5Uul592qwXKawnaI220-July-
201910: 40 found on class gurungdinesh.com.sisapen.ModelPost
D/FA: Connected to remote service
V/FA: Processing queued up service tasks: 4
I/zygote64: Do partial code cache collection, code=498KB, data=332KB
I/zygote64: After code cache collection, code=498KB, data=332KB
I/zygote64: Increasing code cache capacity to 2MB
D/ViewRootImpl#f8f3e40[MainActivity2]: MSG_RESIZED_REPORT: frame=Rect(0,
0 - 1080, 1920) ci=Rect(0, 72 - 0, 0) vi=Rect(0, 72 - 0, 0) or=1
MSG_WINDOW_FOCUS_CHANGED 1
This is my Adapter:
public class AdapterPost extends
RecyclerView.Adapter<AdapterPost.MyHolder> {
Context context;
List<ModelPost> postList;
public AdapterPost(Context context, List<ModelPost>postList) {
this.context = context;
this.postList = postList;
}
#NonNull
#Override
public MyHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int
viewType) {
//inflate layout
View view =
LayoutInflater.from(context).inflate(R.layout.activity_users_posts,
viewGroup, false);
return new MyHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MyHolder myHolder, int i) {
//get data
String fullname = postList.get(i).getFullname();
String date = postList.get(i).getDate();
String time = postList.get(i).getTime();
String Title = postList.get(i).getTitle();
String Writing = postList.get(i).getWriting();
//set data
myHolder.uNameTv.setText(fullname);
myHolder.pTimeTv.setText(time);
myHolder.pDate.setText(date);
myHolder.pTitileTv.setText(Title);
myHolder.pWritingTv.setText(Writing);
}
#Override
public int getItemCount() {
return postList.size();
}
//view holder class
class MyHolder extends RecyclerView.ViewHolder
{
//views from users post
ImageButton moreBtn;
CircularImageView uPictureIv;
TextView uNameTv, pTimeTv, pTitileTv, pWritingTv, pLikesTv, pDate;
Button likebtn, commentBtn, shareBtn;
private MyHolder(#NonNull View itemView) {
super(itemView);
//init views
uPictureIv = itemView.findViewById(R.id.uPictureTv);
uNameTv = itemView.findViewById(R.id.uNameTv);
pTimeTv = itemView.findViewById(R.id.pTimeTv);
moreBtn = itemView.findViewById(R.id.moreBtn);
pDate = itemView.findViewById(R.id.pDateTv);
pTitileTv = itemView.findViewById(R.id.pTitleTv);
pWritingTv = itemView.findViewById(R.id.pWriting);
pLikesTv = itemView.findViewById(R.id.pLikesTv);
likebtn = itemView.findViewById(R.id.likeBtn);
commentBtn = itemView.findViewById(R.id.commentBtn);
shareBtn = itemView.findViewById(R.id.shareBtn);
}
This is my HomeFragment:
public class HomeFragment extends Fragment {
private FirebaseAuth mFirebase;
private DatabaseReference databaseReference;
private RecyclerView recyclerView;
private List<ModelPost> postList;
private AdapterPost adapterPost;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable
ViewGroup container, #Nullable Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.home_activity, container,
false);
//init
mFirebase = FirebaseAuth.getInstance();
databaseReference =
FirebaseDatabase.getInstance().getReference("posts");
recyclerView = view.findViewById(R.id.all_user_post_list);
LinearLayoutManager layoutManager = new
LinearLayoutManager(getActivity());
layoutManager.setStackFromEnd(true);
layoutManager.setReverseLayout(true);
recyclerView.setLayoutManager(layoutManager);
postList = new ArrayList<>();
loadPosts();
return view;
}
private void loadPosts() {
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
postList.clear();
for (DataSnapshot ds : dataSnapshot.getChildren()) {
ModelPost modelPost = ds.getValue(ModelPost.class);
postList.add(modelPost);
//adapter
adapterPost = new AdapterPost(getActivity(), postList);
//set adapter to RecyclerView
recyclerView.setAdapter(adapterPost);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
//in case of error
Toast.makeText(getActivity(), "" +
databaseError.getMessage(), Toast.LENGTH_SHORT).show();
}
});
I have tried so many things but nothing happen.
Since Firebase Tasks are Async the setAdapter method is called after your return view; in onCreateView method. That's why it gives the error No adapter attached. What you can do is call setAdapter in the onCreateView method and after you have populated the list, call notifyDataSetChanged(). See the code below
public class HomeFragment extends Fragment {
private FirebaseAuth mFirebase;
private DatabaseReference databaseReference;
private RecyclerView recyclerView;
private List<ModelPost> postList;
private AdapterPost adapterPost;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable
ViewGroup container, #Nullable Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.home_activity, container,
false);
//init
mFirebase = FirebaseAuth.getInstance();
databaseReference =
FirebaseDatabase.getInstance().getReference("posts");
recyclerView = view.findViewById(R.id.all_user_post_list);
LinearLayoutManager layoutManager = new
LinearLayoutManager(getActivity());
layoutManager.setStackFromEnd(true);
layoutManager.setReverseLayout(true);
recyclerView.setLayoutManager(layoutManager);
postList = new ArrayList<>();
// ----------- set the adapter here --------------------
adapterPost = new AdapterPost(getActivity(), postList);
recyclerView.setAdapter(adapterPost);
loadPosts();
return view;
}
private void loadPosts() {
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
postList.clear();
for (DataSnapshot ds : dataSnapshot.getChildren()) {
ModelPost modelPost = ds.getValue(ModelPost.class);
postList.add(modelPost);
}
// ----------- call notifyDataSetChanged --------------------
adapterPost.notifyDataSetChanged()
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
//in case of error
Toast.makeText(getActivity(), "" +
databaseError.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
You get this message because RecyclerView has no adapter set when the layout is drawn.
What you can do is that you can assign an empty adapter at start, i.e. in onCreateView(), then add the data to your adapter when you have it. This way you will not see this log. However, the first place you set the adapter is in a asynchronous code block. Everything is already drawn and the recyclerview hasn't provided an adapter yet, so it prints this log.
I am still new for the android development. Currently, I am trying to show a RecyclerView within a Fragment. I tried to show the RecyclerView without using Fragment and it worked fine. But when it come to using Fragment, nothing is shown.
Here is the MainActivity containing the Fragment:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//ButterKnife.bind(this);
BottomNavigationView navView = findViewById(R.id.nav_view);
navView.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
mViewModel = ViewModelProviders.of(this).get(MainActivityViewModel.class);
mFragmentManager = getSupportFragmentManager();
mFragmentTransaction = mFragmentManager.beginTransaction();
mFragmentTransaction.add(R.id.fragment_container, missionListFragment).addToBackStack(null).commit();
}
And the Fragment's onCreateView method:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_mission_list, container, false);
//ButterKnife.bind(rootview);
mRecycler = (RecyclerView) rootView.findViewById(R.id.recycler);
mFirestore = FirebaseFirestore.getInstance();
mQuery = mFirestore.collection("COLLECTION_NAME").limit(LIMIT);
if (mQuery == null) {
Log.w(TAG, "No query, not initializing RecyclerView. Created data on server.");
}
mAdapter = new RecyclerViewAdapter(mQuery, this) {
#Override
protected void onDataChanged() {
}
#Override
protected void onError(FirebaseFirestoreException e) {
// Show a snackbar on errors
Snackbar.make(getActivity().findViewById(android.R.id.content),
"Error: check logs for info.", Snackbar.LENGTH_LONG).show();
}
};
mRecycler.setLayoutManager(new LinearLayoutManager(getActivity()));
mRecycler.setAdapter(mAdapter);
return rootView;
}
With the RecyclerViewAdapter:
public class RecyclerViewAdapter extends FirestoreAdapter<RecyclerViewAdapter.ViewHolder> {
private static final int UNAVAILABLE = 0, AVAILABLE = 1;
public interface OnItemSelectedListener {
void onItemSelected(DocumentSnapshot item);
}
private OnItemSelectedListener mListener;
public RecyclerViewAdapter(Query query, OnItemSelectedListener listener) {
super(query);
mListener = listener;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return new ViewHolder(inflater.inflate(R.layout.item, parent, false));
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.bind(getSnapshot(position), mListener);
}
static class ViewHolder extends RecyclerView.ViewHolder {
#BindView(R.id.view1)
TextView view1;
#BindView(R.id.view2)
TextView view2;
#BindView(R.id.view3)
TextView view3;
#BindView(R.id.view4)
TextView view4;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
public void bind(final DocumentSnapshot snapshot,
final OnItemSelectedListener listener) {
Item item = snapshot.toObject(Item.class);
Resources resources = itemView.getResources();
view1.setText(item.getfield1());
view2.setText(Integer.toString(item.getfield2()));
if(item.getfield3() == AVAILABLE)
view3.setText("Available");
else
view3.setText("Unavailable");
view4.setText(item.getfield4().toString());
// Click listener
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (listener != null) {
listener.onItemSelected(snapshot);
}
}
});
}
}
}
As you can notice above, I am getting data from the Firebase and displaying them as a RecyclerView. But I don't think it is the problem of empty query data, so please help.
It could be that data from firebase is not being retrieved, hence there is no content for recyclerview to display. Please check if your firebase connection is working fine and you are retrieving something from it
I made a RecyclerView with CardViews that retrieve two TextViews from the Cloud Firestore and whenever I click on the card, I want it, based on the pdfUrl stored in my Firestore database, that an activity be opened with the pdf or donwload the pdf to the phone. But I don't know how to achieve that.
Here's my firestore structure
My code:
public class RecylerViewTestsActivity extends AppCompatActivity {
RecyclerView recyclerView;
private FirebaseFirestore db = FirebaseFirestore.getInstance();
private FirestoreRecyclerAdapter<uploadTests, TestesViewHolder> adapter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recyler_view_tests);
RecyclerView recyclerView = findViewById(R.id.recyclerViewTests);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
Query query = rootRef.collection("FilterPDFUploads");
FirestoreRecyclerOptions<uploadTests> options = new FirestoreRecyclerOptions.Builder<uploadTests>()
.setQuery(query, uploadTests.class)
.build();
adapter = new FirestoreRecyclerAdapter<uploadTests,TestesViewHolder >(options) {
#Override
protected void onBindViewHolder(#NonNull TestesViewHolder holder, int position, #NonNull uploadTests model) {
holder.setTestesDesc(model.getDescription());
holder.setTestesName(model.getUsername());
}
#NonNull
#Override
public TestesViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.pdf_tests_items, parent, false);
return new TestesViewHolder(view);
}
};
recyclerView.setAdapter(adapter);
}
//////////////////////////VIEW HOLDER////////////////////////////////////////////
private class TestesViewHolder extends RecyclerView.ViewHolder {
private View view;
private CardView itemsCard;
TestesViewHolder(final View itemView) {
super(itemView);
view = itemView;
}
void setTestesDesc (String descri) {
TextView desc = view.findViewById(R.id.teste_description);
desc.setText(descri);
}
void setTestesName (String username) {
TextView user = view.findViewById(R.id.name_id);
user.setText(username);
}
void setPdfUrl(final String url){
}
}
//////////////////////////VIEW HOLDER////////////////////////////////////////////
#Override
protected void onStart() {
super.onStart();
adapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
if (adapter != null) {
adapter.stopListening();
}
}
}
whenever I click on the card, I want it, based on the pdfUrl stored in my firestore database, that an activity be opened with the pdf or donwload the pdf to the phone
To solve this, you should use setOnClickListener() on your TestesViewHolder object. Inside the click listener, please add the following lines of code:
Uri uri = Uri.parse(url);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
Where url is the actual url that is stored in your database. That's it!