android - Recyclerview 在仅添加一项时添加多项
问题描述
首先,我研究了与我讨论类似问题的现有问题。这个答案主要是我遇到的问题的壁橱-> Link。我没有看到任何适合我的问题的解决方案。
我在我的 HomeFragment 和 HomeListAdapter 的代码下方附上了。我已经做了一些研究,因为有人说我不应该在 bindviewholder 中调用 firebase 数据库,但是我正在关注 Firebase 快速启动数据库示例,所以如果有任何 firebase android 工程师可以给我一些指导,那就太好了。
当我在我的编辑配方片段上单击添加时。上传完成后,它会转到主片段。我的困惑是我在应用程序中拥有的所有其他适配器都具有正确的行为。它只添加一个配方(一次只添加一个是预期的行为)。
首页片段
package com.irondigitalmedia.keep;
import java.util.ArrayList;
public class HomeFragment extends BaseFragment {
private static final String TAG = HomeFragment.class.getSimpleName();
private ArrayList<Recipe> mRecipeList;
private ArrayList<String> mRecipeIds;
private RecyclerView HomeRecyclerView;
private HomeListAdapter adapter;
private LinearLayoutManager LLM;
private Context mContext;
private FirebaseDatabase database;
private DatabaseReference myRef;
private Recipe mRecipe;
private User mUser;
private int likeCounter = 0;
private MainActivity mainActivity;
private BaseActivity baseActivity;
private Toolbar toolbar;
private ProgressBar progressBar;
public HomeFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_home,container,false);
mContext = view.getContext();
mRecipeList = new ArrayList<>();
mRecipeIds = new ArrayList<>();
HomeRecyclerView = view.findViewById(R.id.frag_search_rv);
HomeRecyclerView.addItemDecoration(new SpacesItemDecoration(8));
LLM = new LinearLayoutManager(getContext());
HomeRecyclerView.setLayoutManager(LLM);
adapter = new HomeListAdapter(mContext, mRecipeList, mUser);
HomeRecyclerView.setAdapter(adapter);
mainActivity = (MainActivity) view.getContext();
mainActivity.mMainNav.setSelectedItemId(R.id.nav_home);
toolbar = mainActivity.findViewById(R.id.main_toolbar);
toolbar.setTitle("Home");
mainActivity.setSupportActionBar(toolbar);
if(savedInstanceState != null){
Log.e(TAG, "onCreateView: savedInstanceState is null");
}else{
LoadRecipes();
}
return view;
}
private void LoadRecipes() {
database = FirebaseDatabase.getInstance();
myRef = database.getReference();
myRef.child(Constants.DATABASE_ROOT_FOLLOWING).child(getUid()).addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
String key = dataSnapshot.getKey();
Log.i(TAG, "onChildAdded: key is = " + key);
if(key!=null){
Log.i(TAG, "onChildAdded: key is not null ");
myRef.child(Constants.DATABASE_ROOT_USERS_RECIPES).child(key).limitToFirst(5).addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
// A new comment has been added, add it to the displayed list
mRecipe = dataSnapshot.getValue(Recipe.class);
// [START_EXCLUDE]
// Update RecyclerView
mRecipeIds.add(dataSnapshot.getKey());
mRecipeList.add(mRecipe);
adapter.notifyItemInserted(mRecipeList.size() - 1);
// [END_EXCLUDE]
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());
// A comment has changed, use the key to determine if we are displaying this
// comment and if so displayed the changed comment.
mRecipe = dataSnapshot.getValue(Recipe.class);
String recipeKey = dataSnapshot.getKey();
// [START_EXCLUDE]
int commentIndex = mRecipeIds.indexOf(recipeKey);
if (commentIndex > -1) {
// Replace with the new data
mRecipeList.set(commentIndex, mRecipe);
// Update the RecyclerView
adapter.notifyItemChanged(commentIndex);
} else {
Log.w(TAG, "onChildChanged:unknown_child:" + recipeKey);
}
// [END_EXCLUDE]
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());
// A comment has changed, use the key to determine if we are displaying this
// comment and if so remove it.
String recipeKey = dataSnapshot.getKey();
// [START_EXCLUDE]
int commentIndex = mRecipeIds.indexOf(recipeKey);
if (commentIndex > -1) {
// Remove data from the list
mRecipeIds.remove(commentIndex);
mRecipeList.remove(commentIndex);
// Update the RecyclerView
adapter.notifyItemRemoved(commentIndex);
} else {
Log.w(TAG, "onChildRemoved:unknown_child:" + recipeKey);
}
// [END_EXCLUDE]
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());
// A comment has changed position, use the key to determine if we are
// displaying this comment and if so move it.
mRecipe = dataSnapshot.getValue(Recipe.class);
String recipeKey = dataSnapshot.getKey();
// ...
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "recipes:onCancelled", databaseError.toException());
Toast.makeText(mContext, "Failed to load recipes.",
Toast.LENGTH_SHORT).show();
}
});
}else{
Log.e(TAG, "onChildAdded: Key is null");
}
}
@Override
public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
}
@Override
public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelableArrayList(Constants.SAVED_STATE_HOME,mRecipeList);
}
@Override
public void onStart() {
super.onStart();
getActivity().setTitle("Home");
}
public String getUid() {
return FirebaseAuth.getInstance().getCurrentUser().getUid();
}
}
主列表适配器
package com.irondigitalmedia.keep.Adapters;
public class HomeListAdapter extends RecyclerView.Adapter<HomeListAdapter.ViewHolder> {
private static final String TAG = HomeListAdapter.class.getSimpleName();
private DatabaseReference mDatabase;
private Context context;
private List<Recipe> mRecipesList;
private MainActivity mainActivity;
private User user;
private int likeCounter = 0;
public HomeListAdapter(Context context, List<Recipe> mRecipesList, User user) {
this.context = context;
this.mRecipesList = mRecipesList;
this.user = user;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_recipes_recipe_item, parent, false);
mDatabase = FirebaseDatabase.getInstance().getReference();
mainActivity = (MainActivity) view.getContext();
return new HomeListAdapter.ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
final Recipe recipe = mRecipesList.get(position);
SetUserData(holder, position);
holder.tv_recipe_title.setText(mRecipesList.get(position).getTitle());
holder.tv_recipe_prepTime.setText(mRecipesList.get(position).getPrepTime());
Glide.with(context).load(mRecipesList.get(position).getUrl())
.placeholder(R.drawable.ic_loading).thumbnail(0.05f).fitCenter()
.transition(DrawableTransitionOptions.withCrossFade()).centerCrop()
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
.into(holder.recipe_thumbnail);
Log.i(TAG, "onBindViewHolder: Database Reference = " +
mDatabase.child(Constants.DATABASE_ROOT_RECIPES).child(recipe.getUid()).child(Constants.DATABASE_ROOT_LIKES));
mDatabase.child(Constants.DATABASE_ROOT_RECIPES).child(recipe.getUid())
.child(Constants.DATABASE_ROOT_LIKES).addValueEventListener(new ValueEventListener() {
@SuppressLint("SetTextI18n")
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
likeCounter = (int) dataSnapshot.getChildrenCount();
Log.i(TAG, "onDataChange: ChildrenCount = " + recipe.getTitle() + " " + likeCounter);
holder.tv_like_counter.setText(Integer.toString(likeCounter));
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
mDatabase.child(Constants.DATABASE_ROOT_RECIPES).child(recipe.getUid())
.child(Constants.DATABASE_ROOT_LIKES).addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
if(dataSnapshot.hasChild(getUid())){
holder.like.setLiked(true);
Log.i(TAG, "onDataChange: LIKED RECIPE...");
}else{
Log.i(TAG, "onDataChange: RECIPE IS NOT LIKED...");
holder.like.setLiked(false);
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
mDatabase.child(Constants.DATABASE_ROOT_RECIPES).child(recipe.getUid())
.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
if(dataSnapshot.hasChild(Constants.DATABASE_RECIPE_LIKE_COUNT_VALUE)){
holder.tv_like_counter.setText(String.valueOf(dataSnapshot.child(Constants.DATABASE_RECIPE_LIKE_COUNT_VALUE).getValue()));
}else{
// likes do not exist
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
holder.like.setOnLikeListener(new OnLikeListener() {
@Override
public void liked(LikeButton likeButton) {
Log.i(TAG, "liked: LIKED");
// Add like
holder.like.setLiked(true);
mDatabase.child(Constants.DATABASE_ROOT_RECIPES).child(recipe.getUid()).child(Constants.DATABASE_ROOT_LIKES).child(getUid()).setValue("true");
}
@Override
public void unLiked(LikeButton likeButton) {
Log.i(TAG, "unLiked: UNLIKED");
// remove Like
holder.like.setLiked(false);
mDatabase.child(Constants.DATABASE_ROOT_RECIPES).child(recipe.getUid()).child(Constants.DATABASE_ROOT_LIKES).child(getUid()).removeValue();
}
});
}
private void SetUserData(ViewHolder holder, int position) {
mDatabase.child(Constants.DATABASE_ROOT_USERS).child(mRecipesList.get(position).getCreatorId())
.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
holder.tv_user_username.setText(user.getUsername());
Glide.with(context).load(user.getUrl()).centerCrop().placeholder(R.drawable.ic_loading).into(holder.userPhoto);
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}
@Override
public int getItemCount() {
return mRecipesList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView tv_recipe_title, tv_recipe_prepTime, tv_user_username, tv_like_counter;
public ImageView recipe_thumbnail;
public LikeButton like;
public CircleImageView userPhoto;
public LinearLayout user_ll;
public FirebaseAuth mAuth;
public FirebaseDatabase mDatabase;
public ViewHolder(@NonNull View itemView) {
super(itemView);
mainActivity = (MainActivity) itemView.getContext();
mDatabase = FirebaseDatabase.getInstance();
tv_recipe_title = itemView.findViewById(R.id.recipe_item_title);
tv_recipe_prepTime = itemView.findViewById(R.id.recipe_item_time);
recipe_thumbnail = itemView.findViewById(R.id.recipe_item_photo);
like = itemView.findViewById(R.id.recipe_item_image_like);
tv_like_counter = itemView.findViewById(R.id.recipe_item_like_counter);
userPhoto = itemView.findViewById(R.id.recipe_item_user_photo);
tv_user_username = itemView.findViewById(R.id.recipe_item_user_username);
user_ll = itemView.findViewById(R.id.recipe_item_user_linearLayout);
user_ll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ProfileFragment pf = new ProfileFragment();
if(pf.isAdded()){
return;
}else{
Bundle bundle = new Bundle();
bundle.putString(Constants.EXTRA_USER_UID,mRecipesList.get(getAdapterPosition()).getCreatorId());
Log.i(TAG, "onClick: Fragment Interaction recipe Creator Id = " + mRecipesList.get(getAdapterPosition()).getCreatorId());
FragmentTransaction ft = mainActivity.getSupportFragmentManager().beginTransaction();
pf.setArguments(bundle);
ft.replace(R.id.main_frame, pf, Constants.FRAGMENT_TAG_PROFILE);
ft.addToBackStack(Constants.FRAGMENT_TAG_PROFILE);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
}
});
itemView.setOnClickListener(v -> {
RecipeDetailsFragment rd = new RecipeDetailsFragment();
if(rd.isAdded()){
return;
}else{
Bundle bundle = new Bundle();
bundle.putString(Constants.EXTRA_RECIPE_KEY,mRecipesList.get(getAdapterPosition()).getUid());
bundle.putString(Constants.EXTRA_RECIPE_CREATOR_ID, mRecipesList.get(getAdapterPosition()).getCreatorId());
Log.i(TAG, "onClick: Fragment Interaction recipe Key is = " + mRecipesList.get(getAdapterPosition()).getUid());
FragmentTransaction ft = mainActivity.getSupportFragmentManager().beginTransaction();
rd.setArguments(bundle);
ft.replace(R.id.main_frame, rd, Constants.FRAGMENT_TAG_RECIPE_DETAILS);
ft.addToBackStack(null);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
});
}
}
public String getUid() {
return FirebaseAuth.getInstance().getCurrentUser().getUid();
}
}
编辑配方片段
package com.irondigitalmedia.keep.Adapters;
public class EditIngredientAdapter extends RecyclerView.Adapter<EditIngredientAdapter.IngredientViewHolder> {
private static final String TAG = EditIngredientAdapter.class.getSimpleName();
private String dataSnapShotKey;
private Context mContext;
private DatabaseReference mDatabaseReference;
private ChildEventListener mChildEventListener;
public List<String> mIngredientIds = new ArrayList<>();
public List<Ingredient> mIngredients = new ArrayList<>();
public EditIngredientAdapter(final Context mContext, DatabaseReference ref) {
this.mContext = mContext;
this.mDatabaseReference = ref;
// Create child event listener
// [START child_event_listener_recycler]
ChildEventListener childEventListener = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
dataSnapShotKey = dataSnapshot.getKey();
// A new comment has been added, add it to the displayed list
Ingredient ingredient = dataSnapshot.getValue(Ingredient.class);
// [START_EXCLUDE]
// Update RecyclerView
mIngredientIds.add(dataSnapshot.getKey());
mIngredients.add(ingredient);
notifyItemInserted(mIngredients.size() - 1);
// [END_EXCLUDE]
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());
// A comment has changed, use the key to determine if we are displaying this
// comment and if so displayed the changed comment.
Ingredient newIngredient = dataSnapshot.getValue(Ingredient.class);
String ingredientKey = dataSnapshot.getKey();
// [START_EXCLUDE]
int ingredientIndex = mIngredientIds.indexOf(ingredientKey);
if (ingredientIndex > -1) {
// Replace with the new data
mIngredients.set(ingredientIndex, newIngredient);
// Update the RecyclerView
notifyItemChanged(ingredientIndex);
} else {
Log.w(TAG, "onChildChanged:unknown_child:" + ingredientKey);
}
// [END_EXCLUDE]
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());
// A comment has changed, use the key to determine if we are displaying this
// comment and if so remove it.
String ingredientKey = dataSnapshot.getKey();
// [START_EXCLUDE]
int ingredientIndex = mIngredientIds.indexOf(ingredientKey);
if (ingredientIndex > -1) {
// Remove data from the list
mIngredientIds.remove(ingredientIndex);
mIngredients.remove(ingredientIndex);
// Update the RecyclerView
notifyItemRemoved(ingredientIndex);
} else {
Log.w(TAG, "onChildRemoved:unknown_child:" + ingredientKey);
}
// [END_EXCLUDE]
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());
// A comment has changed position, use the key to determine if we are
// displaying this comment and if so move it.
Ingredient movedIngredient = dataSnapshot.getValue(Ingredient.class);
String ingredientKey = dataSnapshot.getKey();
// ...
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "postComments:onCancelled", databaseError.toException());
Toast.makeText(mContext, "Failed to load comments.",
Toast.LENGTH_SHORT).show();
}
};
ref.addChildEventListener(childEventListener);
// [END child_event_listener_recycler]
// Store reference to listener so it can be removed on app stop
mChildEventListener = childEventListener;
}
@NonNull
@Override
public IngredientViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.list_item_recipe_ingredient, parent, false);
return new IngredientViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull IngredientViewHolder holder, int position) {
Ingredient ingredient = mIngredients.get(position);
holder.ingred.setText(ingredient.ingredient);
}
@Override
public int getItemCount() {
return mIngredients.size();
}
public class IngredientViewHolder extends RecyclerView.ViewHolder {
public TextView ingred;
public IngredientViewHolder(View itemView) {
super(itemView);
ingred = itemView.findViewById(R.id.recipe_ingredients_tv);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext, "Ingredient: " + mIngredients.get(getAdapterPosition()).ingredient, Toast.LENGTH_SHORT).show();
}
});
itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Toast.makeText(mContext, "Long Clicked " + getAdapterPosition(), Toast.LENGTH_SHORT).show();
return true;
}
});
}
}
public void RemoveIngredient(DatabaseReference reference){
reference.removeValue();
}
public void cleanupListener() {
if (mChildEventListener != null) {
mDatabaseReference.removeEventListener(mChildEventListener);
}
}
}
截图:
转到搜索并返回首页
回到家
Majuran 尝试了解决方案(谢谢),但没有奏效。结果相同。将 list.clear() 方法添加到两个列表时。
解决方案
据我了解,您认为又添加了一件事。当您回到同一个片段时,对吗?(我在上一个项目中遇到了同样的问题)
问题出在 HomeFragment 中。在您的这些列表中再次添加相同的值。
mRecipeList = new ArrayList<>();
mRecipeIds = new ArrayList<>();
在添加侦听器之前清除它
myRef = database.getReference();
mRecipeList.clear();
mRecipeIds.clear();
myRef.child(Constants.DATABASE_ROOT_FOLLOWING).child(getUid()).add...
希望它有帮助,快乐编码!
推荐阅读
- batch-file - 这个批处理文件如何结束自己的进程?
- c++ - 'std::wstring_convert' 尽可能多地转换(来自 UTF8 文件读取块)
- wordpress - Wordpress 钩子在调用之前触发,而不是在调用之后触发
- html - 背景图像不时更改时的文本可见性问题
- javascript - 使用水线的model.create/createEach时如何查找未插入/跳过的行
- android - FileProvider:安装 APK。解析包时出错
- python - 如何在 matplotlib 中反转条形图上的刻度顺序?
- python - Django - 从 TemplateResponse 获取 URL
- excel - 列出具有特定字符串的工作表名称
- lua - 停止时玩家面向错误的方向