Android RecyclerView only displays items after closing and restarting the app - java

I have a strange effect with my RecyclerView after I updated my App to API 28. I have a search button that triggers a search of Wifi devices in my area. The items are no longer displayed directly in the list. I have to close and reopen the app to get the correct display.
I have a toast that should be displayed when the button is pressed. The toast message is also only displayed after closing and opening the app.
Activity.kt
private fun setFloatingSearchButton() {
floating_button_discover_devices.setOnClickListener { view ->
Snackbar.make(view, "Search for new devices ...",
Snackbar.LENGTH_SHORT).setAction("Action", null).show()
discoverDevices()
registerReceiver(mWifiReceiver, IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION))
mWifiManager!!.startScan()
}
}
WifiAdapter.java
public class WifiAdapter extends RecyclerView.Adapter<WifiAdapter.ViewHolder> {
private final int CONFIGURE_DEVICE_REQUEST_CODE = 0x00000001;
private static final String TAG = "WifiAdapter";
private List<DeviceWifiTo> wifis;
private Context context;
private Activity activity;
public WifiAdapter(List<DeviceWifiTo> wifis) {
this.wifis = wifis;
}
#Override
public WifiAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
context = parent.getContext();
activity = (Activity) context;
LayoutInflater inflater = LayoutInflater.from(context);
View wifiView = inflater.inflate(R.layout.item_wifi, parent, false);
return new WifiAdapter.ViewHolder(wifiView);
}
#Override
public void onBindViewHolder(WifiAdapter.ViewHolder holder, int position) {
DeviceWifiTo wifi = wifis.get(position);
Log.d(TAG, wifi.getSsid());
TextView wifiName = holder.wifiName;
wifiName.setText(wifi.getSsid());
CardView cardView = holder.cardView;
cardView.setOnClickListener(view -> {
Intent intent = new Intent(context, ConfigureDeviceActivity.class);
intent.putExtra("ssid", wifi.getSsid());
activity.startActivityForResult(intent, CONFIGURE_DEVICE_REQUEST_CODE);
});
}
#Override
public int getItemCount() {
return wifis.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
TextView wifiName;
CardView cardView;
ViewHolder(View itemView) {
super(itemView);
wifiName = itemView.findViewById(R.id.text_wifi_name);
cardView = itemView.findViewById(R.id.cardView_device);
}
}
}
UcDiscoverDevicesImpl.java
private void createRecyclerView(List<DeviceWifiTo> list) {
RecyclerView recyclerView = activity.findViewById(R.id.recycler_view_wifi);
WifiAdapter adapter = new WifiAdapter(list);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(activity.getApplicationContext()));
}

Set layout manager before set adapter to recycler view, Update like below
private void createRecyclerView(List<DeviceWifiTo> list) {
RecyclerView recyclerView = activity.findViewById(R.id.recycler_view_wifi);
recyclerView.setLayoutManager(new LinearLayoutManager(activity.getApplicationContext()));
WifiAdapter adapter = new WifiAdapter(list);
recyclerView.setAdapter(adapter);
}
Hope it helps you.

I guess you want to show your result in recyclerView. Do you have any callback methods for Your search?
You need to call notifyDataSetChanged() in that callback method (set result then call notifyDataSetChanged() )

Try setting up layoutmanager before setting the adapter

I had similar issue in kotlin just because of not adding the notifyDataSetChanged() where I am setting the data.

Related

RecyclerView Error No adapter attached ; skipping layout and setting OnClickListener

