How to create Multiple view type Adapter with FirestorePagingAdapter ?
Basic Concepts : Basically FirestorePagingAdapter not allow to use Multiple ViewHolder . So, we find a alternative method to do this. Here we use One item_view xml file, which contain 2 type of view ImageView and PlayerView(for Video) . Here we have one Model class , which contains all Data for video and Image also (Example : for Image we need name, url and For video we have name, url, thumbnail so our model Contains name, url, thumbnail ). From the above example, we check "thumbnail != null" that means this is a video data , so we visible only playerView for video and make Invisible other view. In this process our Multiview adapter work.
[Note:- When you add data to fireStore you must use 2 model one for Image and one for video In a same Collection . But getting the data by a universal model class ]
Follow the Steps we Make a demo app for better understanding :
First must Add some dependency:
implementation 'com.firebaseui:firebase-ui-firestore:7.1.1'
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
implementation 'com.google.android.exoplayer:exoplayer:2.7.1'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'com.google.firebase:firebase-firestore:22.0.1'
implementation 'androidx.paging:paging-runtime:2.1.2'
Create a Layout Resource File Named "item"
item.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="1dp"
android:layout_marginBottom="1dp"
android:orientation="vertical">
<LinearLayout
android:id="@+id/videoLinerLayout"
android:layout_width="match_parent"
android:visibility="visible"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="1dp"
android:layout_marginBottom="1dp">
<LinearLayout
android:id="@+id/linearLayout13"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/vDes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:text="Hlo this is Video Caption section."
android:textColor="@android:color/black"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
<com.google.android.exoplayer2.ui.PlayerView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="225dp"
android:background="@android:color/black"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/linearLayout13">
</com.google.android.exoplayer2.ui.PlayerView>
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@+id/videoView"
app:layout_constraintEnd_toEndOf="@+id/videoView"
app:layout_constraintStart_toStartOf="@+id/videoView"
app:layout_constraintTop_toBottomOf="@+id/linearLayout13" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/imageLinerLayout"
android:layout_width="match_parent"
android:visibility="visible"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="2dp"
>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/captionImage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:padding="4dp"
android:textColor="#353A3A"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="450dp"
android:layout_marginTop="8dp"
android:background="#D5CECE"
android:scaleType="fitCenter"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/captionImage" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
</LinearLayout>
Create a java Class named "Model"
model.java :
public class Model {
private String name,url,thumbnail;
public Model() {
}
public Model(String name, String url, String thumbnail) {
this.name = name;
this.url = url;
this.thumbnail = thumbnail;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getThumbnail() {
return thumbnail;
}
public void setThumbnail(String thumbnail) {
this.thumbnail = thumbnail;
}
}
Create one more java Class named "ViewHolder"
ViewHolder.java :
public class ViewHolder extends RecyclerView.ViewHolder {
View view;
public LinearLayout videoLinerLayout,imageLinerLayout;
public PlayerView videoViewPath;
public SimpleExoPlayer simpleExoPlayer;
public ImageView imageView;
public TextView videoCt,imageCt;
public ProgressBar progressBar;
public ViewHolder(@NonNull View itemView) {
super(itemView);
view=itemView;
videoLinerLayout=itemView.findViewById(R.id.videoLinerLayout);
imageLinerLayout=itemView.findViewById(R.id.imageLinerLayout);
}
public void setImageView(String name,String url) {
imageView=view.findViewById(R.id.imageView);
imageCt=view.findViewById(R.id.captionImage);
imageCt.setText(name);
Glide.with(view.getContext())
.load(url)
.centerCrop()
.into(imageView);
}
public void setVideoView(String name,String url,String thumbnail){
videoViewPath=view.findViewById(R.id.videoView);
progressBar=view.findViewById(R.id.progressBar);
videoCt=view.findViewById(R.id.vDes);
videoCt.setText(name);
setPlayer(url);
}
private void setPlayer(String video) {
LoadControl loadControl = new DefaultLoadControl();
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelector trackSelector = new DefaultTrackSelector(
new AdaptiveTrackSelection.Factory(bandwidthMeter)
);
simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(
view.getContext(), trackSelector, loadControl
);
DefaultHttpDataSourceFactory factory = new DefaultHttpDataSourceFactory(
"Video"
);
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
MediaSource mediaSource = new ExtractorMediaSource(Uri.parse(video),
factory, extractorsFactory, null, null
);
videoViewPath.setPlayer(simpleExoPlayer);
videoViewPath.setKeepScreenOn(true);
simpleExoPlayer.prepare(mediaSource);
simpleExoPlayer.setPlayWhenReady(false);
simpleExoPlayer.addListener(new Player.DefaultEventListener() {
@Override
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
super.onTimelineChanged(timeline, manifest, reason);
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
super.onTracksChanged(trackGroups, trackSelections);
}
@Override
public void onLoadingChanged(boolean isLoading) {
super.onLoadingChanged(isLoading);
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
super.onPlayerStateChanged(playWhenReady, playbackState);
switch (playbackState) {
case Player.STATE_BUFFERING:
progressBar.setVisibility(View.VISIBLE);
break;
case Player.STATE_ENDED:
break;
case Player.STATE_IDLE:
break;
case Player.STATE_READY:
progressBar.setVisibility(View.INVISIBLE);
break;
default:
break;
}
}
@Override
public void onRepeatModeChanged(int repeatMode) {
super.onRepeatModeChanged(repeatMode);
}
@Override
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
super.onShuffleModeEnabledChanged(shuffleModeEnabled);
}
@Override
public void onPlayerError(ExoPlaybackException error) {
super.onPlayerError(error);
}
@Override
public void onPositionDiscontinuity(int reason) {
super.onPositionDiscontinuity(reason);
}
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
super.onPlaybackParametersChanged(playbackParameters);
}
@Override
public void onSeekProcessed() {
super.onSeekProcessed();
}
});
}
}
activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
tools:context=".MainActivity">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#E4E0E4"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/feeds"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<ProgressBar
android:id="@+id/loadMore"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@+id/swipeLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java:
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private SwipeRefreshLayout swipeRefreshLayout;
private FirestorePagingAdapter<Model,ViewHolder> firestorePagingAdapter;
private LinearLayoutManager feedsLayoutManager;
private ProgressBar loadMore;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
feedsLayoutManager = new LinearLayoutManager(this);
feedsLayoutManager.setOrientation(RecyclerView.VERTICAL);
recyclerView.setLayoutManager(feedsLayoutManager);
Query query = FirebaseFirestore.getInstance()
.collection("HomeFeed")
.orderBy("mTimestamp", Query.Direction.DESCENDING);
PagedList.Config config = new PagedList.Config.Builder()
.setEnablePlaceholders(false)
.setInitialLoadSizeHint(5)
.setPageSize(5)
.build();
FirestorePagingOptions<Model> options = new FirestorePagingOptions.Builder<Model>()
.setQuery(query, config, Model.class)
.build();
firestorePagingAdapter= new FirestorePagingAdapter<Model, ViewHolder>(options) {
@Override
protected void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull Model model) {
if (model.getThumbnail() != null){
holder.imageLinerLayout.setVisibility(View.GONE);
holder.setVideoView(model.getName(),model.getUrl(),model.getThumbnail());
}else {
holder.videoLinerLayout.setVisibility(View.GONE);
holder.setImageView(model.getName(),model.getUrl());
}
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item,parent,false));
}
@Override
protected void onLoadingStateChanged(@NonNull LoadingState state) {
switch (state) {
case LOADING_INITIAL:
// The initial load has
swipeRefreshLayout.setRefreshing(true);
break;
// ...
case LOADING_MORE:
// The adapter has started to load an additional page
loadMore.setVisibility(View.VISIBLE);
break;
// ...
case LOADED:
// The previous load (either initial or additional) completed
swipeRefreshLayout.setRefreshing(false);
loadMore.setVisibility(View.INVISIBLE);
break;
// ...
case FINISHED:
loadMore.setVisibility(View.INVISIBLE);
break;
case ERROR:
// The previous load (either initial or additional) failed. Call
// the retry() method in order to retry the load operation.
break;
// ...
}
}
@Override
public void onViewDetachedFromWindow(@NonNull ViewHolder holder) {
super.onViewDetachedFromWindow(holder);
if (holder.simpleExoPlayer != null) {
holder.simpleExoPlayer.setPlayWhenReady(false);
}
}
};
recyclerView.setAdapter(firestorePagingAdapter);
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
firestorePagingAdapter.refresh();
}
});
}
private void init() {
recyclerView=findViewById(R.id.feeds);
swipeRefreshLayout=findViewById(R.id.swipeLayout);
loadMore=findViewById(R.id.loadMore);
}
}
Our Demo App is now Completed. I hope you all learn some thing new. Thank You for visiting Our site. Keep Learning Keep Growing

