This is my code, I tried ti build simple application that plays a song whenever I click one button (clicking twice will play the song a new from the beginning) & stop playing when another button is pushed.
I wanted that when the user put the activity in the background the media player will "save its state" - continue playing/not playing - and when the activity returns to the foreground the interaction will remain the same.
Instead it works fine until I put the activity in the background (then it keeps playing/not playing) but when I return it back it seems like "a new media player object was created" and if I click play while the song is played, it starts to play the song from the beginning simultaneously with the previous one, and clicking stop - stopping only the new "instance" of the song. Like I loose connection with the media player after the activity is in the background.
what could be the problem?
public class MainActivity extends ActionBarActivity {
private MediaPlayer mediaPlayer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button buttonStart = new Button(this);
Button buttonStop = new Button(this);
buttonStart.setText(R.string.button_start_text);
buttonStop.setText(R.string.button_stop_text);
buttonStart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startPlaying();
}
});
buttonStop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
stopPlaying();
}
});
ViewGroup layout = (ViewGroup) findViewById(R.id.mainLayout);
layout.addView(buttonStart);
layout.addView(buttonStop);
}
void startPlaying(){
stopPlaying();
mediaPlayer = MediaPlayer.create(this,R.raw.dreams);
mediaPlayer.start();
}
void stopPlaying(){
if (mediaPlayer != null){
try {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.release();
}
}
catch (Exception e){
e.printStackTrace();
}
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
I changed the code also, like this (now there are 3 buttons: play, stop, pause:
void startPlaying(){
if (mediaPlayer == null) {
mediaPlayer = MediaPlayer.create(this, R.raw.dreams);
}
mediaPlayer.start();
}
void stopPlaying(){
if (mediaPlayer != null){
try {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.prepare();
}
}
catch (Exception e){
e.printStackTrace();
}
}
}
void pausePlaying(){
if (mediaPlayer != null) mediaPlayer.pause();
}
but still same behaviour.
Some insight I got:
before the user place the activity in the background the member mediaPlayer is some constructed android object.
when the activity returns to the foregound mediaPlayer is null.
Why is this?
Maybe I got wrong the idea of activity but I thought it keeps its members with their values during its life cycle.
Your are creating and destroying your mediaplayer everytime. Try to create two methods for pause and resume/start like that.
below you can find the code that is working fine for me. I am developing a game that starts a main theme when the activity loads. Each time the activity resumes, the media player continue to play the song at the paused position. I override onDestroy() to stop, onResume to start/resume and onPause() to pause when the activity goes Background.
public MediaPlayer mp=null;
#Override
protected void onDestroy() {
if (mp!=null)
mp.stop();
super.onStop();
}
#Override
protected void onResume() {
super.onResume();
if (mp==null){
self=this;
Thread thMusic= new Thread(new Runnable(){
public void run(){
mp= MediaPlayer.create(self,R.raw.dizzy );
mp.start();
}
});
thMusic.start();
}
else
mp.start();
}
#Override
protected void onPause() {
if (mp!=null)
mp.pause();
super.onPause();
}
i hope this will help you.
http://developer.android.com/guide/components/activities.html
Saving activity state gives a detailed information that could explain what happened.
In short when activity is in the background it might be killed and created again by OS when user navigate it back to foreground.
onSaveInstanceState() should be implemented unless only UI objects are restored
but not class members
Related
I am making a chat application and I have implemented the feature for sending audio messages.But here I find one thing which I don't want it to happen.It is that whenever my adapter gets updated,The media player starts loading again. In this way there will be an issue for if someone is listening to an audio and the user at other end sends a message ,the media player stops and it loads again.Here is the code of my adapter.
final MediaPlayer mediaPlayer;
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
handler = new Handler();
try {
mediaPlayer.setOnCompletionListener(mediaPlayer1 -> {
mediaPlayer1.stop();
binding.audioSeekbar.setProgress(0);
});
if (mediaPlayer.isPlaying()){
mediaPlayer.stop();
mediaPlayer.release();
}
mediaPlayer.setDataSource(finalUrlToLoad[1]);
mediaPlayer.setVolume(1f, 1f);
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(mediaPlayer1 -> {
int totalDuration = mediaPlayer1.getDuration();
binding.totalDurationAudio.setText(createTimeLabel(totalDuration));
binding.loadingAudio.setVisibility(GONE);
binding.playPauseAudio.setVisibility(VISIBLE);
});
} catch (IOException e) {e.printStackTrace();}
binding.playPauseAudio.setOnClickListener(view -> {
if (mediaPlayer.isPlaying()){
handler.removeCallbacks(runnable);
mediaPlayer.pause();
binding.playPauseAudio.setImageResource(R.drawable.pause_to_play);
Drawable drawable = binding.playPauseAudio.getDrawable();
if( drawable instanceof AnimatedVectorDrawable) {
AnimatedVectorDrawable animation = (AnimatedVectorDrawable) drawable;
animation.start();
}
}else {
mediaPlayer.seekTo(binding.audioSeekbar.getProgress());
mediaPlayer.start();
handler.post(runnable);
binding.playPauseAudio.setImageResource(R.drawable.play_to_pause);
Drawable drawable = binding.playPauseAudio.getDrawable();
if( drawable instanceof AnimatedVectorDrawable) {
AnimatedVectorDrawable animation = (AnimatedVectorDrawable) drawable;
animation.start();
}
}
});
runnable = () -> {
int totalTime = mediaPlayer.getDuration();
binding.audioSeekbar.setMax(totalTime);
int currentPosition = mediaPlayer.getCurrentPosition();
binding.audioSeekbar.setProgress(currentPosition);
binding.totalDurationAudio.setText(createTimeLabel(totalTime));
Log.d("time", String.valueOf(currentPosition));
handler.postDelayed(runnable,1000);
};
binding.audioSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
if (b){
mediaPlayer.seekTo(i);
seekBar.setProgress(i);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
mediaPlayer.setOnBufferingUpdateListener((mediaPlayer1, i) -> binding.audioSeekbar.setSecondaryProgress(i));
Here finalurltoload[1] is the url for the audio.
Now what do I need to do in order to prevent loading it again and again.
I will be really grateful to who answer this question.
Thanks😊.
It's hard to tell from this code but I assume this is all set in your onBind event? If so, then this means every time RecyclerView creates a new holder and binds it, the associated media will be prepped and loaded, and whichever is the 'last holder to have been called with onBind, "wins" (and is what MediaPlayer will be loaded with). Since by default RecyclerView typically creates multiple holders up front, you are seeing your MediaPlayer being "loaded" multiple times.
You probably just don't want to do the initialization of each audio message in the onBind. Instead, just use the onBind event to initialize state variables (duration, progress, etc.) to some default value, hide them and bind the specific audio Uri. Then when the user takes some action like tapping on the holder, you unhide an indeterminate progress bar while the initialization takes place, and in the onPrepared() event unhide the state information (duration, progress, seekbar, etc.), and finally hide the indeterminate progress bar and start the audio.
I assume you are also sending over the sound file as part of your messaging app (i.e. not storing it on the web somewhere in a central location?), and this file gets stored in an app-specific storage location? If so, you don't need to worry about persisting the permission to that URI, but if that isn't the case you will.
First extract the media player code into singleton class like AudioManager.
Add few method like setMediaUpdateListener that set a callback for seek duration. and togglePlayPause to play or pause the audio.
Passed the message id or any unique identifier to the audio manager while playing the video.
In Adapter class onBind Method.
First Compare the id and playing Id is same like AudioManager.getInstance().isPlaying(messageId);
If yes then set the seekUpdatelistner to the audio manager class.
also update the play/pause icon based on AudioManager.isPlaying() method.
3.if user play other message by clicking play button. call AudioManager.play(message) method.In which we release the previous message and play the new one.
If current message is not playing then reset the view on non-playing state.
If Auto play is enabled then you need to check if audioManager is free then only you can play the last message otherwise ignored.
Like a class who are managing the audio for you and store all the state.
class AudioManager {
public static AudioManager instance;
final MediaPlayer mediaPlayer;
private AudioListener audioListener;
private Uri currentPlaying;
public AudioManager getInstance() {
if (instance == null) {
instance = new AudioManager();
}
}
public void play(Uri dataUri) {
if (mediaPlayer != null && currentPlaying == null || currentPlaying.equals(dataUri)) {
if (!mediaPlayer.isPlaying) {
mediaPlayer.play();
}
return;
} else if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
handler = new Handler();
try {
mediaPlayer.setOnCompletionListener(mediaPlayer1 -> {
mediaPlayer1.stop();
sendProgress(0);
});
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
}
mediaPlayer.setDataSource(dataUri;
mediaPlayer.setVolume(1f, 1f);
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(mediaPlayer1 -> {
int totalDuration = mediaPlayer1.getDuration();
sendTotalDuration(totalDuration);
});
} catch (IOException e) {
e.printStackTrace();
}
}
public void pause() {
// update the pause code.
}
public void sendProgress(int progress) {
if (audioListener != null) {
audioListener.onProgress(progress);
}
}
public void sendTotalDuration(int duration) {
if (audioListener != null) {
audioListener.onTotalDuraration(duration);
}
}
public void AudioListener(AudioListener audioListener) {
this.audioListener = audioListener;
}
public interface AudioListener {
void onProgress(int progress);
void onTotalDuraration(int duration);
void onAudioPlayed();
void onAudioPaused():
}
}
Hello StackOverflow's users,
I'm developing a Music Player App for android. In my main activity when the user clicks on a song I start a new intent that displays PlayerActivity. In there, I initialize a MediaPlayer and all the other UI elements. When the user clicks the back button, I bring them back to the main activity and the song continues to play in the background. The same thing happens if they exit the application. Now I was wondering if it's fine to do something like this or if I should instead start a new Service for the MediaPlayer from the PlayerActivity class instead of doing it in there.
PlayerActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_player);
Bundle extras = getIntent().getExtras();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(getResources().getColor(R.color.colorPrimaryDark));
getWindow().setNavigationBarColor(getResources().getColor(R.color.colorPrimaryDark));
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
getWindow().setNavigationBarDividerColor(getResources().getColor(R.color.white));
}
playBtn = findViewById(R.id.btn_play);
artImage = findViewById(R.id.art);
remainingTimeLabel = findViewById(R.id.current_song_duration);
totalTimeLabel = findViewById(R.id.total_duration);
manager = MainActivity.getManager();
Song song = manager.getCurrentSong();
boolean wasCall = extras != null && extras.containsKey("call");
if (!wasCall && manager.hasStarted()) {
MediaPlayer mediaPlayer = manager.getMediaPlayer();
mediaPlayer.pause();
mediaPlayer.stop();
}
if (!wasCall) {
mp = MediaPlayer.create(this, Uri.parse(song.getPath()));
mp.setLooping(true);
mp.seekTo(0);
mp.setVolume(0.5f, 0.5f);
} else {
mp = manager.getMediaPlayer();
mp.setLooping(true);
mp.setVolume(0.5f, 0.5f);
}
totalTime = mp.getDuration();
artImage.setImageBitmap(Bitmap.createScaledBitmap(song.getIcon(), 250, 250, true));
totalTimeLabel.setText(createTimeLabel(totalTime));
songName = findViewById(R.id.songName);
songName.setText(song.getName());
songAuthor = findViewById(R.id.songAuthor);
songAuthor.setText(song.getArtist());
Toolbar toolbar = findViewById(R.id.player_top_bar);
toolbar.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark));
setSupportActionBar(toolbar);
assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
assert toolbar.getNavigationIcon() != null;
toolbar.getNavigationIcon().setColorFilter(getResources().getColor(R.color.white), PorterDuff.Mode.SRC_ATOP);
getSupportActionBar().setTitle(Html.fromHtml("<font color='#ffffff'>MySound</font>"));
positionBar = findViewById(R.id.seek_song_progressbar);
positionBar.setMax(totalTime);
positionBar.setOnSeekBarChangeListener(
new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
mp.seekTo(progress);
positionBar.setProgress(progress);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
}
);
LinearLayout layout = findViewById(R.id.player_control);
layout.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark));
new Thread(() -> {
while (mp != null) {
try {
Message msg = new Message();
msg.what = mp.getCurrentPosition();
handler.sendMessage(msg);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
this.action = SongEndAction.REPEAT;
mp.start();
manager.setMediaPlayer(mp);
}
Here is a Music Service that I implemented in my book.
https://github.com/Wickapps/Practical-Android-MusicService
This implementation includes play, stop, and seek forward, but you could add other functions.
Service is the best architecture for future scalability.
There is a MainActivity.java which starts the service.
MusicService.java is the service implementation.
Hope this helps.
If you want your app to keep playing audio while it's in background ( like spotify ), then yes, it is a must to use a foreground service.
Unfortunately it's more complex than your current implementation.
This is a nice starting point : https://developer.android.com/guide/topics/media-apps/audio-app/building-an-audio-app
I am very new to android just started with Android currently referring the below code from past 2 days, not able to fix the issue.
Code:
https://github.com/quocnguyenvan/media-player-demo
Issue: Let's say we 4 Songs in the ListView when we click on the first song play it for some time and pause it without clicking on stop.
As soon as we click on the second song the first song starts playing we cannot play the second song unless we click on stop of the first song How to solve this issue.
The issue with code not able to figure out and fix it.I have referred many posts before posting on StackOverflow but could not make it, any suggestion or guidance is highly appreciated.
Problematic code:
// play music
viewHolder.ivPlay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(flag){
mediaPlayer = MediaPlayer.create(context, music.getSong());
flag = false;
}
if(mediaPlayer.isPlaying()) {
mediaPlayer.pause();
viewHolder.ivPlay.setImageResource(R.drawable.ic_play);
} else {
mediaPlayer.start();
viewHolder.ivPlay.setImageResource(R.drawable.ic_pause);
}
}
});
// stop
viewHolder.ivStop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(!flag) {
mediaPlayer.stop();
mediaPlayer.release();
flag = true;
}
viewHolder.ivPlay.setImageResource(R.drawable.ic_play);
}
});
These are the steps I used for playing song you can try to sync with my steps to resolve the error.
private void initMembers() {
//initialize the members here
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
//media prepare
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(final MediaPlayer mediaPlayer) {
//media player prepared
togglePlayPausePlayer();
}
});
//media completion
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(final MediaPlayer mediaPlayer) {
//handle the media play completion
handleOnCompletionLogic();
}
});
}
after that whenever I try to play the song. I call this method.
public void playMusic(final MusicModel musicModel) {
//here play the music with data in below
try {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
}
mMediaPlayer.reset();
mMediaPlayer.setDataSource(musicModel.getUrl());
mMediaPlayer.prepareAsync();
} catch (IOException | IllegalStateException exp) {
exp.printStackTrace();
showMessage(getString(R.string.error_unable_play));
}
}
above resets the playing song and prepare the player for another song.
and OnPreparedListener it calls the togglePlayPausePlayer() which play and pause the song accordingly.
private void togglePlayPausePlayer() {
//here handle the logic for play and pause the player
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.pause();
setPlayAndPause(false);
} else {
mMediaPlayer.start();
setPlayAndPause(true);
}
}
The key is we initialize the player and set an onPrepareListener for the media player to get prepared and then play the song, which will check if it's playing then it will stop and else it will play.
hope this may help you.
For on click on ListView you need to reset the media player, change the data source and start playing with new song.
mp.reset();
mp.setDataSource("song you selected from ListView");
mp.prepare();
mp.start();
I'm developing an android app and i'm using NavigationDrawer, there is only one activity (MainActivity) and Fragments.
I have a radio live stream button on the ActionBar so i made an object of MediaPlayer in the MainActivity for the live stream button and it's working fine, now i have some sound files in one of the fragments, i want to get the mediaPlayer object that i made in the MainActivity in order to use it. Note that the live stream button is always visible at the top of the application so if i'm in a fragment that has a sound file i want to be able to listen to the sound file and if i clicked on the live stream button the sound file will be paused and live stream will be on.
Here's my code:
This is MainActivity (only the relative part):
public class MainActivity extends ActionBarActivity {
private static final String RADIO_STREAM_URL= "http://198.178.123.23:8662/stream/1/;listen.mp3";
MediaPlayer mediaPlayer;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mediaPlayer.setDataSource(RADIO_STREAM_URL);
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item != null )
{
if(item.getItemId() == android.R.id.home){
if (mDrawerLayout.isDrawerOpen(Gravity.END)){
mDrawerLayout.closeDrawer(Gravity.END);
} else {
mDrawerLayout.openDrawer(Gravity.END);
}
}else if(item.getItemId() == R.id.action_settings){
try {
mediaPlayer.prepareAsync();
} catch (IllegalStateException e) {
e.printStackTrace();
}
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
if(mediaPlayer.isPlaying()){
mediaPlayer.stop();
Log.e("ANA Radio","was playing");
}else{
Log.e("ANA Radio","was not playing");
mediaPlayer.start();
}
}
});
}
}
return false;
}
Now how to get the mediaPlayer object in a Fragment ?
Here try this:
In your fragment you can write the code below to get the MediaPlayer object:
((MainActivity)getActivity()).mediaPlayer
Another solution is that, you make your mediaPlayer a member of a class. To do that go like this:
public static MediaPlayer mediaPlayer;
I have an Activity named PhotoSelectorActivity. It inherits from a BaseActivity that looks like this:
public class BaseActivity
extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(this.getClass().getSimpleName(),
"onCreate("+Integer.toHexString(System.identityHashCode(this))+")");
}
#Override
protected void onDestroy() {
super.onDestroy();
getSupportActionBar().setCustomView(null);
Log.d(this.getClass().getSimpleName(),
"onDestroy("+Integer.toHexString(System.identityHashCode(this))+")");
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
return onNavigateUp(item);
case R.id.menu_item_settings:
startActivity(new Intent(this, PreferencesActivity.class));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
protected ActionBar setupActionBar(boolean enableBackButton) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
getSupportActionBar().setDisplayHomeAsUpEnabled(enableBackButton);
}
ActionBar actionBar = getSupportActionBar();
actionBar.setCustomView(R.layout.action_bar);
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setDisplayShowCustomEnabled(true);
return null;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
The purpose of this BaseActivity is to provide the same menu and actionbar to each one of my activities. You'll notice the getSupportActionBar().setCustomView(null) in the onDestroy() method, that's there to try and combat the problem that I may be having.
When i get an orientation change event, i notice in DDMS that i end up with 2 instances of my activity. One of them may be leaking, but I'm not certain. Here's a screen shot from DDMS:
So the object at the top is the Activity in question: PhotoSelectorActivity. The instance shown here is the previous instance (onDestroy() has already been called on it). Yet it remains in memory even after a forced GC via DDMS.
Another bit of information is that this only seems to happen after using a dialog. That is, when the Activity is initially displayed and before the user performs and action I can do back to back orientation changes without the # of activities climbing above 1. After I've used the following dialog i seem to get the extra Activity in memory:
public class PhotoSourceDialog
extends DialogFragment
implements DialogInterface.OnClickListener {
public static interface PhotoSourceDialogListener {
void onPhotoSourceSelected(String result);
}
private PhotoSourceDialogListener listener;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (!PhotoSourceDialogListener.class.isInstance(activity)) {
throw new IllegalStateException(
"Activity must implement PhotoSourceDialogListener");
}
listener = PhotoSourceDialogListener.class.cast(activity);
}
#Override
public void onDetach() {
super.onDetach();
listener = null;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setTitle(R.string.photo_source)
.setItems(R.array.photo_sources, this).create();
}
#Override
public void onClick(DialogInterface dialog, int which) {
String choice = getResources().getStringArray(
R.array.photo_sources)[which];
if (listener!=null) {
listener.onPhotoSourceSelected(choice);
}
}
}
and to invoke it i do this in my activity:
PhotoSourceDialog dialog = new PhotoSourceDialog();
dialog.show(getSupportFragmentManager(), PhotoSourceDialog.class.getName());
So my question is this: Should I be worried? Is this just something that is hanging around for a bit but will eventually be GCd? I would think that if there was a leak it would grow higher than 2.
I'm closing this question. Someone at google has responded with the following:
OK, in that case then it's not an AppCompat bug since the standard
Action Bar implementation is used on ICS+.
Looking at that MAT screenshot, the framework's ActionMenuItemView is
being referenced from a clipboard event which is being finalized,
hence about to be GC'd. The LayoutInflater is probably the
LayoutInflater that the Activity keeps itself (getLayoutInflater()).