android - 删除项目时 RecyclerView 显示不稳定。Android Studio 和云 Firestore
问题描述
我在回收站视图的卡片视图中放置了一个删除项目按钮。当我按下删除时,该项目似乎会短暂地重新创建它,然后消失。但是,当单击然后返回到 recyclerView 活动时,该项目已在视图中重新创建自己,但不是在数据库中。我认为问题必须在 deleteButton onClickListener 中,但我似乎无法找到问题的解决方案......任何建议都会很棒。我已经包含了回收器适配器代码和显示 cardView 的活动代码。还有xml,以防它与可以在那里设置的onClick方法有关。
UserMenuListAdapter.java
import static com.melcolton.bite.UsersMenuActivity.finalId;
public class UserMenuListAdapter extends RecyclerView.Adapter<UserMenuListAdapter.ViewHolder> implements View.OnClickListener {
private static final String TAG = "Adapter Log";
private View.OnClickListener myClickListener;
private FirebaseFirestore fbFirestore;
private FirebaseAuth fbAuth;
public String fbUserId;
public List<UserMenu> userMenu;
public Context context;
public UserMenuListAdapter(Context context, List<UserMenu> userMenu, View.OnClickListener myClickListener) {
this.myClickListener = myClickListener;
this.userMenu = userMenu ;
this.context = context;
}
@NonNull
@Override
public UserMenuListAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Context context = parent.getContext();
View menuView = LayoutInflater.from( context ).inflate( R.layout.item_confirm_list_element, parent, false );
return new ViewHolder( menuView, myClickListener );
}
@Override
public void onBindViewHolder(@NonNull UserMenuListAdapter.ViewHolder holder, int position) {
fbAuth = FirebaseAuth.getInstance();
fbFirestore = FirebaseFirestore.getInstance();
fbUserId = fbAuth.getCurrentUser().getUid();
if (holder instanceof ViewHolder) {
ViewHolder viewHolder = holder;
holder.userMenuName.setText( userMenu.get( position ).getItemName() );
holder.userMenuDesc.setText( userMenu.get( position ).getItemDesc() );
holder.userMenuCals.setText( userMenu.get( position ).getItemCals().toString() );
holder.userMenuCost.setText( userMenu.get( position ).getItemCost().toString() );
holder.deleteButton.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText( context, "Removed", Toast.LENGTH_SHORT ).show();
fbFirestore.collection( "AppUsers" ).document(fbUserId).collection( "UserMenu" ).document(finalId)
.delete().addOnSuccessListener( new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
userMenu.remove( position );
notifyItemRemoved( position );
notifyItemRangeChanged( position, userMenu.size() );
notifyDataSetChanged();
//holder.menuView.setVisibility( View.GONE );
}
} );
}
});
}
}
@Override
public int getItemCount() {
return userMenu.size();
}
public void onEvent (QuerySnapshot queryDocumentSnapshots, FirebaseFirestoreException e) {
if (e !=null) {
Log.w( TAG, "onEvent error: ",e );
onError (e);
}
}
private void onError(FirebaseFirestoreException e) {
Log.w( TAG, "onEvent error: ",e );
}
@Override
public void onClick(View v) {
}
public class ViewHolder extends RecyclerView.ViewHolder {
public CardView userMenuCardView;
public TextView userMenuName;
public TextView userMenuDesc;
public TextView userMenuCals;
public TextView userMenuCost;
public Button deleteButton;
View menuView;
public ViewHolder(View itemView, View.OnClickListener myClickListener) {
super( itemView );
itemView.setOnClickListener( myClickListener );
menuView = itemView;
userMenuCardView = menuView.findViewById( R.id.user_menu_cardview );
userMenuName = menuView.findViewById( R.id.txt_cart_item_name );
userMenuDesc = menuView.findViewById( R.id.txt_cart_item_desc );
userMenuCals = menuView.findViewById( R.id.txt_cart_item_cals );
userMenuCost = menuView.findViewById( R.id.txt_cart_item_cost );
deleteButton = menuView.findViewById( R.id.remove_button );
}
}
}
用户菜单活动.java
import static com.melcolton.bite.ChooseRestaurant.valFromAct1;
public class UsersMenuActivity extends AppCompatActivity {
private static final String TAG = "UserMenuActivity";
public static String finalId;
public Context umContext;
public Button myButton;
public static int totalCalsSet;
public static double totalCostSet;
public TextView caloriesUsed;
public String toCalsUsed;
Toolbar menuToolbar;
private FirebaseFirestore umFirestore;
private FirebaseAuth umFirebaseAuth;
private FirebaseAuth mAuth;
private RecyclerView umRecyclerView;
private List<UserMenu> userMenu;
private View.OnClickListener umClickListener;
private UserMenuListAdapter userMenuListAdapter;
private String getUserId;
private TextView passedCalContent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_users_menu );
menuToolbar = findViewById( R.id.menu_toolbar );
setSupportActionBar( menuToolbar );
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled( false );
getSupportActionBar().setDisplayShowHomeEnabled( false );
}
myButton = findViewById( R.id.remove_button );
caloriesUsed = findViewById( R.id.users_menu_calories_used );
toCalsUsed = Integer.toString( totalCalsSet );
caloriesUsed.setText( toCalsUsed );
userMenu = new ArrayList<>();
userMenuListAdapter = new UserMenuListAdapter( getApplicationContext(), userMenu, umClickListener );
umRecyclerView = (RecyclerView) findViewById( R.id.user_menu_recycler_view );
umRecyclerView.setHasFixedSize( true );
umRecyclerView.setLayoutManager( new LinearLayoutManager( this ) );
umRecyclerView.setAdapter( userMenuListAdapter );
passedCalContent = findViewById( R.id.users_menu_calories_set );
passedCalContent.setText( valFromAct1 );
umFirestore = FirebaseFirestore.getInstance();
umFirebaseAuth = FirebaseAuth.getInstance();
getUserId = Objects.requireNonNull( umFirebaseAuth.getCurrentUser() ).getUid();
CollectionReference userMenuRef = umFirestore.collection( "AppUsers" )
.document( getUserId )
.collection( "UserMenu" );
userMenuRef.limit( 100 ).addSnapshotListener( (documentSnapshots, e) -> {
if (e != null) {
Log.d( TAG, "Error: " + e.getMessage() );
}
assert documentSnapshots != null;
for (DocumentChange doc : Objects.requireNonNull( documentSnapshots ).getDocumentChanges()) {
UserMenu menu = doc.getDocument().toObject( UserMenu.class ).withId( doc.getDocument().getId() );
Log.d( TAG, doc.getDocument().getId() + " => " + doc.getDocument() );
finalId = doc.getDocument().getId();
userMenu.add( menu );
userMenuListAdapter.notifyDataSetChanged();
}
} );
//Method here to calculate the total cals value to show in header.
userMenuRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
int totalCals = 0;
for (QueryDocumentSnapshot document : task.getResult()) {
double itemCals = document.getDouble("itemCals");
totalCals = (int) (totalCals + itemCals);
}
Log.d("TAG", String.valueOf(totalCals));
totalCalsSet = totalCals;
}
}
});
//Calculates the total cost of the menu.
userMenuRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
double totalCost = 0;
for (QueryDocumentSnapshot document : task.getResult()) {
double itemCost = document.getDouble("itemCost");
totalCost = totalCost + itemCost;
}
Log.d("TAG", String.valueOf(totalCost));
totalCostSet = totalCost;
}
}
});
}
//ACTION BAR
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate( R.menu.main_menu, menu );
return true;
}
@Override
public boolean onOptionsItemSelected(android.view.MenuItem item) {
switch (item.getItemId()) {
case R.id.action_logout_button:
logout();
return true;
case R.id.action_settings_button:
Intent settingsIntent = new Intent( UsersMenuActivity.this, AccSetupActivity.class );
startActivity( settingsIntent );
return true;
case R.id.about_info:
Intent aboutIntent = new Intent( UsersMenuActivity.this, DisclaimerActivity.class );
startActivity( aboutIntent );
return true;
default:
return false;
}
}
private void sendToLogin() {
Intent loginIntent = new Intent( UsersMenuActivity.this, LogInActivity.class );
startActivity( loginIntent );
}
private void logout() {
mAuth.signOut();
sendToLogin();
finish();
}
}
布局文件
<android.support.v7.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/food_constraint_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:layout_gravity="center"
android:clickable="true"
android:focusable="true"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:id="@+id/user_menu_cardview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="8dp"
app:cardBackgroundColor="@color/cardview_light_background"
app:cardCornerRadius="4dp">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/txt_cart_item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:fontFamily="sans-serif-condensed"
android:text="title of item"
android:textAllCaps="true"
android:textColor="@android:color/black"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/txt_cart_item_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@+id/txt_cart_item_name"
android:layout_marginEnd="8dp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:paddingEnd="16dp"
android:text="Description"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/txt_cart_item_name" />
<TextView
android:id="@+id/calories_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/txt_cart_item_desc"
android:layout_marginStart="16dp"
android:layout_marginTop="20dp"
android:text="Calories"
android:textSize="12sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/devider" />
<TextView
android:id="@+id/cost_text"
android:layout_width="wrap_content"
android:layout_height="19dp"
android:layout_below="@+id/txt_cart_item_desc"
android:layout_marginStart="38dp"
android:layout_toStartOf="@+id/txt_cart_item_cost"
android:text="Cost £"
android:textSize="12sp"
app:layout_constraintBaseline_toBaselineOf="@+id/txt_cart_item_cals"
app:layout_constraintStart_toEndOf="@+id/txt_cart_item_cals" />
<TextView
android:id="@+id/txt_cart_item_cals"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignEnd="@+id/txt_cart_item_name"
android:layout_below="@+id/txt_cart_item_desc"
android:layout_marginStart="8dp"
android:paddingBottom="8dp"
android:text="100"
android:textColor="@color/biteBlue"
android:textSize="26sp"
app:layout_constraintBaseline_toBaselineOf="@+id/calories_text"
app:layout_constraintStart_toEndOf="@+id/calories_text" />
<TextView
android:id="@+id/txt_cart_item_cost"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/calories_text"
android:layout_alignParentEnd="true"
android:layout_marginStart="4dp"
android:text="4.99"
android:textColor="@android:color/black"
app:layout_constraintBaseline_toBaselineOf="@+id/cost_text"
app:layout_constraintStart_toEndOf="@+id/cost_text" />
<TextView
android:id="@+id/devider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignBottom="@+id/txt_cart_item_cals"
android:layout_marginTop="8dp"
android:background="@color/biteBlue"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/txt_cart_item_desc" />
<Button
android:id="@+id/remove_button"
android:layout_width="32dp"
android:layout_height="31dp"
android:layout_below="@+id/devider"
android:layout_marginEnd="8dp"
android:layout_marginTop="18dp"
android:background="@drawable/ic_delete_black_24dp"
android:backgroundTint="@color/cardview_dark_background"
android:fontFamily="sans-serif-condensed"
android:textColor="@color/biteBlue"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/txt_cart_item_desc" />
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
</android.support.v7.widget.LinearLayoutCompat>
解决方案
问题似乎出在适配器的 onCreate 方法中。将演员表移除到 UserMenuListAdapter 并简单地让 ViewHolder onCreate... 已经停止了这个问题。
@NonNull
@Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Context context = parent.getContext();
View menuView = LayoutInflater.from( context ).inflate( R.layout.item_confirm_list_element, parent, false );
return new ViewHolder( menuView, myClickListener );
推荐阅读
- java - 如何将 QueueLinearFloodFiller 算法应用于 android App
- r - 申请结果不一致
- c++ - 将返回值从函数存储到 const ref
- objective-c - 当 Objc-C 桥接到 Swift 时如何查看方法签名,反之亦然?
- python - 将日期时间转换为纪元时出错,增加 5 秒,然后转换回日期时间
- corda - 如何解决单元测试“LinearState”的普通实现时抛出的“NotSerializableException”
- c# - 是否可以制作一个采用 Dictionary 的方法
>? - r - 实施严格的重载方法签名以防止误用
- reactjs - 从 Redux 迁移到 React Context API + hooks 时如何处理副作用
- jquery - 在数据表列复选框下拉列表中使用可选择的 jQuery