如何在Android中使用MutableLiveData更新仅更改的项目?

多里安·帕维蒂奇(DorianPavetić):

我使用ViewPager2和Tabs嵌套了片段,并使用将数据加载到RecyclerView其中MutableLiveData一切正常,直到我在Firebase实时数据库上更新了某些内容(例如某些食品的名称)。因此,如果我有10个类别项,每个类别有5种食物,并且我更新了1种食物的名称,那么我的屏幕闪烁和10个新类别就被添加了,每个类别有5种食物,现在我共有20个类别

所需的行为是:更新数据,没有屏幕闪烁,仅更新更改的项目,而无需再次添加所有类别和食物列表

那么我如何才能实现MutableLiveData更新刚刚更改的项目,而不是整个列表?

视图模型

public class MenuViewModel extends ViewModel implements 
    ICategoryCallbackListener, IFoodCallbackListener {

private MutableLiveData<String> messageError = new MutableLiveData<>();
private MutableLiveData<List<CategoryModel>> categoryListMutable;
private ICategoryCallbackListener categoryCallbackListener;
private MutableLiveData<List<FoodModel>> foodListMutable;
private IFoodCallbackListener foodCallbackListener;

public MenuViewModel() {
    categoryCallbackListener = this;
    foodCallbackListener = this;
}

public MutableLiveData<List<CategoryModel>> getCategoryListMutable() {
    if(categoryListMutable == null)
    {
        categoryListMutable = new MutableLiveData<>();
        messageError = new MutableLiveData<>();
        loadCategories();
    }
    return categoryListMutable;
}

public MutableLiveData<List<FoodModel>> getFoodListMutable(String key) {
    if(foodListMutable == null)
    {
        foodListMutable = new MutableLiveData<>();
        messageError = new MutableLiveData<>();
        loadFood(key);
    }
    return foodListMutable;
}

public void loadCategories() {
    List<CategoryModel> tempList = new ArrayList<>();

    DatabaseReference categoryRef = FirebaseDatabase.getInstance()
            .getReference(Common.RESTAURANT_REF)
            .child(Common.currentRestaurant.getUid())
            .child(Common.CATEGORY_REF);
    categoryRef.keepSynced(true);

    categoryRef.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot snapshot) {
            for(DataSnapshot itemSnapShot: snapshot.getChildren())
            {
                CategoryModel categoryModel=itemSnapShot.getValue(CategoryModel.class);
                if(categoryModel != null)
                    categoryModel.setMenu_id(itemSnapShot.getKey());
                tempList.add(categoryModel);
            }
            categoryCallbackListener.onCategoryLoadSuccess(tempList);
        }

        @Override
        public void onCancelled(@NonNull DatabaseError error) {
            categoryCallbackListener.onCategoryLoadFailed(error.getMessage());
        }
    });
}

public void loadFood(String key) {
    List<FoodModel> tempList = new ArrayList<>();

    DatabaseReference foodRef = FirebaseDatabase.getInstance()
            .getReference(Common.RESTAURANT_REF)
            .child(Common.currentRestaurant.getUid())
            .child(Common.CATEGORY_REF)
            .child(key)
            .child(Common.FOOD_REF);
    foodRef.keepSynced(true);

    foodRef.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot snapshot) {
            for(DataSnapshot itemSnapShot: snapshot.getChildren())
            {
                FoodModel foodModel = itemSnapShot.getValue(FoodModel.class);
                tempList.add(foodModel);
            }
            foodCallbackListener.onFoodLoadSuccess(tempList);
        }

        @Override
        public void onCancelled(@NonNull DatabaseError error) {
            foodCallbackListener.onFoodLoadFailed(error.getMessage());
        }
    });
}

public MutableLiveData<String> getMessageError() {
    return messageError;
}

@Override
public void onCategoryLoadSuccess(List<CategoryModel> categoryModels) {
    categoryListMutable.setValue(categoryModels);
}

@Override
public void onCategoryLoadFailed(String message) {
    messageError.setValue(message);
}

