Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RecyclerView + MediaPlayer + Toggle Button + String Uri

Background: I'm working on an Fitness app. Everything is working good till now but problem came when I was working with audio files MediaPlayer in android.

I have checked resources and found ListView but couldn't find anything on RecyclerView + MediaPlayer.

I want to know how to make it work while working with RecyclerView + Toggle Button + String Uri (Offline - Raw folder)

Problem: Right now it is playing the first .mp3 file on every click event (for Eng: R.raw.sample_one_eng is played and for Hindi: R.raw.sample_one_hindi is played). I think it is not taking int position into consideration.

Later, I would like to put it online (may be google cloud) since audio files (.mp3) are making my app quite heavy. Any ideas on that would be appreciated too (fast buffering, etc.).

ListExercises.java

public class ListExercises extends AppCompatActivity {

    List<ExerciseAudio> exerciseList = new ArrayList<>();
    RecyclerView.LayoutManager layoutManager;
    RecyclerView recyclerView;
    RecyclerViewAdapterAud adapter;
    PlayClickHandler clickHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.list_exercises);

        initData();

        recyclerView = (RecyclerView) findViewById(R.id.list_ex);
        adapter = new RecyclerViewAdapterAud(exerciseList, getBaseContext());
        layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setAdapter(adapter);
    }

    private void initData() {

        exerciseList.add(new ExerciseAudio(R.drawable.sample_one, "Sample Exercise One", "Sans One",
                R.raw.sample_one_eng,
                R.raw.sample_one_hindi));

        exerciseList.add(new ExerciseAudio(R.drawable.sample_two, "Sample Exercise Two", "Sans Two",
                R.raw.sample_two_eng,
                R.raw.sample_two_hindi));

        exerciseList.add(new ExerciseAudio(R.drawable.sample_three, "Sample Exercise Three", "Sans Three",
                R.raw.sample_three_eng,
                R.raw.sample_three_hindi));

        exerciseList.add(new ExerciseAudio(R.drawable.sample_four, "Sample Exercise Four", "Sans Four",
                R.raw.sample_four_eng,
                R.raw.sample_four_hindi));
    }
}

ViewExercise.java

public class ViewExercise extends AppCompatActivity {

    int image_id, eng_aud_url, hindi_aud_url;
    String name, sans_name;

    ArrayList<String> arrayList = new ArrayList<>();

    TextView timer, title, sansName;
    ImageView detail_image;
    ToggleButton tg_btn_speaker_eng, tg_btn_speaker_hindi;

    MediaPlayer mp;

    int position;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.view_exercise);

        Field[] field = R.raw.class.getFields();
        for (int i = 0; i < field.length; i++){
            arrayList.add(field[i].getName());
        }

        title = (TextView) findViewById(R.id.title);
        sansName = (TextView) findViewById(R.id.sans_name);
        detail_image = (ImageView) findViewById(R.id.detail_image);

        tg_btn_speaker_eng = (ToggleButton) findViewById(R.id.tg_btn_speaker_eng);
        tg_btn_speaker_hindi = (ToggleButton) findViewById(R.id.tg_btn_speaker_hindi);

        tg_btn_speaker_eng.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //toggleEnglish(tg_btn_speaker_eng.isChecked());
                int positionEng = 0;
                playSongEng(positionEng);
            }
        });

        tg_btn_speaker_hindi.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //toggleHindi(tg_btn_speaker_hindi.isChecked());
                int positionHindi = 0;
                playSongHindi(positionHindi);
            }
        });

        if (getIntent() != null) {
            image_id = getIntent().getIntExtra("image_id", -1);
            name = getIntent().getStringExtra("name");
            sans_name = getIntent().getStringExtra("sanskrit_name");

            detail_image.setImageResource(image_id);
            title.setText(name);
            sansName.setText(sans_name);
        }
    }


    public void playSongEng(int i) {
        //mp.reset();
        int resId = getResources().getIdentifier(arrayList.get(i), "raw", getPackageName());
        mp = MediaPlayer.create(getApplicationContext(), resId);
        mp.start();
    }

    public void playSongHindi(int i) {
        //mp.reset();
        int resId = getResources().getIdentifier(arrayList.get(i), "raw", getPackageName());
        mp = MediaPlayer.create(getApplicationContext(), resId);
        mp.start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mp != null)
            mp.release();
    }
}

