Reputation: 372
I am working on a music player. There are two activities. The first activity is a ViewPager
which contains four fragments (All songs, Playlist, Albums and Artist). The other Activity
is used to list the songs of a particular playlist. Everything works fine when playing music from the first fragment (i.e. all songs) in the ViewPager
. Now when I open a playlist from the second fragment it opens up the new Activity
listing the songs in that playlist. When I click to play, it plays fine. However, when I go back to the previous activity (i.e. ViewPager
) and I try to play a song in the 1st fragment (i.e. all songs), it plays the song from the predecessor playlist which is from the previous Activity
. It seems like the Fragment
loses its focus despite it been visible and its RecyclerView
click doesn't work. It works for the previous, maybe because it uses the same adapter class for their RecyclerView
. I don't know what am I doing wrong here. Please help.
This is my ViewPager code.
public class Home extends AppCompatActivity {
ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
Intent service = new Intent(this, MyMusicPlayerService.class);
bindService(service, serviceConnection, Context.BIND_AUTO_CREATE);
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = new MyMusic();
break;
case 1:
fragment = new PlayList();
break;
case 2:
fragment = new Albums();
break;
case 3:
fragment = new Artist();
break;
}
return fragment;
}
@Override
public int getCount() {
return 4;
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return getResources().getString(R.string.title1);
case 1:
return getResources().getString(R.string.title2);
case 2:
return getResources().getString(R.string.title3);
case 3:
return getResources().getString(R.string.title4);
}
return null;
}
}
}
The All Songs Fragment: I am writing the onCreateView()
method first fragment of the ViewPager
.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_my_music, container, false);
storage = new Storage(getActivity());
rvAdapter = new RVAdapter(musics, getActivity(), "all");
layoutManager = new LinearLayoutManager(getActivity());
recycler = (RecyclerView) view.findViewById(R.id.recycler);
recycler.setLayoutManager(layoutManager);
rvAdapter.setOnItemClickListener(new RVAdapter.OnRvItemClickListener() {
@Override
public void onRvItemClickListener(ArrayList<String> data, int position) {
storage.storeSongs(musics); //stores all musics of the current list in an Array, in case of next and prev
mListener.onFragmentInteraction(position);
}
});
rvAdapter.setOnOptionClickListener(new RVAdapter.OnOptionClickListener() {
@Override
public void onOptionClick(String mode, ArrayList<String> data) {
processOption(mode, data);
}
});
populate(); // function to populate recyclerview
recycler.setAdapter(rvAdapter);
return view;
}
Second Activity: This is the onCreate()
method for the second activity that lists the song of a particular playlist opened from the 2nd tab(Playlist) in the first activity.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_song);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
LocalBroadcastManager.getInstance(this).registerReceiver(updateReceiver, new IntentFilter(Constants.ACTION.PLAY_INFO));
storage = new Storage(this);
playinfo = (CardView) findViewById(R.id.playinfo);
prev = (ImageView) findViewById(R.id.prev);
playpause = (ImageView) findViewById(R.id.playpause);
fwd = (ImageView) findViewById(R.id.fwd);
title = (TextView) findViewById(R.id.title);
artist = (TextView) findViewById(R.id.artist);
playinfo.setOnClickListener(this);
prev.setOnClickListener(this);
playpause.setOnClickListener(this);
fwd.setOnClickListener(this);
layoutManager = new LinearLayoutManager(this);
recycler = (RecyclerView) findViewById(R.id.recycler);
recycler.setItemAnimator(new DefaultItemAnimator());
recycler.setLayoutManager(layoutManager);
empty = (TextView) findViewById(R.id.empty);
rvAdapter.setOnItemClickListener(new RVAdapter.OnRvItemClickListener() {
@Override
public void onRvItemClickListener(ArrayList<String> data, int position) {
storage.storeSongs(musics); //stores all musics of the current list in an Array, in case of next and prev
Intent intent = new Intent(Constants.ACTION.PLAY_INFO);
intent.putExtra("title", data.get(0));
intent.putExtra("artist", data.get(1));
intent.putExtra("playStatus", "play");
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
storage.storeAudioIndex(position);
Intent intent2 = new Intent(getBaseContext(), MyMusicPlayerService.class);
intent2.setAction(Constants.ACTION.STARTFOREGROUND_ACTION);
startService(intent2);//play music
updateBottom();
}
});
rvAdapter.setOnOptionClickListener(new RVAdapter.OnOptionClickListener() {
@Override
public void onOptionClick(String mode, ArrayList<String> data) {
processOption(mode, data);
}
});
recycler.setAdapter(rvAdapter);
}
Upvotes: 1
Views: 1591
Reputation: 24211
This is too board to answer. However, I thought I could give you an insight of the solution to your problem and hence I am writing an answer.
From my understanding the Home
activity hosts the four Fragment
in a ViewPager
. All of these four fragments contain RecyclerView
to list different things. But hence clicking on any item in the RecyclerView
in any of these four Fragment
brings up the SecondActivity
which contains a list of songs. So as far as I have understood, you can play songs from two different places. One is the first Fragment
in the ViewPager
which is labeled as All Songs and the another one is from the list that you have inside SecondActivity
for all other three Fragment
in the ViewPager
.
Now, I would like to suggest a design flow which will help you to have control over the song that you are playing.
You need to host two Fragment
in your Home
activity. A Fragment
will be ViewPagerContainerFragment
and the other will be the SecondFragment
. Convert your SecondActivity
as the SecondFragment
here and move the ViewPager
related code from your Home
activity to ViewPagerContainerFragment
. By default, set the ViewPagerContainerFragment
in the fragment container of the Home
activity.
Let us have a public function in the Home
activity that hosts these two Fragment
. I am just giving you a sample, please modify the function parameter as per your requirement.
public void playSong (List<Music> musics, int position, ArrayList<String> data) {
storage.storeSongs(musics); //stores all musics of the current list in an Array, in case of next and prev
Intent intent = new Intent(Constants.ACTION.PLAY_INFO);
intent.putExtra("title", data.get(0));
intent.putExtra("artist", data.get(1));
intent.putExtra("playStatus", "play");
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
storage.storeAudioIndex(position);
Intent intent2 = new Intent(getBaseContext(), MyMusicPlayerService.class);
intent2.setAction(Constants.ACTION.STARTFOREGROUND_ACTION);
startService(intent2); //play music
updateBottom();
}
I do not know what you are exactly doing with storage
and the data
, but the idea is to pass necessary parameters to the playSong
function to play the specific song and handle the next and previous song properly from the specific list. It would be great if you could just pass the name of the list and the index of the song from that list in the playSong
function. So that we could play the song from a single place.
Now, as you have wrote the function playSong
perfectly in the Home
activity which handles playing a song and maintains the previous and next song along with the specific list from where the song is playing, our problem is nearly solved. Try to keep a static variable of your Service
intent, so that each time you do not re-initialize the MyMusicPlayerService
class.
The next step will be removing the code for playing a song from everywhere other than the playSong
function that we have now in the Home
activity.
From the AllSongsFragment
modify the click action on RecyclerView
like this.
rvAdapter.setOnItemClickListener(new RVAdapter.OnRvItemClickListener() {
@Override
public void onRvItemClickListener(ArrayList<String> data, int position) {
((Home) getActivity()).playSong(...); // Call the public function that you have declared in Home activity.
mListener.onFragmentInteraction(position);
}
});
And from the SecondFragment
call the playSong()
function in the same manner which will play the song for you.
Another approach
I can think of another approach without changing the SecondActivity
to Fragment
and keeping the current structure. This might be solved using a LocalBroadcastReceiver
. You might consider having a BroadcastReceiver
in your Host
activity and on receiving the broadcast send from the SecondActivity
and AllSongsFragment
it will play the song accordingly from a single place. If you want to have a basic idea on how BroadcastReceiver
works, you may look into my answer here for better understanding. The idea is to play and track the song from a single static place.
Upvotes: 1