Recyclerview Изменение элементов во время прокрутки
У меня есть RecyclerView. В каждой строке есть кнопка воспроизведения, текстовое изображение и Progressbar. при нажатии на кнопку воспроизведения необходимо воспроизвести звук с моей SD-карты и выполнить прогресс.
Проблема заключается в том, что когда я прокручиваю изменения recycliewiew, Progress Progress в следующей строке. Я могу сразу поместить 5 элементов на экран. Когда я перехожу к 6-му, 6-я строка поиска меняется внезапно.
public class ListAdapter extends RecyclerView.Adapter {
private List<Historyitem> stethitems;
public Context mContext;
public Activity activity;
public Handler mHandler;
static MediaPlayer mPlayer;
static Timer mTimer;
public ListAdapter(Activity activity,Context mContext,List<Historyitem> stethitems) {
this.stethitems = stethitems;
this.mContext = mContext;
this.activity = activity;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View rootView = LayoutInflater.
from(mContext).inflate(R.layout.stethoscopeadapteritem, null, false);
RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
rootView.setLayoutParams(lp);
mHandler = new Handler();
return new MyViewHolder(rootView);
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, int position) {
final Historyitem dataItem = stethitems.get(position);
final MyViewHolder myViewHolder = (MyViewHolder) viewHolder;
myViewHolder.progressplay.setProgress(0);
myViewHolder.stethdatetime.setText(dataItem.getReported_Time());
myViewHolder.stethhosname.setText(dataItem.getdiv());
if(dataItem.getPatient_Attribute().replaceAll(" ","").equals("")){
myViewHolder.stethdoctorname.setText(dataItem.getunit());
} else {
myViewHolder.stethdoctorname.setText(dataItem.getPatient_Attribute());
}
myViewHolder.stethstreamplay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
FileDownload(dataItem.getmsg(),
myViewHolder.progressplay);
}
});
}
@Override
public int getItemCount() {
return stethitems.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
final CustomTextRegular stethdatetime;
final CustomTextView stethhosname;
final CustomTextBold stethdoctorname;
final ImageButton stethstreamplay;
final NumberProgressBar progressplay;
public MyViewHolder(View itemView) {
super(itemView);
stethdatetime = (CustomTextRegular)
itemView.findViewById(R.id.stethdatetime);
stethhosname = (CustomTextView)
itemView.findViewById(R.id.stethhosname);
stethdoctorname = (CustomTextBold)
itemView.findViewById(R.id.stethdoctorname);
stethstreamplay = (ImageButton)
itemView.findViewById(R.id.stethstreamplay);
progressplay= (NumberProgressBar)
itemView.findViewById(R.id.progressplay);
}
}
public void FileDownload(final String downloadpath,
final NumberProgressBar progressplay) {
new AsyncTask<NumberProgressBar, Integer, NumberProgressBar>() {
NumberProgressBar progress;
@Override
protected void onPreExecute() {
super.onPreExecute();
try {
if(mPlayer!=null){
mPlayer.stop();
}
}catch (Exception e){
}
try {
if(mTimer != null){
mTimer.purge();
mTimer.cancel();
}
}catch (Exception e){
}
}
@Override
protected NumberProgressBar doInBackground(NumberProgressBar... params) {
int count;
progress = progressplay;
try {
final List<NameValuePair> list = new ArrayList<NameValuePair>();
list.add(new BasicNameValuePair("pid",id));
URL url = new URL(Config.requestfiledownload + "?path=" +
downloadpath);
URLConnection connection = url.openConnection();
connection.connect();
int lenghtOfFile = connection.getContentLength();
// download the file
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(Environment.getExternalStorageDirectory() +
"record.wav");
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
// publishing the progress....
publishProgress((int) (total * 100 / lenghtOfFile));
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
} catch (Exception e) {
}
return progress;
}
@Override
protected void onPostExecute(final NumberProgressBar numberProgressBar) {
super.onPostExecute(numberProgressBar);
try {
StartMediaPlayer(numberProgressBar);
} catch (Exception e){
e.printStackTrace();
}
}
}.execute();
}
public void StartMediaPlayer(final NumberProgressBar progressbar){
Uri playuri = Uri.parse("file:///sdcard/record.wav");
mPlayer = new MediaPlayer();
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mPlayer.reset();
try {
mPlayer.setDataSource(mContext, playuri);
} catch (IllegalArgumentException e) {
} catch (SecurityException e) {
} catch (IllegalStateException e) {
} catch (Exception e) {
}
try {
mPlayer.prepare();
} catch (Exception e) {
}
mPlayer.start();
progressbar.setMax(mPlayer.getDuration());
mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
if(mPlayer!=null) {
mPlayer.release();
progressbar.setProgress(0);
}
if(mTimer != null){
mTimer.purge();
mTimer.cancel();
}
}
});
mTimer = new Timer();
mTimer.schedule(new TimerTask() {
@Override
public void run() {
mHandler.post(new Runnable() {
@Override
public void run() {
progressbar.setProgress(mPlayer.getCurrentPosition());
}
});
}
},0,500);
}}
Ответы
Ответ 1
Пожалуйста, попробуйте
-
Если вы используете ListView
- переопределите следующие методы.
@Override
public int getViewTypeCount() {
return getCount();
}
@Override
public int getItemViewType(int position) {
return position;
}
-
Если вы используете метод RecycyclerView
- переопределить только getItemViewType()
.
@Override
public int getItemViewType(int position) {
return position;
}
Ответ 2
Добавьте setHasStableIds(true);
в свой конструктор адаптера и переопределите эти два метода в адаптере.
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return position;
}
Ответ 3
Как следует из названия, представления в RecyclerView
перерабатываются при прокрутке вниз. Это означает, что вам нужно сохранить состояние каждого элемента в вашей модели подкачки, что в данном случае будет Historyitem
, и восстановить его в onBindViewHolder
.
1) Создайте позицию, максимум и любые другие переменные, необходимые для сохранения состояния ProgressBar
в вашей модели.
2) Задайте состояние вашего ProgressBar
на основе данных в вашей модели подкачки; по щелчку, передайте позицию элемента своим методам FileDownload
/StartMediaPlayer
.
public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, int position) {
final Historyitem dataItem = stethitems.get(position);
final MyViewHolder myViewHolder = (MyViewHolder) viewHolder;
myViewHolder.progressplay.setMax(dataItem.getMax());
myViewHolder.progressplay.setProgress(dataItem.getPosition());
...
myViewHolder.stethstreamplay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
FileDownload(dataItem.getmsg(), position);
}
});
3) Обновите индикатор выполнения, обновив модель поддержки и сообщив, что она была изменена.
stethitems.get(position).setPosition(mPlayer.getCurrentPosition());
notifyItemChanged(position);
Ответ 4
Поместите recylerView
в представление NestedScroll View
в XML
и добавьте свойство nestedScrollingEnabled = false
.
А на вашем адаптере на onBindViewHolder
добавьте эту строку
final MyViewHolder viewHolder = (MyViewHolder)holder;
Используйте этот объект viewHolder
с вашими представлениями, чтобы установить setText
или сделать любой вид событий щелчка.
например, viewHolder.txtSubject.setText("Example");
Ответ 5
У меня была такая же проблема при обработке большого количества данных, она работает с 5, потому что она отображает пять элементов, которые видны на экране, но это дает проблему с большим количеством элементов. Дело в том, что..
Иногда RecyclerView и listView просто пропускают Populating Data. В случае, если функция привязки RecyclerView пропускается во время прокрутки, но при попытке и отладке адаптера recyclerView она будет работать нормально, поскольку она будет вызывать onBind каждый раз, вы также можете увидеть официальный просмотр разработчика google Мир listView. Примерно через 20 минут -30 минут они объяснят, что вы никогда не сможете предположить, что getView по позиции будет вызываться каждый раз.
поэтому я предлагаю использовать
RecyclerView DataBinder, созданный satorufujiwara.
или
RecyclerView MultipleViewTypes Binder, созданный yqritc.
Это другие привязки, доступные, если вы обнаружите, что их легко обойти.
Это способ иметь дело с типами MultipleView или если вы используете большой объем данных. Эти связующие могут помочь вам
просто внимательно прочитайте документацию, чтобы исправить это, мир!
Ответ 6
Эта строка меняет прогресс до 0 на каждой привязке
myViewHolder.progressplay.setProgress(0);
Сохраните его состояние где-нибудь, затем загрузите его в эту же строку.
Ответ 7
Почему бы вам не попробовать,
HashMap<String, Integer> progressHashMap = new HashMap<>();
//...
if(!progressHashMap.containsKey(downloadpath)){
progressHashMap.put(downloadpath, mPlayer.getCurrentPosition());
}
progressbar.setProgress(progressHashMap.get(downloadpath));
Ответ 8
попробуйте это
@Override public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
int position) { LinearSmoothScroller linearSmoothScroller =
new LinearSmoothScroller(recyclerView.getContext()) {
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return LinearLayoutManager.this
.computeScrollVectorForPosition(targetPosition);
}
}; linearSmoothScroller.setTargetPosition(position); startSmoothScroll(linearSmoothScroller); }
см. это также
Ответ 9
Я сталкивался с той же проблемой, когда пытался реализовать представление переработчика, которое содержит edittex и флажок в качестве элементов строки. Я решил проблему изменения значения прокрутки, просто добавив следующие две строки в класс адаптера.
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return position;
}
Я надеюсь, что это будет возможным решением. Спасибо
Ответ 10
Это ожидаемое поведение recyclerView. Поскольку представление переработано, ваши объекты могут попадать в случайные представления. Чтобы преодолеть это, вы должны указать, какой элемент будет помещен в какой-то вид. Эта информация может храниться в SparseBooleanArray. что вы можете сделать, это создать в вашем адаптере SparseBooleanArray, как этот
SparseBooleanArray selectedItems = new SparseBooleanArray();
всякий раз, когда ваш вид изменяется, выполните:
selectedItems.put(viewItemIndex,true);
Теперь в вашем onBindViewHolder выполните
if(selectedItems.get(position, false)){
//set progress bar of related to the view to desired position
}
else {
//do the default
}
Это основной способ решить вашу проблему. Вы можете настроить эту логику на любую аналогичную проблему в recyclerView.
Ответ 11
У меня была похожая проблема, и я много раз искал правильный ответ. По сути, это скорее дизайн представления переработчика, который обновляет представление на свитке, потому что обновляет представление.
Так что все, что вам нужно сделать, это в обязательное время сказать, чтобы оно не обновлялось.
Вот так должен выглядеть ваш onBindViewHolder
@Override
@SuppressWarnings("unchecked")
public void onBindViewHolder(final BaseViewHolder holder, final int position) {
holder.bind(mList.get(position));
// This is the mighty fix of the issue i was having
// where recycler view was updating the items on scroll.
holder.setIsRecyclable(false);
}