This is how it looks!

Edit (to avoid confusion): Just noticed, that image name would have been List Exercises instead of View Exercise which corresponds to ListExercises.java

List Exercise - RecyclerView

And this one corresponds to ViewExercise.java

View Exercise

Thanks!

like image 964
Rohit Sharma Avatar asked Jun 30 '18 04:06

Rohit Sharma


2 Answers

Try this code .. add below dependency into app level gradle file..

    compile 'com.google.android.exoplayer:exoplayer:r2.3.0'

after that used below code ..

public class VideoPlayerActivity extends AppCompatActivity implements ExoPlayer.EventListener {

private SimpleExoPlayer mSimpleExoPlayer;

private SimpleExoPlayerView mSimpleExoPlayerView;

private Handler mMainHandler;
private AdaptiveTrackSelection.Factory mAdaptiveTrackSelectionFactory;
private TrackSelector mTrackSelector;
private LoadControl mLoadControl;
private DefaultBandwidthMeter mBandwidthMeter;
private DataSource.Factory mDataSourceFactory;
private SimpleCache mSimpleCache;
private DataSource.Factory mFactory;
private MediaSource mVideoSource;
private LoopingMediaSource mLoopingMediaSource;
private ProgressBar mProgressBar;
private String videoUrl="http://sample.vodobox.net/skate_phantom_flex_4k/skate_phantom_flex_4k.m3u8";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_video);
    mSimpleExoPlayerView = (SimpleExoPlayerView) findViewById(R.id.videoPlayer);
    mProgressBar = (ProgressBar) findViewById(R.id.amPrgbrLoading);
}

/**
 * this method play audio and video with hls streaming.
 */
private void playMedia() {
    mMainHandler = new Handler();
    mBandwidthMeter = new DefaultBandwidthMeter();
    mAdaptiveTrackSelectionFactory = new AdaptiveTrackSelection.Factory(mBandwidthMeter);
    mTrackSelector = new DefaultTrackSelector(mAdaptiveTrackSelectionFactory);

    mLoadControl = new DefaultLoadControl();
    mSimpleExoPlayer = ExoPlayerFactory.newSimpleInstance(this, mTrackSelector, mLoadControl);

    mSimpleExoPlayerView.setPlayer(mSimpleExoPlayer);
    mSimpleExoPlayerView.setControllerVisibilityListener(new PlaybackControlView.VisibilityListener() {
        @Override
        public void onVisibilityChange(int visibility) {
            mSimpleExoPlayerView.showController();
        }
    });
    mDataSourceFactory = new DefaultDataSourceFactory(this,Util.getUserAgent(this, "com.exoplayerdemo"), mBandwidthMeter);
    mSimpleCache = new SimpleCache(this.getCacheDir(), new LeastRecentlyUsedCacheEvictor(1024 * 1024 * 10));
    mFactory = new CacheDataSourceFactory(mSimpleCache, mDataSourceFactory,0);
    mVideoSource = new HlsMediaSource(Uri.parse(videoUrl),
            mFactory, mMainHandler, new AdaptiveMediaSourceEventListener() {
        @Override
        public void onLoadStarted(DataSpec dataSpec, int dataType, int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs, long mediaEndTimeMs, long elapsedRealtimeMs) {
            //Toast.makeText(VideoPlayerActivity.this, "Load Started", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onLoadCompleted(DataSpec dataSpec, int dataType, int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs, long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs, long bytesLoaded) {
            //Toast.makeText(VideoPlayerActivity.this, "Load Completed", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onLoadCanceled(DataSpec dataSpec, int dataType, int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs, long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs, long bytesLoaded) {

        }

        @Override
        public void onLoadError(DataSpec dataSpec, int dataType, int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs, long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs, long bytesLoaded, IOException error, boolean wasCanceled) {
            videoUrl=""; // define second url
        }

        @Override
        public void onUpstreamDiscarded(int trackType, long mediaStartTimeMs, long mediaEndTimeMs) {
           // Toast.makeText(VideoPlayerActivity.this, "Up stream", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onDownstreamFormatChanged(int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, long mediaTimeMs) {
           // Toast.makeText(VideoPlayerActivity.this, "Down Stream", Toast.LENGTH_SHORT).show();
        }
    });

    mLoopingMediaSource = new LoopingMediaSource(mVideoSource);
    mSimpleExoPlayer.prepare(mLoopingMediaSource);
    mSimpleExoPlayer.setPlayWhenReady(true);
    mSimpleExoPlayer.addListener(new ExoPlayer.EventListener() {
        @Override
        public void onTimelineChanged(Timeline timeline, Object manifest) {

        }

        @Override
        public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {

        }

        @Override
        public void onLoadingChanged(boolean isLoading) {

        }

        @Override
        public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {

            if (playbackState == ExoPlayer.STATE_BUFFERING) {
                mProgressBar.setVisibility(View.VISIBLE);
            } else {
                mProgressBar.setVisibility(View.GONE);
            }

        }

        @Override
        public void onPlayerError(ExoPlaybackException error) {

        }

        @Override
        public void onPositionDiscontinuity() {

        }
    });



}

