I use the exoplayer 3 times in my application so I thought it would be better to implement it in its own class and just use it 3 times.
In doing this I introduced a memory leak so it is leaking the activity and causing the app to crash.
I am not really sure why this would be happening because I haven't closed the activity. I guess it is because there is some change in the activity or the view.
If you could tell me what is wrong with my implementation to cause a memory leak it would be greatly appreciated.
This is my exoplayer control class:
public class ExoPlayerControls {
Context context;
SimpleExoPlayerView simpleExoplayerView;
SimpleExoPlayer player;
boolean preview;
public ExoPlayerControls(Context context, SimpleExoPlayerView simpleExoplayerView, SimpleExoPlayer player, Boolean preview) {
this.context = context;
this.simpleExoplayerView = simpleExoplayerView;
this.player = player;
this.preview = preview;
}
public boolean setUPExoPlayer (String alarmMediaLocation){
try {
if (player != null){
player.setPlayWhenReady(false);
//URI location of audio
Uri mediaURI = Uri.parse(alarmMediaLocation);
// Data source Factory
DefaultHttpDataSourceFactory datasourceFactory = new DefaultHttpDataSourceFactory("alarm video");
// Extractor Factory
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
// Media source
MediaSource mediasource = new ExtractorMediaSource(mediaURI, datasourceFactory, extractorsFactory, null, null);
// Prepare the exoplayer
player.prepare(mediasource);
player.setPlayWhenReady(false);
} else {
// Create a bandwith meter
BandwidthMeter bandwidthmeter = new DefaultBandwidthMeter();
// Create a track selector
TrackSelector trackselector = new DefaultTrackSelector(new AdaptiveTrackSelection.Factory(bandwidthmeter));
// Create the player
player = ExoPlayerFactory.newSimpleInstance(context, trackselector);
//URI location of audio
Uri mediaURI = Uri.parse(alarmMediaLocation);
// Data source Factory
DefaultHttpDataSourceFactory datasourceFactory = new DefaultHttpDataSourceFactory("alarm video");
// Extractor Factory
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
// Media source
MediaSource mediasource = new ExtractorMediaSource(mediaURI, datasourceFactory, extractorsFactory, null, null);
// Bind the player to the view.
simpleExoplayerView.setPlayer(player);
// Prepare the exoplayer
player.prepare(mediasource);
player.setPlayWhenReady(false);
}
} catch (Error e){
Toast.makeText(context, "Exoplayer error" + e, Toast.LENGTH_SHORT).show();
}
return true;
}
public void playAlarmMedia(String alarmMediaLocation){
try {
boolean exoPlayerSet = setUPExoPlayer(alarmMediaLocation);
if (exoPlayerSet){
// Tell exoplayer to start playing immediately
player.setPlayWhenReady(true);
}
} catch (Error e){
Toast.makeText(context, "Exoplayer error" + e, Toast.LENGTH_SHORT).show();
}
}
}
And I implement it in my activity like this:
// Initialise exoplayer controls
exoPlayerControls = new ExoPlayerControls(this, simpleExoplayerView, player, preview);
String alarmMediaLocation = downloadedAlarmToPlay.getAlarmMediaLocation();
exoPlayerControls.setUPExoPlayer(alarmMediaLocation);
The exoplayer class has three nested static classes/interfaces ExoplayerComponent, Factory and Listener. In general any Static objects will hold reference to an activity. Could the memory leak be caused by orientation changes? Because the activity will be unable to destroy itself. So older instances of the activity will be retained in memory causing a memory leak. A way to get over this is to use getAppplicationContext() instead of the Activity context (this). The application context is a singleton object. So every time Activity gets created due to screen rotation, no new instances of context are being created.
Related
I am building Music App in which I have uploaded music on firebase. I am using SimpleExoPlayer and PlayerView to run the music. The problem is when I click on the music, the music start after 10 seconds or more. I search it but did not find any solution
ExoPLayer library:
implementation "com.google.android.exoplayer:exoplayer:2.14.1"
public void initPlayer(MusicModel dataModel) {
if (playerLayout.getVisibility() == View.GONE && !isFullScreenOn) {
playerLayout.setVisibility(View.VISIBLE);
}
assignPlayerLayout(dataModel);
assignFullScreenPlayerLayout(dataModel);
try {
playerView.setControllerShowTimeoutMs(0);
playerView.setCameraDistance(10);
playerView.setShowFastForwardButton(false);
playerView.setShowRewindButton(false);
playerView.setShowNextButton(false);
playerView.setShowPreviousButton(false);
playerView.setShutterBackgroundColor(R.color.white);
simpleExoPlayer = new SimpleExoPlayer.Builder(MainActivity.this).build();
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setUsage(C.USAGE_MEDIA)
.setContentType(C.CONTENT_TYPE_MOVIE)
.build();
simpleExoPlayer.setAudioAttributes(audioAttributes, true);
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(MainActivity.this,
Util.getUserAgent(MainActivity.this, getResources().getString(R.string.app_name)));
MediaSource mediaSource = new ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(Uri.parse(getString(dataModel.getAudioFile())));
playerView.setPlayer(simpleExoPlayer);
simpleExoPlayer.seekTo(0);
// Tell it to play the sound
simpleExoPlayer.prepare(mediaSource);
simpleExoPlayer.setPlayWhenReady(true);
isPlaying = true;
}catch (Exception e){
Log.e("except",e.toString());
}
}
Please give me a solution
Blockquote
, I shall be very thankful to you.
I'm using exoplayer 2, and have Repeat mode on, meaning it will keep playing the video once it reaches the end. However, after the video ends and plays again, it keeps rebuffering (reloading the video). How do I prevent this from happening?
player = new SimpleExoPlayer.Builder(mContext).build();
player.setPlayWhenReady(false);
player.setRepeatMode(Player.REPEAT_MODE_ONE);
Edit1:
Have tried using LoopingMediaSource, not sure if I am doing it correctly though?
Because it still rebuffers when it automatically replays the video.
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(mContext,
Util.getUserAgent(mContext, "yourApplicationName"));
Uri uri = Uri.parse(mUrl);
MediaSource videoSource =
new ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(uri);
LoopingMediaSource loopingMediaSource = new LoopingMediaSource(videoSource);
player.prepare(loopingMediaSource);
When it comes to video buffering this is inevitable, as only a portion of the video is kept in memory.
What you can try is to adjust the buffering duration by setting a custom load control. Tune the setBufferDurationsMs parameters to achieve your expected results.
final DefaultTrackSelector trackSelector = new DefaultTrackSelector(context);
final DefaultLoadControl loadControl = new DefaultLoadControl
.Builder()
.setBufferDurationsMs(25000, 50000, 1500, 2000)
.build();
player = new SimpleExoPlayer
.Builder(context)
.setTrackSelector(trackSelector)
.setLoadControl(loadControl)
.build();
If by adjusting the parameters in setBufferDurationMs you can't still get the desired results, then you may need to implement the drip-feeding technique to improve rebuffering. Next a tutorial about how to implement such technique, targeted at ExoPlayer:
https://medium.com/#filipluch/how-to-improve-buffering-by-4-times-with-drip-feeding-technique-in-exoplayer-on-android-b59eb0c4d9cc
You need cache data in ExoPlayer
Create a custom cache data source factory
public class CacheDataSourceFactory implements DataSource.Factory {
private final Context context;
private final DefaultDataSourceFactory defaultDatasourceFactory;
private final long maxFileSize, maxCacheSize;
public CacheDataSourceFactory(Context context, long maxCacheSize, long maxFileSize) {
super();
this.context = context;
this.maxCacheSize = maxCacheSize;
this.maxFileSize = maxFileSize;
String userAgent = Util.getUserAgent(context, context.getString(R.string.app_name));
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
defaultDatasourceFactory = new DefaultDataSourceFactory(this.context,
bandwidthMeter,
new DefaultHttpDataSourceFactory(userAgent, bandwidthMeter));
}
#Override
public DataSource createDataSource() {
LeastRecentlyUsedCacheEvictor evictor = new LeastRecentlyUsedCacheEvictor(maxCacheSize);
SimpleCache simpleCache = new SimpleCache(new File(context.getCacheDir(), "media"), evictor);
return new CacheDataSource(simpleCache, defaultDatasourceFactory.createDataSource(),
new FileDataSource(), new CacheDataSink(simpleCache, maxFileSize),
CacheDataSource.FLAG_BLOCK_ON_CACHE | CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR, null);
}
}
And the player
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory =
new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
SimpleExoPlayer exoPlayer = ExoPlayerFactory.newSimpleInstance(this, trackSelector);
MediaSource audioSource = new ExtractorMediaSource(Uri.parse(url),
new CacheDataSourceFactory(context, 100 * 1024 * 1024, 5 * 1024 * 1024), new DefaultExtractorsFactory(), null, null);
exoPlayer.setPlayWhenReady(true);
exoPlayer.prepare(audioSource);
Try to use LoopingMediaSource and put it to player by:
player.prepare(loopingMediaSource)
I am using Customised ExoPlayer to display videos in my project. I set some fixed height for ExoPlayer view let say 300dp the video is playing without any issues. But the problem is if I set the height of ExoPlayer view to match parent and change the screen orientation to landscape the video is playing but it keeps on buffering. The state of the video most of the time is reaming in the buffering state. Please help me to solve the issue and I am posting the code snippet of my data source below.
public void play(String url) {
defaultBandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory trackSelectionFactory = new AdaptiveTrackSelection.Factory(defaultBandwidthMeter);
exoPlayer = ExoPlayerFactory.newSimpleInstance(new DefaultRenderersFactory(VideoNewFullScreenMode.this),
new DefaultTrackSelector(trackSelectionFactory), new DefaultLoadControl());
MediaSource datasource = buildMediaStore(url);
exoPlayer.prepare(datasource, true, true);
simpleExoPlayer.setPlayer(exoPlayer);
exoPlayer.setPlayWhenReady(true);
simpleExoPlayer.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_ZOOM);
exoPlayer.seekTo(getIntent().getLongExtra("position", 0));
//updateTimers();
exoPlayer.addListener(this);
}
private MediaSource buildMediaStore(String mediaUrl) {
Uri videoUri = Uri.parse(mediaUrl);
DataSource.Factory dataSourceFactory = new DefaultHttpDataSourceFactory(Util.getUserAgent(this, getApplicationInfo().packageName), defaultBandwidthMeter);
DefaultExtractorsFactory extractorFactory = new DefaultExtractorsFactory();
return new ExtractorMediaSource(videoUri, dataSourceFactory, extractorFactory, null, null);
}
I'm creating a playlist video player in exoplayer in android studio. I'm adding the first video extracted from a server and it is being played by the exoplayer perfectly. But when I add the second part, the exoplayer does not play that video. I want to add the second video after the exoplayer has been prepared. I want to know how to do that. Please Help me.
My MainActivity.java:
public class MainActivity extends AppCompatActivity
{
SimpleExoPlayer video_player;
PlayerView player_screen;
DefaultTrackSelector track_selector;
DefaultBandwidthMeter band_width_meter = new DefaultBandwidthMeter();
ArrayList<MediaSource> mediaSources_contents = new ArrayList<>();
ConcatenatingMediaSource concatenating_mediaSource_contents;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
player_screen = (PlayerView) findViewById(R.id.player_screen);
player_screen.requestFocus();
TrackSelection.Factory video_track_selection_factory = new AdaptiveTrackSelection.Factory(band_width_meter);
track_selector = new DefaultTrackSelector(video_track_selection_factory);
video_player = ExoPlayerFactory.newSimpleInstance(this, track_selector);
player_screen.setPlayer(video_player);
video_player.setPlayWhenReady(true);
Uri url1 = Uri.parse("THE - URL - OF - FIRST - VIDEO");
DataSource.Factory data_source_factory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "Application Name"), band_width_meter);
MediaSource source1 = new ExtractorMediaSource.Factory(data_source_factory).createMediaSource(url1);
mediaSources_contents.add(source1);
concatenating_mediaSource_contents = new ConcatenatingMediaSource(mediaSources_contents.toArray(new MediaSource[mediaSources_contents.size()]));
video_player.prepare(concatenating_mediaSource_contents);
// The lines below this point adds the second video to the media source. But it is not being played by the exoplayer.
Uri url2 = Uri.parse("THE - URL - OF - SECOND - VIDEO");
MediaSource source2 = new ExtractorMediaSource.Factory(data_source_factory).createMediaSource(url2);
mediaSources_contents.add(source2);
}
}
At Prepared Time
Initialize ConcatenatingMediaSource
ConcatenatingMediaSource mediaSource = new ConcatenatingMediaSource();
MediaSource firstSource = new ProgressiveMediaSource.Factory(new FileDataSourceFactory()).createMediaSource(Uri.parse(uri.get(0)));
MediaSource secondSource= new ProgressiveMediaSource.Factory(new FileDataSourceFactory()).createMediaSource(Uri.parse(uri.get(1)));
mediaSource.addMediaSources(firstSource);
mediaSource.addMediaSources(secondSource);
player.prepare(mediaSource, true, false);
After Prepare Add mediasource
MediaSource thirdSource= new ProgressiveMediaSource.Factory(new FileDataSourceFactory()).createMediaSource(Uri.parse(uri.get(3)));
mediaSource.addMediaSources(thirdSource);// mediaSource is refrance of ConcatenatingMediaSource
Try add this concatenating_mediaSource_contents.addMediaSource(source2); instead mediaSources_contents.add(source2);and for first media source also (not necessary, for better readability)
if i use the first one from the following codes,
the 1.m3u8 type songs are running.
if i use the second one, mp3 and the other songs are running.
Is there one code series that can run these formats in one? Maybe it is a simple coding but i couldn t do that. Please help me.
#Override
protected String doInBackground(String... a) {
String s = Constant.arrayList_play.get(Constant.playPos).getMp3Url().replace(" ","%20");
try {
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory((MainActivity)Constant.context,
Util.getUserAgent((MainActivity)Constant.context, "onlinemp3"), bandwidthMeter);
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
MediaSource videoSource = new ExtractorMediaSource(Uri.parse(s),
dataSourceFactory, extractorsFactory, null, null);
Constant.exoPlayer.prepare(videoSource);
Constant.exoPlayer.setPlayWhenReady(true);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
May be you need to read here about exoplayer's supported formats.