所以我有一个适配器,该适配器保存着我要显示的对象列表。我将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);
}
}
答案 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