首页 > 解决方案 > 删除项目时 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>

标签: androidandroid-recyclerviewgoogle-cloud-firestore

解决方案


问题似乎出在适配器的 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 );

推荐阅读