I'm working on an application where I store the data on Firebase and retrieve it after the user manages to sign in. The application works fine I see this error occurs.
E/RecyclerView: No adapter attached; skipping layout
I'm loading an image together with long and short description. I'm trying to take the users into another Activity where they can the content more detailed. However. I am confused where I can set OnClickListener so that I can take the id of this post and load it in another activity.
this is the main activity :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
homeAuth = FirebaseAuth.getInstance();
recyclerView = findViewById(R.id.recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
layoutManager.setStackFromEnd(true);
layoutManager.setReverseLayout(true); // this will load it from the end and show last as first
progressDialog = new ProgressDialog(this);
recyclerView.setLayoutManager(layoutManager);
postModelList = new ArrayList<>();
pullPosts();
}
and this is the method where I pull the data from the DB :
void pullPosts() {
progressDialog.setMessage("Please wait for the pictures to load...");
progressDialog.show();
progressDialog.setCancelable(false);
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("Posts");
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
postModelList.clear();
for (DataSnapshot ds : dataSnapshot.getChildren()){
postModel = ds.getValue(PostModel.class);
postModelList.add(postModel);
postAdapter = new PostAdapter(HomeActivity.this , postModelList);
recyclerView.setAdapter(postAdapter);
}
progressDialog.dismiss();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
progressDialog.dismiss();
Toast.makeText(HomeActivity.this, ""+databaseError, Toast.LENGTH_SHORT).show();
}
});
}
I read other posts related to that error tried the options but the rest seems to me fine as the following is my Adapter :
public class PostAdapter extends RecyclerView.Adapter<PostAdapter.MyHolder> {
Context context;
List<PostModel> postModelList;
public PostAdapter(Context context, List<PostModel> postModelList) {
this.context = context;
this.postModelList = postModelList;
}
#NonNull
#Override
public MyHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.home_post, parent, false);
return new MyHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MyHolder holder, int position) {
String title = postModelList.get(position).getPostTitle();
String sDescription = postModelList.get(position).getPostShDescription();
String lDescription = postModelList.get(position).getPostLoDescription();
String image = postModelList.get(position).getPostImage();
holder.pulledTitle.setText(title);
holder.pulledShortDescription.setText(sDescription);
holder.pulledLongDescription.setText(lDescription);
Glide.with(context).load(image).into(holder.pulledImage);
//now we will add library to load image
}
#Override
public int getItemCount() {
return postModelList.size();
}
class MyHolder extends RecyclerView.ViewHolder {
ImageView pulledImage;
TextView pulledTitle, pulledShortDescription, pulledLongDescription;
public MyHolder(#NonNull View itemView) {
super(itemView);
pulledImage = itemView.findViewById(R.id.pulled_image);
pulledTitle = itemView.findViewById(R.id.pulled_title);
pulledShortDescription = itemView.findViewById(R.id.pulled_short_description);
pulledLongDescription = itemView.findViewById(R.id.pulled_long_description);
}
}
}
Could you please help me with fixing the issue? I would appreciate your time and help.
E/RecyclerView: No adapter attached; skipping layout
that's not an error you can ignore it, it's happening because there's not adapter when the activity is created as you set the adapter after fetching the data.
About your question where to set onClickListener, you should do that in the adapter's viewHolder
class MyHolder extends RecyclerView.ViewHolder {
ImageView pulledImage;
TextView pulledTitle, pulledShortDescription, pulledLongDescription;
public MyHolder(#NonNull View itemView) {
super(itemView);
pulledImage = itemView.findViewById(R.id.pulled_image);
pulledTitle = itemView.findViewById(R.id.pulled_title);
pulledShortDescription = itemView.findViewById(R.id.pulled_short_description);
pulledLongDescription = itemView.findViewById(R.id.pulled_long_description);
itemView.setOnClickListner(v->{
//your implementation here f.e Id = postModelList.getId(); or and start another activity from here
});
}
}

You cannot start a load for a destroyed activity on using Recycle view with Glide

I"m using adapter to load images and text inside my fragment which is attached to Activity A. But when I close app and open the app then app crashes with error
You cannot start a load on a not yet attached View or a Fragment where getActivity() returns null (which usually occurs when getActivity() is called before the Fragment is attached or after the Fragment is destroyed)
But 2nd time when I open app, then it runs smoothly.
But if again I close app and reopen then app crashes with same error and Once error occurs and on second time it runs smoothly.
Here is my adapter classs. Home is my Fragment
public class TopAdapter extends RecyclerView.Adapter<TopAdapter.MyViewHolder> {
ArrayList<location> bookslist;
CardView cv;
FirebaseAuth fauth;
FirebaseDatabase database;
DatabaseReference dbreference;
location g;
private Home context;
public TopAdapter(Home context, ArrayList<location> bookslist){
this.bookslist = bookslist;
this.context = context; // add this as a field in your adapter class.
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_top,parent,false);
return new MyViewHolder(v);
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView teacher_name,teacher_location;
LinearLayout profile_details;
ImageView iv;
MyViewHolder(final View itemView) {
super(itemView);
cv = (CardView) itemView.findViewById(R.id.my_card_view);
iv = (ImageView) itemView.findViewById(R.id.placePic);
teacher_name= (TextView) itemView.findViewById(R.id.teacher_name);
teacher_location = (TextView) itemView.findViewById(R.id.teacher_location);
profile_details = (LinearLayout) itemView.findViewById(R.id.profile_details);
fauth = FirebaseAuth.getInstance();
}
}
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
database = FirebaseDatabase.getInstance();
g = bookslist.get(position);
holder.teacher_location.setText(g.getBlocas());
holder.teacher_name.setText(g.getSellername());
holder.profile_details.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
g = bookslist.get(position);
Intent intent = new Intent(v.getContext(), gender_details.class);
intent.putExtra(MOBILE, g.getSellermobile());
intent.putExtra(EMAIL, g.getSelleremail());
v.getContext().startActivity(intent);
}
});
if (getContext() != null) {
Glide.with(context).load(Uri.parse(g.getPics())).apply(RequestOptions.circleCropTransform().placeholder(R.drawable.bshelf).error(R.drawable.userphoto)).into(holder.iv);
}
#Override
public int getItemCount() {
return bookslist.size();
}
}
Use your Activity's Context to load images with Glide. Pass it via the constructor of your adapter like the following.
// Declare a Context variable in your adapter
private Context context;
public TopAdapter(ArrayList<location> bookslist, Context context){
this.bookslist = bookslist;
this.context = context; // add this as a field in your adapter class.
}
And then use glide with the activity context.
Glide.with(context).load(Uri.parse(g.getPics())).apply(RequestOptions.circleCropTransform().placeholder(R.drawable.bshelf).error(R.drawable.userphoto)).into(holder.iv);
Fragment's getActivity() is null because it not attached to your activity.
use isAdded() method to check your fragment is currently added to its activity.

