Curtis White
Curtis White

Reputation: 250

Error while Instantiating Music Player Components inside a Fragment Class

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

Answers (1)

Ananya Srivastav
Ananya Srivastav

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

Related Questions