These are steps I am doing in this project:
First I am creating a user profile on Firebase
Once the profile is created, I am redirecting the user to another activity, where the user is creating a journal with Image
Then saving the journal with image on Firestore
Once the data is created on the user profile, I am trying to fetch the values from Firestore using RecyclerView Adapter
Then on a listing page I am trying to fetch all the values in an ArrayList--> here I am getting the error of No Adapter Attached
The ArrayList Activity file:
Initializing the recyclerView in OnCreate
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_journal_list);
firebaseAuth= FirebaseAuth.getInstance();
user= firebaseAuth.getCurrentUser();
noJournalEntry= findViewById(R.id.list_no_thoughts);
journalList= new ArrayList<>();
recyclerView= (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
}
Invoking the RecyclerView in onStart:
#Override
protected void onStart() {
super.onStart();
//we are getting the user Id of the person who is logged in
collectionReference.whereEqualTo("userId", JournalApi.getInstance()
.getUserId())
.get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
if(!queryDocumentSnapshots.isEmpty()) {
for(QueryDocumentSnapshot journals: queryDocumentSnapshots){
Journal journal = journals.toObject(Journal.class);
journalList.add(journal);
Toast.makeText(JournalListActivity.this,"UserId found", Toast.LENGTH_LONG).show();
}
// Invoke Recyclerview
journalRecyclerAdapter= new JournalRecyclerAdapter(JournalListActivity.this, journalList);
recyclerView.setAdapter(journalRecyclerAdapter);
journalRecyclerAdapter.notifyDataSetChanged();
} else {
noJournalEntry.setVisibility(View.VISIBLE);
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(JournalListActivity.this,"UserId NOT found", Toast.LENGTH_LONG).show();
}
});
}
}
As you can see that the RecyclerView is called fine, but the ArrayList is not loading.
The Error: E/RecyclerView: No adapter attached; skipping layout
I referred to various posts in Stackoverflow and followed the steps, not sure where I am going wrong.
I am adding screenshots here of the Arraylist file:
The RecyclerView adapter:
You are getting the following warning, not an error:
E/RecyclerView: No adapter attached; skipping layout
Because you are setting the adapter in a background thread. To solve this, you have to set the adapter outside the callback and inside it, just notify it about the changes. So please move the following lines of code:
journalRecyclerAdapter= new JournalRecyclerAdapter(JournalListActivity.this, journalist);
recyclerView.setAdapter(journalRecyclerAdapter);
Right after:
super.onStart();
And leave the following line as it is inside the callback:
journalRecyclerAdapter.notifyDataSetChanged();
And the warning will disapear.
Related
By the title of this question, its easily understandable that, the adapter of recyclerview is not set inside a UI thread. But in my case to avoid that I have tried doing it even on UI thread but still no luck.
I am using FirebaseUI for my app. Below is the code snippet:
public static void getUserFromUserId(#NonNull DatabaseReference dbRef, #NonNull String userId) {
dbRef.child(USERS).child(userId)
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
FriendsActivity.this.runOnUiThread(new Handler() {
#Override
public void run() {
loadFriends(user);
}
});
}
#Override
public void onCancelled(DatabaseError databaseError) {
FirebaseCrash.report(databaseError.toException());
}
});
}
private void loadFriends(User user) {
Query friendsRef = ; // your firebase DatabseReference path
FirebaseRecyclerAdapter<Friend, FriendViewHolder> adapter =
new FirebaseRecyclerAdapter<Friend, FriendViewHolder>(Friend.class,
R.layout.item_challenge, FriendViewHolder.class, friendsRef) {
#Override
protected void populateViewHolder(FriendViewHolder viewHolder, Friend model, int position) {
viewHolder.setFriendName(model.getName());
viewHolder.setFriendPic(FriendActivity.this, model.getProfilePic());
}
};
mRecyclerView.setAdapter(adapter);
}
My Activity's onCreate() method has below code related to RecyclerView:
mRecyclerView = (RecyclerView) findViewById(R.id.challenge_recycler_view);
mRecyclerView.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(layoutManager);
I dont understand why even after calling loadFriends inside runOnUiThread, why the error still persists.
Any help is appreciated.
You need to attach your adapter when you initialize your RecyclerView and attach LayoutManager, etc.
loadFriends method should fetch data and add data to the adapter and then you should call notifyDataSetChanged or equivalent.
What you're doing here is incorrect. A recyclerview should always have an adapter attached. You just need to update the data in the adapter.
And that's what the error says E/RecyclerView﹕ No adapter attached; skipping layout. Because you have not attached adapter after attaching LayoutManager and you're attaching adapter at a later stage.
Did you try adding LayoutManager in your recyclerView?
Make sure you call setLayoutManager, like below.
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
before setting adapter into recyclerView, otherwise it is not gonna work.
Source : - recyclerview-not-call-any-adapter-method
I want my RecyclerView to be scrolled to the bottom when my chat loads up but when the user manually scrolls up the list to read previous messages it should not scroll back down again upon the addition of new item in the list unless the message(new item) is sent/added by the user himself.
I have tried using both layoutManager.setStackFromEnd(true) and recyclerView.scrollToPosition(list.size() - 1). Both of these methods automatically scroll down the list upon receiving a new message if I have scrolled up manually it should not scroll down to the bottom again unless im the one sending the message.
mref.child(RoomName).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot dataSnapshot1 :dataSnapshot.getChildren()) {
ChatMessage value = dataSnapshot1.getValue(ChatMessage.class);
ChatMessage fire = new ChatMessage();
String msgtxt = value.getMessageText();
String user=value.getMessageUser();
long msgtime=value.getMessageTime();
String prothumb=value.getProfuri();
String sentimguri=value.getSentimguri();
String type=value.getType();
fire.setMessageUser(user);
fire.setMessageText(msgtxt);
fire.setMessageTime(msgtime);
fire.setProfuri(prothumb);
fire.setSentimguri(sentimguri);
fire.setType(type);
list.add(fire);
}
adapter = new RecyclerViewAdapter(ChatRoom.this, list);
recyclerView.setAdapter(adapter);
//layoutManager.setStackFromEnd(true);
}
//Initializing RecyclerView
private void initRecyclerView() {
//Log.d(TAG, "initRecyclerView: init recyclerview.");
recyclerView =(RecyclerView) findViewById(R.id.list_of_messages);
recyclerView.setHasFixedSize(true);
layoutManager=new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
//recyclerView.scrollToPosition(list.size() - 1);
}
}
Upon getting the chat list , you need not have to create the new instance of adapter everytime .Instead just notify the adapter about the change .
mref.child(RoomName).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
list.clear();
for(DataSnapshot dataSnapshot1 :dataSnapshot.getChildren()) {
ChatMessage value = dataSnapshot1.getValue(ChatMessage.class);
ChatMessage fire = new ChatMessage();
String msgtxt = value.getMessageText();
String user=value.getMessageUser();
long msgtime=value.getMessageTime();
String prothumb=value.getProfuri();
String sentimguri=value.getSentimguri();
String type=value.getType();
fire.setMessageUser(user);
fire.setMessageText(msgtxt);
fire.setMessageTime(msgtime);
fire.setProfuri(prothumb);
fire.setSentimguri(sentimguri);
fire.setType(type);
list.add(fire);
}
if(!(recyclerView.canScrollVertically(1)))
{
recyclerView.smoothScrollToPosition(adapter.getItemCount());
}
adapter.notifyDataSetChanged();
//layoutManager.setStackFromEnd(true);
}
//Initializing RecyclerView
private void initRecyclerView() {
//Log.d(TAG, "initRecyclerView: init recyclerview.");
recyclerView =(RecyclerView) findViewById(R.id.list_of_messages);
recyclerView.setHasFixedSize(true);
layoutManager=new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
//initialse your adapter only once
adapter = new RecyclerViewAdapter(ChatRoom.this, list);
recyclerView.setAdapter(adapter);
layoutManager.setStackFromEnd(true);
//recyclerView.scrollToPosition(list.size() - 1);
}
}
This might will solve your issue .
The issue I can see is that you are creating a new instance of adapter everytime when data changes. Which explains why it always scroll down to bottom. And it's not a proper way of using a recyclerView.
What you need to do is to create just one instance of adapter during initRecyclerView using an empty list. Then whenever data changes, update the existing list and then call adapter.notifyDataSetChanged(). This will give you the behaviour that you wanted.
Keep getting the following error:
E/RecyclerView: No adapter attached; skipping layout.
As you can see below I have the adapter set but in the OnDataChange() Method I think this may be the issue as it needs to be in the OnCreate() method but I cannot seem to fix it.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_judge);
RecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
RecyclerView.setHasFixedSize(true);
RecyclerView.setLayoutManager(new LinearLayoutManager(this));
ProgressCircle = findViewById(R.id.progress_circle);
mUploads = new ArrayList<>();
DatabaseRef = FirebaseDatabase.getInstance().getReference("uploads");
DatabaseRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
UploadClass upload =
postSnapshot.getValue(UploadClass.class);
mUploads.add(upload);
}
Adapter = new ImageAdapter(JudgeActivity.this, mUploads);
ProgressCircle.setVisibility(View.INVISIBLE);
RecyclerView.setAdapter(Adapter);
}
You set the adapter but did so too late. The view is loaded with no adapter because you're waiting for Firebase.
Ideally you should set your adapter initially, so remove the mUploads paramater in the constructor.
#Override
protected void onCreate(Bundle savedInstanceState) {
recyclerView = (RecyclerView) find...
recyclerView.setAdapter(new ImageAdapter(this));
...
}
Initially the adapter will have no data - but the RecyclerView will have an adapter solving your problem.
You can set the data later, if you store an instance of your adapter you can simply:
adapter.setUploads(mUploads)
in your Firebase call.
This question already has answers here:
recyclerview No adapter attached; skipping layout
(38 answers)
No adapter attached; skipping layout [duplicate]
(2 answers)
Closed 3 years ago.
Its giving me "RecyclerView: No adapter attached; skipping layout" error but in my opinion adapter is correctly attached. Please help.
public class MainActivity extends AppCompatActivity {
private final String TAG = "MainActivity";
private RecyclerView recyclerView;
private LinearLayoutManager layoutManager;
private RecyclerViewAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView)findViewById(R.id.recycler_view);
layoutManager = new LinearLayoutManager(MainActivity.this);
recyclerView.setLayoutManager(layoutManager);
requestJsonObject();
}
private void requestJsonObject(){
RequestQueue queue = Volley.newRequestQueue(this);
String url ="https://api.myjson.com/bins/2t4j3";
StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d(TAG, "Response " + response);
GsonBuilder builder = new GsonBuilder();
Gson mGson = builder.create();
List<ItemObject> posts = new ArrayList<ItemObject>();
posts = Arrays.asList(mGson.fromJson(response, ItemObject[].class));
adapter = new RecyclerViewAdapter(MainActivity.this, posts);
recyclerView.setAdapter(adapter);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "Error " + error.getMessage());
}
});
queue.add(stringRequest);
}
}
I was moving my methods, but its not working. I was looking here for answer but there was only problems with wrong implemented adapters. I dont't know whats wrong here.
Try to put this line:
adapter = new RecyclerViewAdapter(MainActivity.this, posts);
After adding a LayoutManager to the RecyclerView. Of course the list will be empty, but just init RecyclerAdapter and assign it to the RecyclerView
Then, when Volley completes it's request, use:
recyclerView.getAdapter().addAll(posts);
recyclerView.getAdapter().notifyDataSetChaged();
The last commands add elements to the RecyclerView's adapter and notify LayoutManager of the change.
You are calling setAdapter in a delay thread. When the view is created in the main thread, the Recyclerview do not have an adapter.
Put this two lines before setLayoutManager
List<ItemObject> posts = new ArrayList<ItemObject>();
adapter = new RecyclerViewAdapter(MainActivity.this, posts);
In onResponse, you can ethier set a new adpater or update the data in the adapter which depends on your implementation.
I have 3 tabs in my main activity. In the 2nd tab I have a fragment that has a list and I am using Retrofit to get data from my server and display it in the list.
In my 2nd fragment I have:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_recents, container, false);
mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
getBooks();
}
private void getBooks(){
final ProgressDialog loading = ProgressDialog.show(getContext(), "Fetching Data", "Please wait...", false, false);
/* Retrofit code: */
//Creating a rest adapter
RestAdapter adapter = new RestAdapter.Builder()
.setEndpoint(ROOT_URL)
.build();
//Creating an object of our api interface
MyAPI api = adapter.create(MyAPI.class);
//Defining the method
api.getBooks(new Callback<List<MyPojo>>() {
#Override
public void success(List<MyPojo> list, Response response) {
//Dismissing the loading progressbar
loading.dismiss();
//Storing the data in our list
pojos = list;
mAdapter = new MyAdapter(getContext(), pojos);
mRecyclerView.setAdapter(mAdapter);
}
#Override
public void failure(RetrofitError error) {
//you can handle the errors here
loading.dismiss();
Log.v("Error: ", "" + error);
}
});
}
my problem is that the progress dialog is shown as soon as the app is launched in the 1st tab..I want it to fetch the data only when the 2nd tab is opened.
According to the developer guide for fragments, a fragment's lifecycle (see Figure 2 in the link) is only active (i.e. displayed and the user can interact with it) between the onResume() and onPause() android callbacks.
If you want something to only occur when the fragment is displayed, place the code for showing it in the onResume() callback. You can pre-fetch or do other setup in other callbacks if you like.
Put the network code in your second Fragment's onResume()
#Override
public void onResume() {
super.onResume();
final ProgressDialog loading = ProgressDialog.show(getContext(), "Fetching Data", "Please wait...", false, false);
(and the rest is the Retrofit code)
}