Search code examples
androidjsonandroid-recyclerviewrestexoplayer

how to play next video automatically in list exoplayer android


I am creating movie streaming app in android studio i have used recyclerview and exoplayer . everything is perfect there is one final touch which is episodes creation. i would like to add episode to the videos and auto play them after completion of current video exactly like youtube player does. i am adding my json file , main activity video player activity for reference .

what i know is i can create another recycler inside movie activity (where i would display all my episodes list in recyclerview)

i need to create a model and new adapter file for this episodes list also i think i have to create seperate JSon data for this since its different and specific from rest

Main Activity . java program

package com.threeminutesfix.gospelvideos;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.widget.NestedScrollView;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager.widget.ViewPager;

import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import com.threeminutesfix.gospelvideos.Utility.NetworkChangeListerner;
import com.threeminutesfix.gospelvideos.adapter.BannerMoviesPagerAdapter;
import com.threeminutesfix.gospelvideos.adapter.ItemRecyclerAdapter;
import com.threeminutesfix.gospelvideos.adapter.MainRecyclerAdapter;
import com.threeminutesfix.gospelvideos.model.AllCategory;
import com.threeminutesfix.gospelvideos.model.BannerMovies;
import com.threeminutesfix.gospelvideos.retrofit.RetrofitClient;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.tabs.TabLayout;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.observers.DisposableObserver;
import io.reactivex.schedulers.Schedulers;

public class MainActivity extends AppCompatActivity {

    BannerMoviesPagerAdapter bannerMoviesPagerAdapter;
    NetworkChangeListerner networkChangeListerner = new NetworkChangeListerner();

    TabLayout IndicatorTab, categoryTab;
    ViewPager bannerMoviesViewpager;
    List<BannerMovies> homeBannerList;
    List<BannerMovies> tvBannerList;
    List<BannerMovies> songBannerList;
    List<BannerMovies> audioBannerList;
    NestedScrollView nestedScrollView;
    AppBarLayout appBarLayout;
    MainRecyclerAdapter mainRecyclerAdapter;
    RecyclerView mainRecycler;
    List<AllCategory> allCategoryList;
    ItemRecyclerAdapter itemRecyclerAdapter;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Objects.requireNonNull(getSupportActionBar()).setLogo(R.drawable.main_logo);
        getSupportActionBar().setDisplayUseLogoEnabled(true);
        IndicatorTab = findViewById(R.id.tab_indicator);
        categoryTab = findViewById(R.id.tabLayout);
        nestedScrollView = findViewById(R.id.nested_scroll);
        appBarLayout = findViewById(R.id.appbar);
        homeBannerList = new ArrayList<>();
        tvBannerList = new ArrayList<>();
        songBannerList = new ArrayList<>();
        audioBannerList = new ArrayList<>();
        getBannerData();
        getAllMoviesData(1);

