我有一个RecyclerView。每行都有一个播放按钮,textview和Progressbar。当点击播放按钮时必须播放我的SD卡中的音频并且必须进度Progressbar 问题是当我向下滚动recyclerview时,请更改下一行中的进度条。这意味着我可以同时在屏幕上显示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);
}}
答案 0 :(得分:155)
请试试这个
如果您使用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;
}
答案 1 :(得分:35)
在适配器构造函数中添加setHasStableIds(true);
并在适配器中覆盖这两个方法。
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return position;
}
答案 2 :(得分:25)
顾名思义,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);
答案 3 :(得分:2)
当我们动态更改RecyclerView
个项目时(即,更改特定RecyclerView
项目的背景颜色时),由于{ {1}}重用其项目。
但是要避免这种情况,可以使用RecyclerView
周围的android.support.v4.widget.NestedScrollView
并让RecyclerView
处理滚动。
NestedScrollView
然后在代码中,您可以为<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
禁用嵌套滚动,以仅允许RecyclerView
处理滚动来平滑滚动。
NestedScrollView
答案 4 :(得分:1)
将recylerView
放入NestedScroll View
的{{1}}中,并添加属性XML
。
然后在适配器nestedScrollingEnabled = false
上添加以下行
onBindViewHolder
将此final MyViewHolder viewHolder = (MyViewHolder)holder;
对象与您的视图一起用于viewHolder
或进行任何类型的点击事件。
例如setText
答案 5 :(得分:0)
我在处理大量数据时遇到了同样的问题,它与5一起工作,因为它渲染了屏幕上可见的五个元素,但这给了概念更多的元素。事情是......
有时,RecyclerView和listView只会跳过填充数据。如果在滚动时跳过了RecyclerView绑定功能,但是当您尝试调试recyclelerView适配器时,它将正常工作,因为它每次都会调用onBind,您还可以看到官方谷歌开发人员的视图The World of listView。大约20分钟-30分钟,他们将解释你永远不会假设每次都会调用getView的位置。
所以,我建议使用
RecyclerView DataBinder created by satorufujiwara.
或
RecyclerView MultipleViewTypes Binder created by yqritc.
如果你发现那些易于解决的问题,可以使用其他粘合剂。
这是处理MultipleView类型或使用大量数据的方法。这些粘合剂可以帮助您 只需仔细阅读文档即可修复它,和平!!
答案 6 :(得分:0)
此行在每个绑定上将进度更改为0
myViewHolder.progressplay.setProgress(0);
将其状态保存在某处,然后将其加载到同一行。
答案 7 :(得分:0)
为什么不尝试这样做,
HashMap<String, Integer> progressHashMap = new HashMap<>();
//...
if(!progressHashMap.containsKey(downloadpath)){
progressHashMap.put(downloadpath, mPlayer.getCurrentPosition());
}
progressbar.setProgress(progressHashMap.get(downloadpath));
答案 8 :(得分:0)
试试这个
@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 :(得分:0)
在尝试实现一个recyclerview时遇到了同样的问题,该视图包含一个edittex和一个复选框作为行元素。我只是通过在适配器类中添加以下两行来解决滚动值更改问题。
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return position;
}
我希望这将是一个可能的解决方案。谢谢
答案 10 :(得分:0)
覆盖适配器中的方法 getItemViewType 。在Kotlin中使用
override fun getItemViewType(position: Int): Int {
return position
}
答案 11 :(得分:0)
如果您的recyclerview ViewHolder具有更多逻辑或具有不同的其他视图,则应尝试:
ORDER BY DOCID,
DOC_VERSION DESC,
DATE_LOG,
DECODE(EVENT_DESC,'Document Submitted for Deployment',1,
'Document Deployed',2,
3) -- added this
其中x是列表的大小。以上对我有用,我希望对您也有用。
答案 12 :(得分:-2)
这是recyclerView的预期行为。由于视图已被回收,因此您的商品可能会进入随机视图。要解决这个问题,您必须自己指定将哪个项目放入哪种视图中。此信息可以保存在SparseBooleanArray中。你可以做的是在你的适配器中像这样
创建一个SparseBooleanArraySparseBooleanArray 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中的任何类似问题。
答案 13 :(得分:-2)
我遇到了类似的问题,并大量搜索了正确的答案。基本上,这是回收站视图的一种设计,它可以更新滚动视图,因为它可以刷新视图。
因此,您要做的就是在绑定时告诉它不要刷新它。
这就是您的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);
}