How do i add the show more functionality to getting firebase database?

I am new in firebase android app development.
In this app i fetched the data from firebase database.
Here i want to implement show more functionality in recyclerview to save data loading.
I see the solution in many stackoverflow question. But in every question The adapter class is defined outside from main activity. so i cant understand properly.
And here my adapter is within main activty class.
class MainActivity extends AppCompatActivity {
private RecyclerView postList;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PostRef=FirebaseDatabase.getInstance().getReference().child("Posts");
postList = (RecyclerView) findViewById(R.id.all_user_post_list);
postList.setHasFixedSize(true);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setReverseLayout(true);
linearLayoutManager.setStackFromEnd(true);
postList.setLayoutManager(linearLayoutManager);
displayAllUserPost();
}
private void displayAllUserPost() {
Query sortPost=PostRef;
FirebaseRecyclerOptions<Post> options=new FirebaseRecyclerOptions.Builder<Post>().setQuery(sortPost,Post.class).build();
FirebaseRecyclerAdapter<Post, PostsViewHolder> firebaseRecyclerAdapter=new FirebaseRecyclerAdapter<Post, PostsViewHolder>(options)
#Override
protected void onBindViewHolder(#NonNull final PostsViewHolder holder, final int position, #NonNull final Post model) {
final String PostKey = getRef(position).getKey();
holder.postfullname.setText(model.getFirstname() + " " + model.getLastname());
}
#NonNull
#Override
public PostsViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType)
{
View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.all_post_layout,parent,false);
PostsViewHolder viewHolder=new PostsViewHolder(view);
return viewHolder;
}
}
}
public static class PostsViewHolder extends RecyclerView.ViewHolder
{
TextView postfullname;
public PostsViewHolder(View itemView)
{
super(itemView);
postfullname = itemView.findViewById(R.id.user_post_full_name);
}
}
}
So How i add show more functionality in this code when first load only 10 items and than after load more 10 items with rounded progressbar(show more button is not important).
Most important thing is that first load only 10 items. rest item should not be loaded until user scrolled down to last(10th) item
Thank you.

RecyclerView is messed up when scrolling