@Override
protected void onResume() {
    super.onResume();
    playMedia();
}

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

@Override
protected void onPause() {
    super.onPause();
    stopMedia();
}

private void stopMedia() {
    mSimpleExoPlayer.stop();
    mSimpleExoPlayer.release();
}



@Override
public void onTimelineChanged(Timeline timeline, Object manifest) {

}

@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {

}

@Override
public void onLoadingChanged(boolean isLoading) {

}

@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {

}

@Override
public void onPlayerError(ExoPlaybackException error) {

}

@Override
public void onPositionDiscontinuity() {

}

}

in this code used for video you can pass yor audio file path..

xml code..

        <com.google.android.exoplayer2.ui.SimpleExoPlayerView
        android:id="@+id/videoPlayer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
         />
like image 143
Android Team Avatar answered Sep 22 '22 17:09

Android Team


You can also set the click listener inside onBindViewHolder without using any interface by setting the click listener on parent view of your item_exercise_aud layout like this:

holder.parentView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(context, ViewExercise.class);
            intent.putExtra("image_id", exerciseList.get(position).getImage_id());
            intent.putExtra("name", exerciseList.get(position).getName());
            intent.putExtra("sanskrit_name", exerciseList.get(position).getSanskrit_name());
            intent.putExtra("eng_aud_url", exerciseList.get(position).getEng_aud_url());
            intent.putExtra("hindi_aud_url", exerciseList.get(position).getHindi_aud_url());
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent);
        }
    });

Or you can refer here

Edit - To play the audio according to the recyclerview list's position, we have to send the raw file name of that particular exercise to the media player.

Add two new variables to ExerciseAudio model class:

private String file_name_eng;
private String file_name_hindi;

Now modify the initData method as below:

private void initData() {

    exerciseList.add(new ExerciseAudio(R.drawable.sample_one, "Sample Exercise One", "Sans One",
            R.raw.sample_one_eng, R.raw.sample_one_hindi,
            "sample_one_eng", "sample_one_hindi"));

    exerciseList.add(new ExerciseAudio(R.drawable.sample_two, "Sample Exercise Two", "Sans Two",
            R.raw.sample_two_eng, R.raw.sample_two_hindi,
            "sample_two_eng", "sample_one_hindi"));

    exerciseList.add(new ExerciseAudio(R.drawable.sample_three, "Sample Exercise Three", "Sans Three",
            R.raw.sample_three_eng, R.raw.sample_three_hindi,
            "sample_three_eng", "sample_three_hindi"));

    exerciseList.add(new ExerciseAudio(R.drawable.sample_four, "Sample Exercise Four", "Sans Four",
            R.raw.sample_four_eng, R.raw.sample_four_hindi,
            "sample_four_eng", "sample_four_hindi"));
}

Now Modify the ViewExercise intent as:

intent.putExtra("file_name_eng", exerciseList.get(position).getFile_name_eng());
intent.putExtra("file_name_hindi", exerciseList.get(position).getFile_name_hindi());

Get the string extras in ViewExercise activity and send it to the mediaplayer:

file_name_eng = getIntent().getStringExtra("file_name_eng");
file_name_hindi = getIntent().getStringExtra("file_name_hindi");

For english:
    int resId = getResources().getIdentifier(file_name_eng, "raw", getPackageName());

For hindi:
    int resId = getResources().getIdentifier(file_name_hindi, "raw", getPackageName());
like image 41
Nainal Avatar answered Sep 22 '22 17:09

Nainal