        categoryTab.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                switch (tab.getPosition()) {
                    case 1:

                        setBannerMoviesPagerAdapter(tvBannerList);
                        getAllMoviesData(2);


                        return;
                    case 2:

                        setBannerMoviesPagerAdapter(songBannerList);
                        getAllMoviesData(3);

                        return;

                    case 3:

                        setBannerMoviesPagerAdapter(audioBannerList);
                        getAllMoviesData(4);
                        return;
                    default:

                        setBannerMoviesPagerAdapter(homeBannerList);
                        getAllMoviesData(1);


                }

            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });


        //titles
        allCategoryList = new ArrayList<>();


    }



    private void setBannerMoviesPagerAdapter(List<BannerMovies> bannerMoviesList) {
        bannerMoviesViewpager = findViewById(R.id.banner_viewPager);
        bannerMoviesPagerAdapter = new BannerMoviesPagerAdapter(this, bannerMoviesList);
        bannerMoviesViewpager.setAdapter(bannerMoviesPagerAdapter);
        IndicatorTab.setupWithViewPager(bannerMoviesViewpager);


    }


    public void setMainRecycler(List<AllCategory> allCategoryList) {
        mainRecycler = findViewById(R.id.main_recycler);
        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this, RecyclerView.VERTICAL, false);
        mainRecycler.setLayoutManager(layoutManager);
        mainRecyclerAdapter = new MainRecyclerAdapter(this, allCategoryList);
        mainRecycler.setAdapter(mainRecyclerAdapter);
        mainRecyclerAdapter.notifyDataSetChanged();
    }

    private void getBannerData() {
        CompositeDisposable compositeDisposable = new CompositeDisposable();
        compositeDisposable.add(RetrofitClient.getRetroFitClient().getAllBanners()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeWith(new DisposableObserver<List<BannerMovies>>() {
                    @Override
                    public void onNext(List<BannerMovies> bannerMovies) {
                        for (int i = 0; i < bannerMovies.size(); i++) {
                            if (bannerMovies.get(i).getBannerCategoryId().toString().equals("1")) {
                                homeBannerList.add(bannerMovies.get(i));

                            } else if (bannerMovies.get(i).getBannerCategoryId().toString().equals("2")) {
                                tvBannerList.add(bannerMovies.get(i));

                            } else if (bannerMovies.get(i).getBannerCategoryId().toString().equals("3")) {
                                songBannerList.add(bannerMovies.get(i));

                            } else if (bannerMovies.get(i).getBannerCategoryId().toString().equals("4")) {
                                audioBannerList.add(bannerMovies.get(i));

                            } else {
                                homeBannerList.add(bannerMovies.get(i));
                            }


                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.d("bannerData", "" + e);
                    }

                    @Override
                    public void onComplete() {
                        setBannerMoviesPagerAdapter(homeBannerList);
                    }
                })

        );
    }

    private void getAllMoviesData(Integer categoryId) {
        CompositeDisposable compositeDisposable = new CompositeDisposable();
        compositeDisposable.add(RetrofitClient.getRetroFitClient().getAllCategoryMovies(categoryId)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeWith(new DisposableObserver<List<AllCategory>>() {
                    @Override
                    public void onNext(List<AllCategory> allCategoryList) {
                        for (int i = 0; i < allCategoryList.size(); i++) {
                            setMainRecycler(allCategoryList);
                        }


                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.d("bannerData", "" + e);
                    }

                    @Override
                    public void onComplete() {

                    }
                })

        );
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main_menu,menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        int id = item.getItemId();
        switch (id){
            case R.id.refresh_folders:
                finish();
                startActivity(getIntent());
                break;
            case R.id.share_app:
                Intent share_intent= new Intent();
                share_intent.setAction(Intent.ACTION_SEND);
                share_intent.putExtra(Intent.EXTRA_TEXT,"check this app via \n"+"https://play.google.com/store/apps/details?id="+getApplicationContext().getPackageName());
                share_intent.setType("text/plain");
                startActivity(Intent.createChooser(share_intent,"Share App via"));
                break;
        }
        return true;
    }

    private boolean doubleBackToExitPressedOnce = false;

    @Override
    protected void onResume() {
        super.onResume();
        // .... other stuff in my onResume ....
        this.doubleBackToExitPressedOnce = false;
    }

    @Override
    public void onBackPressed() {
        if (doubleBackToExitPressedOnce) {
            super.onBackPressed();
            return;
        }
        this.doubleBackToExitPressedOnce = true;
        Toast.makeText(this, R.string.exit_press_back_twice_message, Toast.LENGTH_SHORT).show();

    }

    @Override
    protected void onStart() {
        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        registerReceiver(networkChangeListerner,filter);

        super.onStart();
    }

    @Override
    protected void onStop() {
        unregisterReceiver(networkChangeListerner);
        super.onStop();
    }

}

Movie Details.java

package com.threeminutesfix.gospelvideos;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.widget.NestedScrollView;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.threeminutesfix.gospelvideos.Utility.NetworkChangeListerner;
import com.threeminutesfix.gospelvideos.adapter.SimilarRecyclerAdapter;
import com.threeminutesfix.gospelvideos.model.AllCategory;
import com.threeminutesfix.gospelvideos.retrofit.RetrofitClient;

import java.util.ArrayList;
import java.util.List;

import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.observers.DisposableObserver;
import io.reactivex.schedulers.Schedulers;

