如何使Livedata不更新整个列表

时间:2019-02-24 16:32:58

标签: android android-livedata

所以我有一个适配器,该适配器保存着我要显示的对象列表。我将MVVP方法与android体系结构框架一起使用的LiveData和ViewModel一起使用。

在我的片段中,我将实时数据连接到适配器:

    viewModel.getAlarms().observe(this, alarms -> {
        Timber.d("Updating alarm list");
        alarmAdapter.updateAlarms(alarms);
    });

然后在我的适配器中,更新列表...

    void updateAlarms(List<Alarm> alarms){
        this.alarms = alarms;
        notifyDataSetChanged();
    }

因此,即使我对列表中的单个项目进行了很小的更改(项目更新,项目创建,项目删除..),整个列表也会更新。那弄乱了我所有的动画。有办法防止这种情况吗?

我不想复制所有内容,但是根据要求,这是更大的图片: 片段:

 @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        viewModel = ViewModelProviders.of(this, factory).get(HomeViewModel.class);

        // Get everything..
        viewModel.getAlarms().observe(this, alarms -> {
            Timber.d("Updating alarm list");
            alarmAdapter.updateAlarms(alarms);
        });
    }

    @OnClick(R.id.home_fbtn_add_alarm)
    void addAlarm(){
        viewModel.createAlarm(new Alarm(13,39));
    }

    private void onAlarmStatusChanged(int alarmId, boolean isActive){
        // TODO Make it so it doesn't update the whole list...
        viewModel.setAlarmStatus(alarmId, isActive);
    }

    private void onAlarmDeleted(int alarmId){
        this.showSnackbar(String.format("Alarm %s deleted", alarmId), clContainer);
        viewModel.deleteAlarm(alarmId);
    }

适配器:

class AlarmsAdapter extends RecyclerView.Adapter<AlarmsAdapter.AlarmHolder> {

private List<Alarm> alarms;
private BiConsumer<Integer, Boolean> onStatusChange;
private Consumer<Integer> onDelete;

AlarmsAdapter(BiConsumer<Integer, Boolean> onStatusChange, Consumer<Integer> onDelete) {
    this.alarms = new ArrayList<>();
    this.onStatusChange = onStatusChange;
    this.onDelete = onDelete;
}

void updateAlarms(List<Alarm> alarms){
    this.alarms = alarms;
    notifyDataSetChanged();
}

@NonNull
@Override
public AlarmHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    Context parentContext = parent.getContext();
    int alarmLayoutId = R.layout.item_alarm;
    View view = LayoutInflater.from(parentContext).inflate(alarmLayoutId, parent, false);

    return new AlarmHolder(view);
}

@Override
public void onBindViewHolder(@NonNull AlarmHolder alarmViewHolder, int position) {
    Alarm alarm = alarms.get(position);
    alarmViewHolder.setAlarm(alarm);
}

@Override
public int getItemCount() {
    return alarms == null ? 0 : alarms.size();
}

class AlarmHolder extends RecyclerView.ViewHolder {

    @BindView(R.id.item_alarm_tv_time)
    TextView tvTime;

    @BindView(R.id.item_alarm_tv_repeat)
    TextView tvRepeat;

    @BindView(R.id.item_alarm_tv_punishments)
    TextView tvPunishment;

    @BindView(R.id.item_alarm_swt_active)
    Switch swtActive;

    @BindView(R.id.item_alarm_img_delete)
    ImageView imgDelete;

    @BindView(R.id.item_alarm_foreground)
    ConstraintLayout foreground;

    @BindView(R.id.item_alarm_background)
    RelativeLayout background;

    AlarmHolder(@NonNull View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);
    }

    void setAlarm(Alarm alarm){
        Timber.i("Setting alarm: %s", this.getAdapterPosition());
        boolean isActive = alarm.getActive();
        tvTime.setText(alarm.getTime());
        tvRepeat.setText(alarm.getRepetitionDays());
        tvPunishment.setText(alarm.getPunishments());
        swtActive.setChecked(isActive);
    }

    private void setStatus(boolean isActive) {
        AlphaAnimation animation;
        if(!isActive){
            animation = new AlphaAnimation(1.0f, 0.3f);

        } else {
            animation = new AlphaAnimation(0.3f, 1f);
        }
        animation.setDuration(300);
        animation.setFillAfter(true);
        this.itemView.startAnimation(animation);
        // TODO Make it so it doesn't update the whole list...

    }

    @OnCheckedChanged(R.id.item_alarm_swt_active)
    void onStatusClick(boolean checked) {
        onStatusChange.accept(getAdapterPosition(), checked);
        setStatus(checked);
    }

    @OnClick(R.id.item_alarm_img_delete)
    void onDeleteClick() {
        onDelete.accept(getAdapterPosition());
    }
}}

还有LiveData:

public class HomeViewModel extends ViewModel {

private final AlarmRepository alarmRepository;
private LiveData<List<Alarm>> alarms;

public HomeViewModel(AlarmRepository alarmRepository) {
    this.alarmRepository = alarmRepository;
}

/**
 * Gets the Alarms' Observable...
 * @return Alarms' observable
 */
LiveData<List<Alarm>> getAlarms() {
    Timber.d("Fetching alarms..");
    if(alarms == null) {
        Timber.i("No alarms are cached. Going to DB!");
        alarms = alarmRepository.getAllAlarms();
    }
    return alarms;
}

/**
 * Deletes the selected
 * @param alarmPosition alarm to be deleted
 */
void deleteAlarm(int alarmPosition) {
    Timber.d("Deleting alarm %d", alarmPosition);

    getAlarmAtPosition(alarmPosition)
            .ifPresent(alarmRepository::deleteAlarm);
}

/**
 * Changes the status of the selected alarm
 * @param alarmPosition The selected alarm
 * @param status The new status
 */
void setAlarmStatus(int alarmPosition, boolean status){
    Timber.d("Alarm: %d is changing active status to %s", alarmPosition, status);

    getAlarmAtPosition(alarmPosition)
            .ifPresent(alarm -> alarmRepository.updateStatus(alarm, status));
}


/**
 * Gets the alarm at the selected position.
 * @param position The position of the alarm
 * @return The alarm of the selected position. Else returns empty.
 */
private Optional<Alarm> getAlarmAtPosition(int position){

    Optional<List<Alarm>> alarms =
            Optional.ofNullable(this.alarms)
                    .map(LiveData::getValue);

    if(!alarms.isPresent()) {
        return Optional.empty();
    }

    try {
        return Optional.of(alarms.get().get(position));
    } catch (Exception e){
        Timber.e(e, "Could not get alarm at position: %d", position);
        return Optional.empty();
    }
}


/**
 * Creates a new alarm. If null, does nothing.
 * @param alarm The alarm to be saved in the DB
 */
void createAlarm(Alarm alarm) {
    Timber.d("Adding new alarm.");
    if(alarm == null) {
        Timber.w("Cannot save null alarm");
        return;
    }

    alarmRepository.createAlarm(alarm);
}

}

1 个答案:

答案 0 :(得分:1)

我建议使用ListAdapter(属于recyclerView库的一部分)

By path2 = By.xpath("//android.widget.ImageView[@index='3']"); 
driver.findElement(path2).click(); 
Thread.sleep(5000);

将此传递给class AlarmsAdapter extends ListAdapter<Alarm , AlarmsAdapter.AlarmHolder> { public AlarmsAdapter( @NonNull ItemCallback<Feed> diffCallback) { super(diffCallback); }..... }

AlarmsAdapter