As you can see in the screenshot, my project contains a RecyclerView (for categories of food) which contains more RecyclerViews (for the ingredients). But iv'e got a problem, my RecyclerView is messing up the order. I debuged the project and the parameters are just fine but the RecyclerView is displaying them wrong. As you can see in the picture, Fruits ingredients are displayed in the Dairy category.
IngredientSectionAdapter.Java
(the main adapter,which contain more RecyclerViews)
class SectionViewHolder extends RecyclerView.ViewHolder {
private TextView sectionBtn;
private RecyclerView itemRecyclerView;
public SectionViewHolder(View itemView) {
super(itemView);
sectionBtn = (TextView) itemView.findViewById(R.id.text_category);
itemRecyclerView = (RecyclerView) itemView.findViewById(R.id.ingredientsRecycler);
}
}
private Context context;
private ArrayList<IngredientSectionModel> sectionModelArrayList;
ArrayList<IngredientItemAdapter> adapters;
public IngredientSectionAdapter(Context context, ArrayList<IngredientSectionModel> sectionModelArrayList) {
this.context = context;
this.sectionModelArrayList = sectionModelArrayList;
adapters = new ArrayList<IngredientItemAdapter>();
}
#Override
public SectionViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(R.layout.parent_list,null);
return new SectionViewHolder(v);
}
#Override
public void onBindViewHolder(SectionViewHolder holder, int position) {
final IngredientSectionModel sectionModel = sectionModelArrayList.get(position);
holder.itemRecyclerView.setTag(holder.itemRecyclerView.getVisibility());
final RecyclerView sectionList = holder.itemRecyclerView;
holder.sectionBtn.setText(sectionModel.getSectionLabel());
//recycler view for items
holder.itemRecyclerView.setHasFixedSize(true);
holder.itemRecyclerView.setNestedScrollingEnabled(false);
/* set layout manager on basis of recyclerview enum type */
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(3,1);
adapters.add(new IngredientItemAdapter(context, sectionModel.getItemArrayList()));
int resId = R.anim.grid_layout_animation_from_bottom;
//LayoutAnimationController animation = AnimationUtils.loadLayoutAnimation(context, resId);
holder.itemRecyclerView.setLayoutManager(staggeredGridLayoutManager);
holder.itemRecyclerView.setAdapter(adapters.get(position));
//holder.itemRecyclerView.setLayoutAnimation(animation);
//toggle visibilty of inner RecyclerView (ingredients, not categories)
holder.sectionBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (sectionList.getVisibility() == View.VISIBLE){
sectionList.setVisibility(View.GONE);
}
else
{
sectionList.setVisibility(View.VISIBLE);
}
}
});
}
What can cause this?
Every time onBindViewHolder is called you create a new IngredientItemAdapter and add it to your adapters, and then you call holder.itemRecyclerView.setAdapter(adapters.get(position)). However, adapters.get(position) is not the adapter you just created. Your adapter will get bigger and bigger. Try this
IngredientItemAdapter adapter = adapters.get(position);
adapter.setIngredients(sectionModel.getItemArrayList());
holder.itemRecyclerView.setAdapter(adapter);

Integrating recyclerview with database

#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
Collections.swap(queuee, viewHolder.getAdapterPosition(), target.getAdapterPosition());
// and notify the adapter that its dataset has changed
adapterr.notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
With the above code i m able to swap the items in the recyclerview ,but now the problem is i also want to make the same respective changes to database.
How to go about?
queuee receives the all the data from the database
queuee is a arraylist which is used to set the recyclerview adapter
Regards
Thanks
Adapter:
public class QueueAdapter extends RecyclerView.Adapter<QueueAdapter.MyViewHolder> {
private Context mContext;
public ArrayList<Music> queue;
MediaPlayer mPlayer = new MediaPlayer();
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView title,tt,artist;
public Button play,stop;
public ImageButton option;
public MyViewHolder(View view) {
super(view);
title = (TextView) view.findViewById(R.id.songtitle1);
artist = (TextView)view.findViewById(R.id.artist1);
// play = (Button) view.findViewById(R.id.play);
// stop = (Button) view.findViewById(R.id.stop);
// tt = (TextView) view.findViewById(R.id.song_name);
option = (ImageButton) view.findViewById(R.id.option1);
}
}
public QueueAdapter(Context mContext, ArrayList<Music> queue) {
this.mContext = mContext;
this.queue = queue;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.queue_card, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
Music mu1 = queue.get(position);
holder.title.setText(mu1.getTitle());
holder.artist.setText(mu1.getArtist());
final String link =mu1.getUrl();
final String SongName = mu1.getTitle();
}
#Override
public int getItemCount() {
return queue.size();
}
public void removeItem(int position) {
queue.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, queue.size());
}
}
activity:
recyclerView = (RecyclerView) findViewById(R.id.recyclerqueue);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
adapterr = new QueueAdapter(this,queuee);
recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));
// adapterr.
recyclerView.setAdapter(adapterr);
initSwipe();
In my opinion, you can do it on OnDestroy method in your Activity. Specifically speaking, firstly, you can get all your data from your adapter, and then delete datas in your database, at last, you can save your data obtained from your adapter again. In this moment, the sequence of your datas is what you want, and this way is easy to code. I'd rather you don't
update your database during onMove, because it's too frequently during your drag, and operates all data is easier than two datas in database.

Categories

Resources