public class MovieDetails extends AppCompatActivity
{
    RecyclerView mainRecycler;
    TextView video_timer;
    ImageView movieImage;
    ImageView MovieThumb;
    TextView movieName;
    TextView movieDesc;
    TextView Language;
    TextView Singers;
    Button playButton;
    List<AllCategory> allCategoryList;
    NestedScrollView nestedScrollView;
     ImageView Trailer;
    String mName;
    String mImage;
    String mId;
    String mFileUrl;
    String subFileUrl;
    String Msmall;
    String Mdesc;
    String Mlang;
    String Msinger;
    String Vtimer;
    String Turl;
    int CatId;
    NetworkChangeListerner networkChangeListerner = new NetworkChangeListerner();
   SimilarRecyclerAdapter similarRecyclerAdapter;
    @SuppressLint("CutPasteId")
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_movie_details);
        movieImage = findViewById(R.id.movie_image);
        movieName = findViewById(R.id.movie_name);
        movieDesc=findViewById(R.id.desc);
        playButton = findViewById(R.id.play_button);
        Trailer=findViewById(R.id.Trailer);
        video_timer= findViewById(R.id.video_timer);
        MovieThumb=findViewById(R.id.smallThumb);
        Language=findViewById(R.id.Language);
        Singers=findViewById(R.id.Singer);
        nestedScrollView= findViewById(R.id.scroll_movie);
        mName = getIntent().getStringExtra("movieName");
        mImage = getIntent().getStringExtra("movieImageUrl");
        mFileUrl = getIntent().getStringExtra("movieFile");
        Msmall=getIntent().getStringExtra("smallThumb");
        Mdesc=getIntent().getStringExtra("MovieDesc");
        Mlang=getIntent().getStringExtra("Language");
        Msinger=getIntent().getStringExtra("Singers");
        Turl=getIntent().getStringExtra("TrailerUrl");
        subFileUrl=getIntent().getStringExtra("SrtUrl");
        Vtimer= getIntent().getStringExtra("VideoTiming");
        setTitle(mName);
        Glide.with(this).load(mImage).placeholder(R.drawable.film).into(movieImage);
        Glide.with(this).load(Msmall).placeholder(R.drawable.thumb).into(MovieThumb);
        Glide.with(this).load(mImage).placeholder(R.drawable.thumb).into(Trailer);
        movieName.setText(mName);
        movieDesc.setText(Mdesc);
        Language.setText(Mlang);
        Singers.setText(Msinger);
        video_timer.setText(Vtimer);
        CatId = getIntent().getIntExtra("categoryId", 0);
        getMovies(CatId);
        allCategoryList = new ArrayList<>();

        playButton.setOnClickListener(v -> {
            if(mFileUrl==null) {
                Toast.makeText(this, "Error Occurred while fetching this video. try again later or restart this app", Toast.LENGTH_LONG).show();
            }
            else{
                Intent i = new Intent(MovieDetails.this, VideoPlayerActivity
                        .class);
                i.putExtra("movieId", mId);
                i.putExtra("url", mFileUrl);
                i.putExtra("movieName", mName);
                i.putExtra("MovieThumb", Msmall);
                i.putExtra("SrtUrl",subFileUrl);
                startActivity(i);

            }
        });
        Trailer.setOnClickListener(v -> {
            if (Turl == null)
            {
                Toast.makeText(this, "Trailer not available or not added by original owners", Toast.LENGTH_LONG).show();
            }
            else{
            Intent i = new Intent(MovieDetails.this, TrailerActivity.class);
            i.putExtra("url", Turl);
            i.putExtra("movieName",mName);
            startActivity(i);
            }
 });

}


    @Override
    protected void onStart() {
        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        registerReceiver(networkChangeListerner,filter);
        super.onStart();
    }

    @Override
    protected void onStop() {
        unregisterReceiver(networkChangeListerner);
        super.onStop();
    }
    public void setMainRecycler(List<AllCategory> allCategoryList) {
        mainRecycler = findViewById(R.id.Similar_rv);
        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this, RecyclerView.VERTICAL, false);
        mainRecycler.setLayoutManager(layoutManager);
        similarRecyclerAdapter = new SimilarRecyclerAdapter(this, allCategoryList);
        mainRecycler.setAdapter(similarRecyclerAdapter);
        similarRecyclerAdapter.notifyDataSetChanged();
    }

    private void getMovies(Integer categoryId) {
        CompositeDisposable compositeDisposable = new CompositeDisposable();
        compositeDisposable.add(RetrofitClient.getRetroFitClient2().getMovies(categoryId)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeWith(new DisposableObserver<List<AllCategory>>() {
                    @Override
                    public void onNext(List<AllCategory> allCategoryList) {
                        for (int i = 0; i < allCategoryList.size(); i++) {
                            setMainRecycler(allCategoryList);
                        }


                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.d("bannerData", "" + e);
                    }

                    @Override
                    public void onComplete() {

                    }
                })

        );
    }


}

