MainActivity
这是我的主要布局并启动了服务连接。
public class MainActivity extends AppCompatActivity implements Tab1.OnFragmentInteractionListener, Tab2.OnFragmentInteractionListener,
Tab3.OnFragmentInteractionListener, Tab4.OnFragmentInteractionListener, Tab5.OnFragmentInteractionListener {
public static List<QuerySongs> songList = new ArrayList<>();
private RelativeLayout mainLayout;
private TabsAdapter tabsAdapter;
private Toolbar mToolbar;
private TabLayout tabLayout;
private ViewPager viewPager;
public static ServiceConnection serviceConnection;
public static MediaPlayerService player;
public static boolean serviceBound = false;
private SharedPreferences mSharedPreferences;
private SharedPreferences.Editor mEditor;
private final String TAG = this.getClass().getName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
mSharedPreferences = getSharedPreferences("Background", Context.MODE_PRIVATE);
//RelativeLayouts
mainLayout = findViewById(R.id.mainLayout);
//ToolBar
mToolbar = findViewById(R.id.mToolbar);
setSupportActionBar(mToolbar);
if (getSupportActionBar() != null) {
getSupportActionBar().setTitle(R.string.library);
}
//Method call permission
checkUserPermission();
//TabLayout
tabLayout = findViewById(R.id.tabLayout);
tabLayout.addTab(tabLayout.newTab().setText("Songs"));
tabLayout.addTab(tabLayout.newTab().setText("Albums"));
tabLayout.addTab(tabLayout.newTab().setText("Artists"));
tabLayout.addTab(tabLayout.newTab().setText("Genres"));
tabLayout.addTab(tabLayout.newTab().setText("Playlist"));
tabLayout.setTabGravity(TabLayout.MODE_FIXED);
viewPager = findViewById(R.id.viewPager);
tabsAdapter = new TabsAdapter(getSupportFragmentManager(), tabLayout.getTabCount());
viewPager.setAdapter(tabsAdapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// We've bound to Service, cast the IBinder and get Service instance
MediaPlayerService.LocalBinder binder = (MediaPlayerService.LocalBinder) service;
player = binder.getService();
serviceBound = true;
Log.i(TAG, "Service connected!");
}
@Override
public void onServiceDisconnected(ComponentName name) {
serviceBound = false;
Log.i(TAG, "Service disconnected!");
}
};
}
@Override
public void onFragmentInteraction(Uri uri) {
}
@Override
protected void onDestroy() {
super.onDestroy();
if (serviceBound){
unbindService(serviceConnection);
player.stopSelf();
}
}
}
片段1
在这个片段中,我显示了使用内容解析器(getSongs方法)在sd卡上获取的所有歌曲,并将其添加到名为“歌曲列表”的歌词中。 使用recyclerview上的OnItemClickListener我得到位置,然后我用它来播放列表中的歌曲(playAudio方法)
playAudio方法将ArrayList songList和songIndex存储在我的StorageUtil类中。
public class Tab1 extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
public static final String broadCast_PlAY_NEW_SONG = "com.vince_mp3player.PlayNewSong";
private RecyclerView recyclerView;
private SongAdapter songAdapter;
private RelativeLayout activeSong;
private List<QuerySongs> songList = new ArrayList<>();
private TextView tvCurrSongTitle, tvCurrSongArtist;
private ImageView albumIvBottom;
private int songIndex;
private final String TAG = this.getClass().getName();
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public Tab1() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment Tab1.
*/
// TODO: Rename and change types and number of parameters
public static Tab1 newInstance(String param1, String param2) {
Tab1 fragment = new Tab1();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
//Method call show list all songs
getSongs();
//Sort songs
Collections.sort(songList, new Comparator<QuerySongs>() {
public int compare(QuerySongs a, QuerySongs b) {
return a.getTitle().compareTo(b.getTitle());
}
});
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_tab1, container,false);
recyclerView = rootView.findViewById(R.id.recyclerView);
//SongAdapter
songAdapter = new SongAdapter(getContext(), songList);
songAdapter.notifyDataSetChanged();
if (recyclerView != null) {
recyclerView.setHasFixedSize(true);
}
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
//DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), linearLayoutManager.getOrientation());
//RecyclerView
recyclerView.setAdapter(songAdapter);
recyclerView.setLayoutManager(linearLayoutManager);
//recyclerView.addItemDecoration(dividerItemDecoration);
//??
recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
activeSong = rootView.findViewById(R.id.activeSong);
albumIvBottom = rootView.findViewById(R.id.albumIvBottom);
tvCurrSongTitle = rootView.findViewById(R.id.tvCurrSongTitle);
tvCurrSongArtist = rootView.findViewById(R.id.tvCurrSongArtist);
recyclerView.addOnItemTouchListener(new OnItemClickListeners(getContext(), new OnItemClickListeners.OnItemClickListener() {
@TargetApi(Build.VERSION_CODES.O)
@Override
public void onItemClick(View view, int position) {
songIndex = position;
playAudio(songIndex);
Toast.makeText(getContext(), "You Clicked position: " + songIndex + " " + songList.get(songIndex).getData(), Toast.LENGTH_SHORT).show();
//Fetch current song details
tvCurrSongTitle.setText(songList.get(songIndex).getTitle());
tvCurrSongArtist.setText(songList.get(songIndex).getArtist());
//Fetch album art activeSong
loadAlbumArtBottom();
}
}));
activeSong.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent activeSong = new Intent(getContext(), SongActivity.class);
startActivity(activeSong);
}
});
return rootView;
}
private void playAudio(int songIndex) {
//Check if service is active
if (!serviceBound) {
StorageUtil storageUtil = new StorageUtil(getContext());
storageUtil.storeSong(songList);
storageUtil.storeSongIndex(songIndex);
Intent playerIntent = new Intent(getContext(), MediaPlayerService.class);
getActivity().startService(playerIntent);
getActivity().bindService(playerIntent, serviceConnection, Context.BIND_AUTO_CREATE);
} else {
//Store new songIndex in mSharedPreferences
StorageUtil storageUtil = new StorageUtil(getContext());
storageUtil.storeSongIndex(songIndex);
//Service is active
//Send media with BroadcastReceiver
Intent broadCastReceiverIntent = new Intent(broadCast_PlAY_NEW_SONG);
getActivity().sendBroadcast(broadCastReceiverIntent);
}
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
outState.putBoolean("ServiceState", serviceBound);
super.onSaveInstanceState(outState);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
serviceBound = savedInstanceState.getBoolean("ServiceState");
}
}
private void loadAlbumArtBottom(){
Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
Uri albumArtUri = ContentUris.withAppendedId(sArtworkUri, songList.get(songIndex).getAlbumId());
Picasso.with(getContext())
.load(albumArtUri)
.placeholder(R.drawable.no_album)
.error(R.drawable.no_album)
.resize(220, 220)
.centerCrop()
.into(albumIvBottom);
}
//Store song info in ArrayList
@TargetApi(Build.VERSION_CODES.O)
private void getSongs() {
final Uri songUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String selection = MediaStore.Audio.Media.IS_MUSIC + "=1";
Cursor myCursor = getActivity().getContentResolver().query(songUri, null, selection, null, null);
if (myCursor != null && myCursor.moveToFirst()) {
int id_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID);
int albumId_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID);
int album_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM);
int data_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
int title_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE);
int artist_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST);
do {
Integer songId = myCursor.getInt(id_Column);
Integer albumId = myCursor.getInt(albumId_Column);
String album = myCursor.getString(album_Column);
String songData = myCursor.getString(data_Column);
String songName = myCursor.getString(title_Column);
String songArtist = myCursor.getString(artist_Column);
QuerySongs querySongs = new QuerySongs(songId, albumId, album, songData, songName, songArtist);
songList.add(querySongs);
} while (myCursor.moveToNext());
myCursor.close();
}
}
}
片段2
在这个片段中,我显示了歌曲中的所有专辑封面,当我点击专辑封面时,它会转到另一个名为AlbumActivity的活动,其中显示该特定专辑中的所有歌曲。
public class Tab2 extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private RecyclerView recyclerViewAlbums;
private AlbumAdapter albumAdapter;
private List<QueryAlbums> albumList = new ArrayList<>();
private int albumIndex;
private final String TAG = this.getClass().getName();
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public Tab2() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment Tab2.
*/
// TODO: Rename and change types and number of parameters
public static Tab2 newInstance(String param1, String param2) {
Tab2 fragment = new Tab2();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
getAlbums();
//Sort songs NOT WORKING !
/* Collections.sort(albumList, new Comparator<QueryAlbums>() {
public int compare(QueryAlbums a, QueryAlbums b) {
return a.getAlbumName().compareTo(b.getAlbumName());
}
}); */
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_tab2, container,false);
recyclerViewAlbums = rootView.findViewById(R.id.recyclerViewAlbums);
//AlbumAdapter
albumAdapter = new AlbumAdapter(getContext(), albumList);
albumAdapter.notifyDataSetChanged();
if (recyclerViewAlbums != null){
recyclerViewAlbums.setHasFixedSize(true);
}
int noOfColumns = Utilities.calculateNoOfColumns(getContext());
final GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), noOfColumns);
recyclerViewAlbums.setAdapter(albumAdapter);
recyclerViewAlbums.setLayoutManager(gridLayoutManager);
recyclerViewAlbums.addOnItemTouchListener(new OnItemClickListeners(getContext(), new OnItemClickListeners.OnItemClickListener() {
@TargetApi(Build.VERSION_CODES.O)
@Override
public void onItemClick(View view, int position) {
albumIndex = position;
Toast.makeText(getContext(), "You Clicked position: " + albumIndex + " " + albumList.get(albumIndex).getAlbumName() + " "
+ albumList.get(position).getAlbumid(), Toast.LENGTH_SHORT).show();
Intent selectedAlbum = new Intent(getContext(), AlbumActivity.class);
selectedAlbum.putExtra("albumIndex", albumIndex);
startActivity(selectedAlbum);
}
}));
return rootView;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
//Store album info in ArrayList
@TargetApi(Build.VERSION_CODES.O)
private void getAlbums() {
final Uri songUri = MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI;
Cursor myCursor = getActivity().getContentResolver().query(songUri, null, null, null, null);
if (myCursor != null && myCursor.moveToFirst()) {
int id_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Albums._ID); //Get column ALBUM ID
int album_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM); //Get column ALBUM NAME
int artist_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ARTIST); //Get column ALBUM ARTIST
int tracks_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.NUMBER_OF_SONGS); //Get column NUMBER OF SONGS IN ALBUM
String temp = myCursor.getString(album_Column);
do {
int albumId = myCursor.getInt(id_Column);
String album = myCursor.getString(album_Column);
String albumArtist = myCursor.getString(artist_Column);
int tracks = myCursor.getInt(tracks_Column);
if (!temp.equals(album)) {
QueryAlbums queryAlbums = new QueryAlbums(albumId, album, albumArtist, tracks);
albumList.add(queryAlbums);
}
temp = album;
} while (myCursor.moveToNext());
myCursor.close();
}
}
}
AlbumActivity
public class AlbumActivity extends AppCompatActivity {
public static final String broadCast_PlAY_NEW_SONG = "com.vince_mp3player.PlayNewSong";
private List<QuerySongs> songList = new ArrayList<>();
private List<QueryAlbums> albumList = new ArrayList<>();
private RecyclerView recyclerViewAlbum;
private SongAdapter songAdapter;
private Bundle bundle;
private int songIndex;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_album);
recyclerViewAlbum = findViewById(R.id.recyclerViewAlbum);
//AlbumAdapter
songAdapter = new SongAdapter(getApplicationContext(), songList);
songAdapter.notifyDataSetChanged();
if (recyclerViewAlbum != null){
recyclerViewAlbum.setHasFixedSize(true);
}
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerViewAlbum.setAdapter(songAdapter);
recyclerViewAlbum.setLayoutManager(linearLayoutManager);
getAlbums();
getSongsFromAlbum();
//Sort songs
Collections.sort(albumList, new Comparator<QueryAlbums>() {
public int compare(QueryAlbums a, QueryAlbums b) {
return a.getAlbumName().compareTo(b.getAlbumName());
}
});
recyclerViewAlbum.addOnItemTouchListener(new OnItemClickListeners(getApplicationContext(), new OnItemClickListeners.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
songIndex = position;
Toast.makeText(getApplicationContext(), "Clicked: " + position, Toast.LENGTH_SHORT).show();
playAudio(songIndex);
}
}));
}
private void playAudio(int songIndex) {
//Check if service is active
if (!serviceBound) {
StorageUtil storageUtil = new StorageUtil(getApplicationContext());
storageUtil.storeSong(songList);
storageUtil.storeSongIndex(songIndex);
Intent playerIntent = new Intent(getApplicationContext(), MediaPlayerService.class);
startService(playerIntent);
bindService(playerIntent, serviceConnection, Context.BIND_AUTO_CREATE);
} else {
//Store new songIndex in mSharedPreferences
StorageUtil storageUtil = new StorageUtil(getApplicationContext());
storageUtil.storeSongIndex(songIndex);
//Service is active
//Send media with BroadcastReceiver
Intent broadCastReceiverIntent = new Intent(broadCast_PlAY_NEW_SONG);
sendBroadcast(broadCastReceiverIntent);
}
}
//Store album info in ArrayList
@TargetApi(Build.VERSION_CODES.O)
private void getAlbums() {
final Uri songUri = MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI;
Cursor myCursor = getContentResolver().query(songUri, null, null, null, null);
if (myCursor != null && myCursor.moveToFirst()) {
int id_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Albums._ID); //Get column ALBUM ID
int album_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM); //Get column ALBUM NAME
int artist_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ARTIST); //Get column ALBUM ARTIST
int tracks_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.NUMBER_OF_SONGS); //Get column NUMBER OF SONGS IN ALBUM
String temp = myCursor.getString(album_Column);
do {
int albumId = myCursor.getInt(id_Column);
String album = myCursor.getString(album_Column);
String albumArtist = myCursor.getString(artist_Column);
int tracks = myCursor.getInt(tracks_Column);
if (!temp.equals(album)) {
QueryAlbums queryAlbums = new QueryAlbums(albumId, album, albumArtist, tracks);
albumList.add(queryAlbums);
}
temp = album;
} while (myCursor.moveToNext());
myCursor.close();
}
}
private void getSongsFromAlbum() {
final Uri songUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
bundle = getIntent().getExtras();
int albumIndex = bundle.getInt("albumIndex");
String selection = MediaStore.Audio.Media.ALBUM + "=?";
String songAlbum[] = { albumList.get(albumIndex).getAlbumName() };
Cursor myCursor = getContentResolver().query(songUri, null, selection, songAlbum, null);
if (myCursor != null && myCursor.moveToFirst()) {
int id_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID);
int albumId_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID);
int album_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM);
int data_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
int title_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE);
int artist_Column = myCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST);
do {
int songId = myCursor.getInt(id_Column);
int albumId = myCursor.getInt(albumId_Column);
String album = myCursor.getString(album_Column);
String songData = myCursor.getString(data_Column);
String songName = myCursor.getString(title_Column);
String songArtist = myCursor.getString(artist_Column);
QuerySongs querySongs = new QuerySongs(songId, albumId, album, songData, songName, songArtist);
songList.add(querySongs);
} while (myCursor.moveToNext());
myCursor.close();
}
}
}
问题
当我参加此活动并播放所选专辑中的歌曲,然后点击后退按钮时,我在logcat中收到此错误;
活动com.vince_mp3player.mp3player.activities.AlbumActivity泄露了最初绑定在这里的ServiceConnection com.vince_mp3player.mp3player.activities.MainActivity$2@84cb73f android.app.ServiceConnectionLeaked:Activity com.vince_mp3player.mp3player.activities.AlbumActivity泄露了最初绑定的ServiceConnection com.vince_mp3player.mp3player.activities.MainActivity$2@84cb73f
很抱歉这么多的文字和代码,但提前感谢,
文斯