问题
I am using a recyclerview for displaying and broadcasting videos of users. However, when I scroll through the recycler view, I see my first view, which has my video gets recycled hence why it's not visible to other users. Is there a way I can make sure that the first view is not recycled so I dont have to worry about my video view getting resetrecycled every single time I scroll through my list?
Here's my code : In my fragment... ...
<android.support.v7.widget.RecyclerView
android:id="@+id/videoList"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="@+id/myButtonContainer"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/myoldContainer">
...
and the corresponding adapter...
public class GroupAdapter extends RecyclerView.Adapter<GroupAdapter.myViewHolder> {
private CopyOnWriteArrayList<Person> persons;
private Context mContext;
public GroupAdapter(@NonNull final CopyOnWriteArrayList<Person> persons , Context context) {
this.persons = persons;
this.mContext= context;
for (Person person : this.persons) {
//get names
}
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View layout = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_person, parent, false);
final MyViewHolder viewHolder = new MyViewHolder(layout);
return viewHolder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
final Person person = person.get(position);
final Participant participant = person.getParticipant();
if (person.getName() != null) {
holder.personName.setText(person.getName());
}
if (person.getImage() != null) {
holder.personImage.setImageBitmap(person.getImage());
} else {
holder.personImage.setImageResource(R.drawable.default_profile);
}
holder.personImage.setVisibility(View.INVISIBLE);
holder.personImage.setVisibility(View.VISIBLE);
final VideoView videoView;
if (participant.isMe) {
videoView = participant.videoStreamer.videoView;
} else {
videoView = participant.videoPlayer.videoView;
}
if (holder.personVideo.getChildCount() != 0) {
holder.personVideo.removeAllViews();
}
if (videoView.getParent() != null) {
ViewGroup parent = (ViewGroup) videoView.getParent();
parent.removeView(videoView);
}
holder.personVideo.addView(videoView, myViewHolder.videoLayoutParams);
if (person.isVideoPaused()) {
holder.personVideo.setVisibility(View.INVISIBLE);
holder.personImage.setVisibility(View.VISIBLE);
} else {
holder.personVideo.setVisibility(View.VISIBLE);
holder.personImage.setVisibility(View.INVISIBLE);
}
}
@Override
public int getItemCount() {
return persons.size();
}
public static final class MyViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.personVideo)
public ViewGroup personVideo;
@BindView(R.id.personImage)
public ImageView personImage;
@BindView(R.id.personName)
public TextView personName;
protected static FrameLayout.LayoutParams videoLayoutParams = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
);
public MyViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
Here's how I am setting it in my fragment:
LinearLayoutManager manager = new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);
videoAdapter = new VideoAdapter(myHelper.getPeople(), getContext());
videoList.setLayoutManager(manager);
videoList.setAdapter(videoAdapter);
item_person:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginTop="0dp"
android:background="@drawable/person_border"
xmlns:app="http://schemas.android.com/apk/res-auto">
<RelativeLayout
android:id="@+id/personContainer"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent">
<FrameLayout
android:id="@+id/personVideo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black" />
<ImageView
android:id="@+id/personImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
android:src="@drawable/default_profile" />
<TextView
android:id="@+id/personName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#AA555555"
android:gravity="center_horizontal|bottom"
android:textColor="@color/green"
android:textSize="12sp"
android:lines="1"
android:ellipsize="end"
tools:text="androiduser@gmail.com"
android:layout_alignParentBottom="true" />
</RelativeLayout>
</android.support.constraint.ConstraintLayout>
fragment with recycle view: xml
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<RelativeLayout>
....
</RelativeLayout>
<include containers>...</include>
...
<android.support.v7.widget.RecyclerView
android:id="@+id/personList"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="invisible"
>
</android.support.v7.widget.RecyclerView>
</android.support.constraint.ConstraintLayout>
回答1:
I don't think that "not recycling" the video view will actually stop it from being destroyed when you scroll. It's not the recycling is the problem but the view unbinding.
I think such complex component such as VideoView
should not be inside the RecyclerView
at all.. You can try adding it as a static content on top, which most likely will solve the issue. You can use a NestedScrollView
for that. Take a look here: Recyclerview inside scrollview- How to scroll whole content?
If you still think you want to keep it in the RecyclerView
and disable the recycling, do the following.
Create a separate view type for your video view items. Here is an example: https://stackoverflow.com/a/26573338/3086818. Treat your video view item as a header view from the example.
Once you do this, there is a RecycledViewPool
class which manages the recycling of items inside a RecyclerView
. You can tell it which views to recycle and which not. By default it recycles all views. To disable recycling for your video view items use your new view type like this:
recyclerView.getRecycledViewPool().setMaxRecycledViews(TYPE_VIDEO_VIEW, 0);
where TYPE_VIDEO_VIEW
is the new type that you created using the previous example. The number 0 tells the RecyclerView
how many items to recycle - in this case it's 0, meaning "do not recycle". More info about this here: https://stackoverflow.com/a/36313437/3086818.
I hope this helps.. Good luck!
回答2:
The answer is yes, you can actually do that. Since you said "The first item" so you simply add a check.
if(position == 0)
{
holder.setIsRecyclable(false); //This line prevents the row from recycling
}
来源:https://stackoverflow.com/questions/50355507/how-do-i-not-recycle-only-the-first-2-views-of-my-recyclerview-or-any-items