@Override
public void onFoodLoadSuccess(List<FoodModel> foodModels) {
    foodListMutable.setValue(foodModels);
}

@Override
public void onFoodLoadFailed(String message) {
    messageError.setValue(message);
}

菜单片段

    public class MenuFragment extends Fragment {

    public static final String ARG_MENU = "menu";
    private MenuViewModel menuViewModel;
    //Irrelevant code
    MyFoodListAdapter adapter;

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        menuViewModel = new ViewModelProvider(this).get(MenuViewModel.class);
        View root = inflater.inflate(R.layout.fragment_menu, container, false);
        //Irrelevant code
        return root;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {

        Bundle args = getArguments();
        menuViewModel.getFoodListMutable(Objects.requireNonNull(args)
            .getString(ARG_MENU))
            .observe(getViewLifecycleOwner(), foodModels -> {
                  adapter = new MyFoodListAdapter(getContext(), foodModels);
                   recycler_menu.setAdapter(adapter);
            });
    }
}

分类模型

public class CategoryModel {
private String menu_id, name, image, background;
private Long numberOfOrders;
List<FoodModel> foods;//Setters and Getters}
弗兰克·范普菲伦:

如果将附加ValueEventListener到某个位置,则每次对其下的任何内容进行修改时,都会调用该位置的所有数据的快照作为调用。

onDataChange可以将快照中的项目添加到tempList任何时候。因此,在初始加载时会添加10个类别。然后,当有更改时,它将再次添加它们,最终得到20个类别。

消除重复项的最简单方法是在将项目添加到列表之前清除列表:

categoryRef.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot snapshot) {
        tempList.clear();
        for(DataSnapshot itemSnapShot: snapshot.getChildren())
        {
            CategoryModel categoryModel=itemSnapShot.getValue(CategoryModel.class);
            if(categoryModel != null)
                categoryModel.setMenu_id(itemSnapShot.getKey());
            tempList.add(categoryModel);
        }
        categoryCallbackListener.onCategoryLoadSuccess(tempList);
    }

这样可以消除重复项,但是当您迫使Android重新绘制整个列表时,仍然可能会导致闪烁。如果您也想摆脱这种情况,请考虑使用addChildEventListener使用这种类型的侦听器,您会收到有关单个子节点的更改的通知,并可以使用该信息对进行最小的更新tempList,然后您还可以通过调用notifyItemChanged和类似方法告诉Android 执行该更新这几乎就是FirebaseUI中的适配器所做的。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在我的 xml 中使用 MutableLiveData 对象?

如何在android sqlite中使用列值更改来更新特定行

如何在android中使用“仅”设备GPS而不是AGPS?

如何在Android中使用按钮获取项目信息

如何在Android库项目中使用匕首

如何在Eclipse中使用android项目库?

如何在libgdx项目中使用android类?

如何在Android项目中使用@WorkerThread批注?

如何在Android Studio项目中使用最新的FFMPEG?

如何在android studio项目中使用Material Design

如何在android studio项目中使用Sketch设计

如何在Android中使用XMLPULLPARSER从XML获取项目?

如何在Android中使用onclick更改按钮?

如何在 Android 中使用动画更改操作栏的内容?

如何在运行时更改微调器的字符串数组如何在if语句中使用微调器的选定项目(eclipse中的Android)

如何在Android中使用PHP MYSQL更新数据

如何在Android中使用ASyncTask更新CustomAdapter

如何在Android中使用更新语句

如何在Android中使用sqlite获取更新的行数?

如何在MVC中使用SignalR仅更新特定页面的点赞计数

如何在Android主项目中包含库项目中使用的AAR文件

如何在 R 项目中使用 fviz_cluster 更改符号和颜色

Kotlin:如何在不使用getter和setter的情况下在ViewModel中更改MutableLiveData的值

如何在项目中使用Printf

如何在dynamodb中使用单个键值更新多个项目?

如何在Android Gradle项目中更改项目构建目标

如何在Android的轮播中使用ImageView的更改来更改TextView

如何在文本框中使用句柄更改事件来更新反应数组状态?

如何在角度5中使用异步更新输入更改中的数组?