Android NumberPicker внутри listView перестает прокручиваться при изменении набора данных
В моем приложении у меня есть listView с пользовательским макетом и пользовательским адаптером. Макет содержит textView и NumberPicker. Я хочу, чтобы numberPicker управлял значением моих данных, поэтому я хочу добавить к нему setOnValueChangedListener. Без прослушивателя это работает нормально - когда я прокручиваю numberPicker, прокручивают числа, и когда я прокручиваю вне его, он прокручивает представление списка, как показано в gif:
Однако, когда я присоединяю setOnValueChangedListener к NumberPicker, вещи ведут себя странно; При прокрутке через NumberPicker он застревает и вместо этого вызывает прокрутку самого макета:
(В gif я прокручиваю только numberPickers, однако он прокручивает listView и прекращает прокручивать numberPicker после изменения значения.)
После дальнейшего изучения выясняется, что именно notifyDataSetChanged() является причиной его возникновения, и отключение делает все нормально.
Что я думаю, так это то, что когда я прокручиваю numberPicker, слушатель запускает каждое измененное значение. Таким образом, после одного приращения он запускает и вызывает notifyDataSetChanged(), который каким-то образом сбрасывает представления и заставляет прокрутку останавливаться и переноситься в listView.
Вот весь соответствующий код:
Приложение (методы не имеют отношения к делу и используются, когда нажата одна из кнопок и создается диалоговое окно):
package com.chdev.mypianopractice;
import android.app.DialogFragment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import java.util.ArrayList;
public class EditPracticeActivity extends AppCompatActivity implements ChoosePracticeStageDialogFragment.PracticeStageDialogListener {
ArrayList<Practice.PracticeStage> practice;
ListView listView;
EditPracticeListViewAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_practice);
findViewById(R.id.practiceNameEditText).clearFocus();
practice = new ArrayList<>();
listView = findViewById(R.id.editPracticeListView);
listView.setAdapter(new EditPracticeListViewAdapter(this, practice));
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
((EditPracticeListViewAdapter) parent.getAdapter()).setClickedPosition(position);
}
});
adapter = (EditPracticeListViewAdapter) listView.getAdapter();
}
// Creates a dialog in order to add a new stage.
public void addStage(View view) {
DialogFragment fragment = new ChoosePracticeStageDialogFragment();
fragment.show(getFragmentManager(), "chooseStage");
}
// Used by the dialog when adding new stages to the practice.
@Override
public void onDialogOK(Practice.PracticeType typeChosen) {
String name = (typeChosen == null) ? "NULL" : getString(typeChosen.id);
if (typeChosen != null) {
practice.add(new Practice.PracticeStage(typeChosen, 30));
adapter.notifyDataSetChanged();
}
System.out.println("The chosen activity: " + name);
}
}
Пользовательский адаптер:
package com.chdev.mypianopractice;
import android.content.Context;
import android.graphics.Color;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.NumberPicker;
import android.widget.TextView;
import java.util.ArrayList;
/**
* The adapter for the listView in EditPracticeActivity, using the custom layout.
*/
public class EditPracticeListViewAdapter extends ArrayAdapter<Practice.PracticeStage> {
// Used for selecting items.
private int lastClickedStage;
public EditPracticeListViewAdapter(@NonNull Context context, ArrayList<Practice.PracticeStage> stages) {
super(context, R.layout.practice_stage_row, stages);
lastClickedStage = 0;
}
@NonNull
@Override
public View getView(final int position, @Nullable View convertView, @NonNull ViewGroup parent) {
View rowView = convertView;
if (rowView == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowView = inflater.inflate(R.layout.practice_stage_row, parent, false);
}
Practice.PracticeStage stage = getItem(position);
TextView text = rowView.findViewById(R.id.practiceStageNameTextView);
text.setText(stage.type.id);
NumberPicker picker = rowView.findViewById(R.id.practiceStageNumberPicker);
picker.setMinValue(0);
picker.setMaxValue(60*60);
picker.setValue(stage.time);
picker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker numberPicker, int oldVal, int newVal) {
getItem(position).time = newVal;
notifyDataSetChanged();
}
});
rowView.setBackgroundColor(position == lastClickedStage ? Color.LTGRAY : Color.WHITE);
return rowView;
}
// Used for selecting items.
public void setClickedPosition(int position) {
lastClickedStage = position;
notifyDataSetChanged();
}
}
Макет деятельности:
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="32dp"
android:text="@string/edit_practice_title"
android:textAlignment="center"
android:textSize="36sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/practiceNameEditText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:ems="10"
android:inputType="textPersonName"
android:text="@string/new_practice_default_text"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView4" />
<ListView
android:id="@+id/editPracticeListView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toTopOf="@+id/button3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/practiceNameEditText" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:layout_marginStart="32dp"
android:onClick="addStage"
android:text="@string/add_practice_stage_edit"
app:layout_constraintBottom_toTopOf="@+id/button5"
app:layout_constraintEnd_toStartOf="@+id/button4"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="32dp"
android:text="@string/remove_practice_stage_edit"
app:layout_constraintBaseline_toBaselineOf="@+id/button3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/button3" />
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginStart="24dp"
android:text="@string/save_practice_edit"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/button10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:text="@string/quit_practice_edit"
app:layout_constraintBaseline_toBaselineOf="@+id/button5"
app:layout_constraintEnd_toEndOf="parent" />
</android.support.constraint.ConstraintLayout>
Пользовательский макет, используемый в listView:
<TextView
android:id="@+id/practiceStageNameTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<NumberPicker
android:id="@+id/practiceStageNumberPicker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
Извините, это немного длинно. Буду очень признателен за вашу помощь, заранее спасибо!