categoryItemlist.java (model file)

package com.threeminutesfix.gospelvideos.model;

import java.io.Serializable;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class AllCategory implements Serializable {

    @SerializedName("categoryId")
    @Expose
    private Integer categoryId;
    @SerializedName("categoryTitle")
    @Expose
    private String categoryTitle;
    @SerializedName("categoryImage")
    @Expose
    private String categoryImage;
    @SerializedName("categoryItemList")
    @Expose
    private List<CategoryItemList> categoryItemList = null;

    public Integer getCategoryId() {
        return categoryId;
    }

    public void setCategoryId(Integer categoryId) {
        this.categoryId = categoryId;
    }

    public String getCategoryTitle() {
        return categoryTitle;
    }

    public void setCategoryTitle(String categoryTitle) {
        this.categoryTitle = categoryTitle;
    }

    public String getCategoryImage() {
        return categoryImage;
    }

    public void setCategoryImage(String categoryImage) {
        this.categoryImage = categoryImage;
    }

    public List<CategoryItemList> getCategoryItemList() {
        return categoryItemList;
    }

    public void setCategoryItemList(List<CategoryItemList> categoryItemList) {
        this.categoryItemList = categoryItemList;
    }

}
all category (model file)

package com.threeminutesfix.gospelvideos.model;

import java.io.Serializable;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class AllCategory implements Serializable {

    @SerializedName("categoryId")
    @Expose
    private Integer categoryId;
    @SerializedName("categoryTitle")
    @Expose
    private String categoryTitle;
    @SerializedName("categoryImage")
    @Expose
    private String categoryImage;
    @SerializedName("categoryItemList")
    @Expose
    private List<CategoryItemList> categoryItemList = null;

    public Integer getCategoryId() {
        return categoryId;
    }

    public void setCategoryId(Integer categoryId) {
        this.categoryId = categoryId;
    }

    public String getCategoryTitle() {
        return categoryTitle;
    }

    public void setCategoryTitle(String categoryTitle) {
        this.categoryTitle = categoryTitle;
    }

    public String getCategoryImage() {
        return categoryImage;
    }

    public void setCategoryImage(String categoryImage) {
        this.categoryImage = categoryImage;
    }

    public List<CategoryItemList> getCategoryItemList() {
        return categoryItemList;
    }

    public void setCategoryItemList(List<CategoryItemList> categoryItemList) {
        this.categoryItemList = categoryItemList;
    }

}

Json data (backend of my app

ready to add further files if needed


Solution

  • It is very easy just follow below steps:-

    1]Add your all video to the list and set that list to your exo player object as below

        for (i in videoList.indices){
            var songPath:String = videoList.get(i)
            val item: MediaItem = MediaItem.fromUri(songPath)
            exoPlayerManager.addMediaItem(item)
        }
      exoPlayerManager.prepare()
      exoPlayerManager.play()
    

    2]Add/enable next, previous switch in xml layout

    <com.google.android.exoplayer2.ui.PlayerView
        android:id="@+id/playerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:keepScreenOn="true"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@id/playerViewFrameLayout"
        app:repeat_toggle_modes="all"
        app:controller_layout_id="@layout/exo_playback_control_view"
        app:resize_mode="fit"
        app:show_buffering="always"
        app:show_shuffle_button="true"
        />
    

    3] Just check by clicking next button from the media controller if that works then you are done, now the videos will be played automatically once finished the current one.