Reputation: 250
I am creating a Music Player app that uses Tabbed Fragments. The Player components (the methods that load the file-list and link playback actions to buttons) are set up in a nested Player class that is found within a PlayerFragment class.
I intend to load my app and the first fragment is the Player where a list of files will appear and once a user presses a file in the list, it will play.
Right now, the issue I'm having is that I'm trying to create an instance of Player and then call the method initializeAllComponents() which, as the name suggests, will instantiate the Player class, allowing the Player to appear in the Fragment View and allow the buttons to use their respective methods.
I have searched around and I haven't found an answer that corrects the issue.
When I open the app, the call to initializeAllComponents() causes the app to close immediately.
The app is currently based on the Lite Music API under License, but it will be modified heavily later. That's why the code looks so similar. Right now I just want the Fragment to load correctly and contain a working Music Player before I start reworking the buttons and MediaPlayer methods.
The MainActivity and TabFragment (the FragmentPager class in this case) classes work correctly, so I won't include them. They allow the app to show a tabbed view and load the fragments fine when they don't contain calls inside OnCreateView, but the PlayerFragment will break the app as it is now with a call inside the OnCreateView method.
I also know that the Player class works correctly when it is set up in the Main Activity with no Fragment implementation. So it seems that it must be the call to player.initializeAllComponents() in OnCreateView() that breaks everything, but I don't know why.
Is there a way to call initializeAllComponents() that will inflate the Fragment correctly without error? Am I simply not instantiating the Player subclass correctly? Or is the Player subclass not going to work inside the Fragment?
Any help would be appreciated.
Here is the code:
PlayerFragment.java
import android.content.DialogInterface;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.AppCompatSeekBar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.TextView;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
public class PlayerFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Player.class.getMethods();
Player player = new Player();
player.initializeAllComponents();
return inflater.inflate(R.layout.player_layout, null);
}
class Player extends AppCompatActivity implements MediaPlayer.OnCompletionListener, SeekBar.OnSeekBarChangeListener {
private View parent_view;
private LinearLayout lyt_main;
// playlist
private ListView listview;
private LinearLayout lyt_progress;
private LinearLayout lyt_list;
// player
private Button bt_play;
private Button bt_next;
private Button bt_prev;
private Button btn_repeat;
private Button btn_shuffle;
private AppCompatSeekBar seek_song_progressbar;
private TextView tv_song_title;
private TextView tv_song_current_duration;
private TextView tv_song_total_duration;
// Media Player
private MediaPlayer mp;
// Handler to update UI timer, progress bar etc,.
private Handler mHandler = new Handler();
//private SongsManager songManager;
private MusicUtils utils;
private int currentSongIndex = 0;
private boolean isShuffle = false;
private boolean isRepeat = false;
// the items (songs) we have queried
private ArrayList<MusicItem> mItems = new ArrayList<MusicItem>();
private MusicItem cur_music = null;
private DatabaseHandler db;
public void initializeAllComponents() {
parent_view = findViewById(R.id.main_content);
db = new DatabaseHandler(getApplicationContext());
lyt_main = (LinearLayout) findViewById(R.id.lyt_main);
initPlaylistComponents();
initPlayerComponents();
}
private void initPlayerComponents() {
// All player buttons
bt_play = (Button) findViewById(R.id.bt_play);
bt_next = (Button) findViewById(R.id.bt_next);
bt_prev = (Button) findViewById(R.id.bt_prev);
btn_repeat = (Button) findViewById(R.id.btn_repeat);
btn_shuffle = (Button) findViewById(R.id.btn_shuffle);
seek_song_progressbar = (AppCompatSeekBar) findViewById(R.id.seek_song_progressbar);
tv_song_title = (TextView) findViewById(R.id.tv_song_title);
tv_song_title.setSelected(true);
tv_song_current_duration = (TextView) findViewById(R.id.tv_song_current_duration);
tv_song_total_duration = (TextView) findViewById(R.id.tv_song_total_duration);
// Media Player
mp = new MediaPlayer();
//songManager = new SongsManager();
utils = new MusicUtils();
// Listeners
seek_song_progressbar.setOnSeekBarChangeListener(this); // Important
mp.setOnCompletionListener(this); // Important
// Getting all songs list songsList = songManager.getPlayList();
buttonPlayerAction();
}
private void initPlaylistComponents() {
listview = (ListView) findViewById(R.id.list_main);
lyt_progress = (LinearLayout) findViewById(R.id.lyt_progress);
lyt_list = (LinearLayout) findViewById(R.id.lyt_list);
lyt_progress.setVisibility(View.GONE);
mItems.clear();
mItems = db.getAllMusicFiles();
listview.setAdapter(new MusicFileListAdapter(Player.this, mItems));
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
playSong(mItems.get(arg2));
}
});
}
/**
* Play button click event plays a song and changes button to pause image
* pauses a song and changes button to play image
*/
private void buttonPlayerAction() {
bt_play.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
if (mItems.size() > 0) {
// check for already playing
if (mp.isPlaying()) {
if (mp != null) {
mp.pause();
// Changing button image to play button
bt_play.setBackgroundResource(R.drawable.btn_play);
}
} else {
// Resume song
if (mp != null) {
mp.start();
// Changing button image to pause button
bt_play.setBackgroundResource(R.drawable.btn_pause);
}
}
} else {
Snackbar.make(parent_view, "Song not found", Snackbar.LENGTH_SHORT).show();
}
}
});
/**
* Next button click event
* Plays next song by taking currentSongIndex + 1
* */
bt_next.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// check if next song is there or not
if (currentSongIndex < (mItems.size() - 1)) {
playSong(mItems.get(currentSongIndex + 1));
currentSongIndex = currentSongIndex + 1;
} else {
// play first song
playSong(mItems.get(0));
currentSongIndex = 0;
}
}
});
/**
* Back button click event
* Plays previous song by currentSongIndex - 1
* */
bt_prev.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
if (currentSongIndex > 0) {
playSong(mItems.get(currentSongIndex - 1));
currentSongIndex = currentSongIndex - 1;
} else {
// play last song
playSong(mItems.get(mItems.size() - 1));
currentSongIndex = mItems.size() - 1;
}
}
});
/**
* Button Click event for Repeat button
* Enables repeat flag to true
* */
btn_repeat.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
if (isRepeat) {
isRepeat = false;
Snackbar.make(parent_view, "Repeat is OFF", Snackbar.LENGTH_SHORT).show();
btn_repeat.setBackgroundResource(R.drawable.btn_repeat);
} else {
// make repeat to true
isRepeat = true;
Snackbar.make(parent_view, "Repeat is ON", Snackbar.LENGTH_SHORT).show();
// make shuffle to false
isShuffle = false;
btn_repeat.setBackgroundResource(R.drawable.btn_repeat_focused);
btn_shuffle.setBackgroundResource(R.drawable.btn_shuffle);
}
}
});
/**
* Button Click event for Shuffle button
* Enables shuffle flag to true
* */
btn_shuffle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
if (isShuffle) {
isShuffle = false;
Snackbar.make(parent_view, "Shuffle is OFF", Snackbar.LENGTH_SHORT).show();
btn_shuffle.setBackgroundResource(R.drawable.btn_shuffle);
} else {
// make repeat to true
isShuffle = true;
Snackbar.make(parent_view, "Shuffle is ON", Snackbar.LENGTH_SHORT).show();
// make shuffle to false
isRepeat = false;
btn_shuffle.setBackgroundResource(R.drawable.btn_shuffle_focused);
btn_repeat.setBackgroundResource(R.drawable.btn_repeat);
}
}
});
}
/**
* Function to play a song
*/
public void playSong(MusicItem msc) {
// Play song
try {
mp.reset();
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.setDataSource(getApplicationContext(), msc.getURI());
mp.prepare();
mp.start();
cur_music = msc;
// Displaying Song title
String songTitle = msc.getTitle();
tv_song_title.setText(songTitle);
// Changing Button Image to pause image
bt_play.setBackgroundResource(R.drawable.btn_pause);
// set Progress bar values
seek_song_progressbar.setProgress(0);
seek_song_progressbar.setMax(100);
// Updating progress bar
updateProgressBar();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Update timer on seekbar
*/
public void updateProgressBar() {
mHandler.postDelayed(mUpdateTimeTask, 100);
}
/**
* Background Runnable thread
*/
private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
long totalDuration = mp.getDuration();
long currentDuration = mp.getCurrentPosition();
// Displaying Total Duration time
tv_song_total_duration.setText("" + utils.milliSecondsToTimer(totalDuration));
// Displaying time completed playing
tv_song_current_duration.setText("" + utils.milliSecondsToTimer(currentDuration));
// Updating progress bar
int progress = (int) (utils.getProgressPercentage(currentDuration, totalDuration));
seek_song_progressbar.setProgress(progress);
// Running this thread after 100 milliseconds
mHandler.postDelayed(this, 100);
}
};
public class loadFiles extends AsyncTask<String, String, String> {
MusicRetriever mRetriever;
String status = "success";
public loadFiles() {
mRetriever = new MusicRetriever(getContentResolver());
}
@Override
protected void onPreExecute() {
mItems.clear();
lyt_progress.setVisibility(View.VISIBLE);
lyt_list.setVisibility(View.GONE);
super.onPreExecute();
}
@Override
protected String doInBackground(String... params) {
try {
Thread.sleep(1000);
mRetriever.prepare();
mItems = mRetriever.getAllItem();
status = "success";
} catch (Exception e) {
status = "failed";
}
return null;
}
@Override
protected void onPostExecute(String result) {
if (!status.equals("failed")) {
lyt_progress.setVisibility(View.GONE);
lyt_list.setVisibility(View.VISIBLE);
listview.setAdapter(new MusicFileListAdapter(Player.this, mItems));
//if(musicfiles.size()>0){
db.truncateTableScan();
db.addMusicFiles(mItems);
}
super.onPostExecute(result);
}
}
// 2.0 and above
@Override
public void onBackPressed() {
moveTaskToBack(true);
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// TODO Auto-generated method stub
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
// remove message Handler from updating progress bar
mHandler.removeCallbacks(mUpdateTimeTask);
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
mHandler.removeCallbacks(mUpdateTimeTask);
int totalDuration = mp.getDuration();
int currentPosition = utils.progressToTimer(seekBar.getProgress(), totalDuration);
// forward or backward to certain seconds
mp.seekTo(currentPosition);
// update timer progress again
updateProgressBar();
}
@Override
public void onCompletion(MediaPlayer arg0) {
// check for repeat is ON or OFF
if (isRepeat) {
// repeat is on play same song again
playSong(mItems.get(currentSongIndex));
} else if (isShuffle) {
// shuffle is on - play a random song
Random rand = new Random();
currentSongIndex = rand.nextInt((mItems.size() - 1) - 0 + 1) + 0;
playSong(mItems.get(currentSongIndex));
} else {
// no repeat or shuffle ON - play next song
if (currentSongIndex < (mItems.size() - 1)) {
playSong(mItems.get(currentSongIndex + 1));
currentSongIndex = currentSongIndex + 1;
} else {
// play first song
playSong(mItems.get(0));
currentSongIndex = 0;
}
}
}
// stop player when destroy
@Override
public void onDestroy() {
super.onDestroy();
mp.release();
}
@Override
protected void onResume() {
if (mp.isPlaying()) {
updateProgressBar();
bt_play.setBackgroundResource(R.drawable.btn_pause);
} else {
bt_play.setBackgroundResource(R.drawable.btn_play);
}
if(!Tools.isAllPermissionGranted(this)){
showDialogPermission();
}else{
if(db.getAllMusicFiles().size()==0){
new loadFiles().execute("");
}
}
super.onResume();
}
private void showDialogPermission(){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.dialog_title_permission));
builder.setMessage(getString(R.string.dialog_content_permission));
builder.setCancelable(false);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
Tools.goToPermissionSettingScreen(Player.this);
}
});
builder.show();
}
}
}
player_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/main_content">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_song_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:maxLines="1"
android:singleLine="true"
android:text="Song Title"
android:background="@color/orange"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textColor="@color/white" />
<LinearLayout
android:id="@+id/lyt_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/orange"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:gravity="center_horizontal"
android:orientation="horizontal"
android:paddingLeft="10dp"
android:paddingRight="10dp">
<Button
android:id="@+id/btn_repeat"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_margin="3dp"
android:background="@drawable/btn_repeat" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:orientation="horizontal">
<Button
android:id="@+id/bt_prev"
android:layout_width="35dp"
android:layout_height="35dp"
android:background="@drawable/btn_previous" />
<Button
android:id="@+id/bt_play"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:background="@drawable/btn_play" />
<Button
android:id="@+id/bt_next"
android:layout_width="35dp"
android:layout_height="35dp"
android:background="@drawable/btn_next" />
</LinearLayout>
<Button
android:id="@+id/btn_shuffle"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_margin="3dp"
android:background="@drawable/btn_shuffle" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_song_current_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0.00"
android:textColor="@color/white" />
<android.support.v7.widget.AppCompatSeekBar
android:id="@+id/seek_song_progressbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:progress="0"
android:theme="@style/SeekBarStyle" />
<TextView
android:id="@+id/tv_song_total_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0.00"
android:textColor="@color/white" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="20dp"
android:layout_gravity="right"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="SONG INFO HERE"/>
</LinearLayout>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/lyt_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:gravity="center"
android:orientation="vertical">
<ProgressBar
android:id="@+id/progress_loadfiles"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Scanning" />
</LinearLayout>
<LinearLayout
android:id="@+id/lyt_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="@+id/list_main"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
android:paddingTop="5dp" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
Upvotes: 0
Views: 119
Reputation: 85
I am also trying to develop the same kind of app, yes you can do it by using fragments with tabs and using the service class for playing song in fragment via server.
Upvotes: 1