Firebase recycleradapter displaying wrong information Android

我只是一个虾纸丫 提交于 2019-12-24 21:05:48

问题


My app uses a firebase RecyclerAdapter to display "plant" entities in an activity. I made it so that if I longclick on an entity displayed in Cardview format using a ViewHolder and the RecyclerAdapter it will prompt to perform a delete and delete the plant entity + image on the firebase database and storage. Deleting and adding plants work without a hitch on the backend as I can confirm this on my firebase database.

However, when I delete a "plant" entity and add a new one, the CardView shows the previous or another image. Deleting the app and reinstalling it seems to fix the problem, because of this I think it might have to do with the local cache.

  • PlantActivity.java (where the plants are loaded) I think this might be solved if there was some way to refresh the activity in some way or the RecyclerAdapter... although i've tried many things already

public class PlantActivity extends AppCompatActivity {

private static final int ADD_REQUEST = 101;
private static final String TAG = "PlantActivityView";
private DatabaseReference mDatabaseReference;
private FirebaseRecyclerAdapter plantAdapter;
private PlantDAO mPlantDAO;
private UserDAO mUserDAO;
private CoordinatorLayout coordinatorLayout;

@Override
protected void onStart() {
    super.onStart();
    if(!mUserDAO.isLoggedIn()){
        finish();
        startActivity(new Intent(PlantActivity.this, LoginActivity.class));
    }
    plantAdapter.startListening();
}
@Override
protected void onStop() {
    super.onStop();
    plantAdapter.stopListening();
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_plant_view);

    FirebaseDatabase.getInstance().setPersistenceEnabled(true);
    mDatabaseReference = FirebaseDatabase.getInstance().getReference();
    mPlantDAO = new PlantDAO(mDatabaseReference);
    mUserDAO = new UserDAO();

    //make custom appcompat toolbar to replace actionbar and add logout item
    Toolbar toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    coordinatorLayout = findViewById(R.id.plant_coordinator);
    providePlantsOfCurrentUser();

    findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(getApplicationContext(),PlantAddActivity.class);
            startActivityForResult(intent, ADD_REQUEST);
        }
    });
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu, menu);
    return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()){
        case R.id.menuLogout:
            mUserDAO.getAuth().signOut();
            finish();
            startActivity(new Intent(PlantActivity.this,LoginActivity.class));
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    Snackbar GoodResultSnackbar = Snackbar.make(coordinatorLayout,"PLANT ADDED",Snackbar.LENGTH_SHORT);
    Snackbar BadResultSnackbar = Snackbar.make(coordinatorLayout,"PLANT ADD FAILED",Snackbar.LENGTH_SHORT);
    if(requestCode == ADD_REQUEST){
        if(resultCode == Activity.RESULT_OK){
           GoodResultSnackbar.show();
        } else if(resultCode == Activity.RESULT_CANCELED){
            BadResultSnackbar.show();
        }
    }
    super.onActivityResult(requestCode, resultCode, data);
}


public void providePlantsOfCurrentUser(){
    FirebaseRecyclerOptions<Plant> options = new FirebaseRecyclerOptions.Builder<Plant>().setQuery(mPlantDAO.currentUserPlantsQuery(), Plant.class).build();
    plantAdapter = new FirebaseRecyclerAdapter<Plant,PlantViewHolder>(options) {
        @NonNull
        @Override
        public PlantViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.cardview_item_plant, parent, false);
            return new PlantViewHolder(view);
        }

        @Override
        protected void onBindViewHolder(@NonNull final PlantViewHolder holder, final int position, @NonNull final Plant model) {
            StorageReference localstorage = FirebaseStorage.getInstance().getReferenceFromUrl(model.getImageLocation());
            String plantText = /*model.getPlantID() + ": " + */ model.getPlanttype();

            holder.tv_plant_name.setText(plantText);
            //image implementation
            GlideApp.with(getApplicationContext()).load(localstorage).into(holder.img_plant_thumbnail);

            holder.dialogClickListener = new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    switch (which){
                        case DialogInterface.BUTTON_POSITIVE:
                            mPlantDAO.deletePlant(model.getPlantID());
                            plantAdapter.notifyDataSetChanged();
                            break;

                        case DialogInterface.BUTTON_NEGATIVE:
                            //Return
                            break;
                    }
                }
            };

            holder.cardView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //passing data with intent to PlantDetailActivity instance
                    Intent intent = new Intent(getApplicationContext(), PlantDetailActivity.class);
                    intent.putExtra("plantID", model.getPlantID());
                    intent.putExtra("planttype", model.getPlanttype());
                    //image implementation
                    intent.putExtra("image_url", model.getImageLocation());
                    //start the activity
                    startActivity(intent);

                }
            });
            holder.cardView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                   showDeleteDialog(holder);
                    return true;
                }
            });
        }
    };
    RecyclerView recyclerView = findViewById(R.id.recyclerview_id);
    recyclerView.setAdapter(plantAdapter);
    recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
}

private void showDeleteDialog(PlantViewHolder holder){
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setMessage("Delete this plant?").setPositiveButton("Yes", holder.dialogClickListener)
            .setNegativeButton("Cancel", holder.dialogClickListener).show();
}

}


回答1:


The position and model are final on the onBindViewHolder method

The viewholder can be final, but not the data or the position

Use holder.getAdapterPosition() to get the position inside annonymous interfaces like click listeners

And then get the data using getItem() method from the adapter class




回答2:


The last answer by @cutiko definitely helped! But I think I realize the problem. I was saving my plantID string attribute (of new Plant object) in this fashion: "plant_" + count() of "plants" in database + "_" + ID of the current user + ".jpg"

The problem this causes is that when I delete a plant entity and add another this could cause 2 plant entities in the database to have the same ID which causes strange behavior.

I will solve this by instead of deleting a plant from the database, changing a new attribute's("active") to false and not showing these in the FirebaseRecyclerAdapter



来源:https://stackoverflow.com/questions/53837296/firebase-recycleradapter-displaying-wrong-information-android

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!