יום שבת, 7 במרץ 2015

Android Music Player



אחרי חופשה של מספר חודשים אפשר להתחיל את השנה החדשה עם מאמר שבו אלמד כיצד לבנות נגן MP3 בסביבת Android, הרעיון מאוד פשוט, האפליקציה תסרוק את המכשיר עבור קבצי מוזיקה ותנגן אותם אחד אחרי השני עם פונקציות שליטה בסיסיות.

שימו לב!

  • המחלקה נכתבה על Android Studio.
  • המחלקה תואמת ל Api 14.
Music Search

נקודת ההתחלה עבור האפליקציה היא קודם כל לחפש את כל קבצי המוזיקה שעל המכשיר אבל לפני שנתחיל נגדיר מחלקה פשוטה שתאחסן בשבילנו את הנתונים:

    private class SongDetails {
        String songTitle = "";
        String songArtist = "";
        //song location on the device
        String songData = "";
    }

לאחר מכן נפעיל את הפונקציה שתתחבר למסד הנתונים במכשיר ותבקש את כל הקבצי מדיה שמוגדרים כמוזיקה (מתעלמים לחלוטין מוידאו), התוצאה תהיה טבלה שתכיל עמודות לפי מה שביקשנו בשאילתא:

 private void getAllSongs()
    {
       //creating selection for the database
        String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0";
        final String[] projection = new String[] {
                MediaStore.Audio.Media.DISPLAY_NAME,
                MediaStore.Audio.Media.ARTIST,
                MediaStore.Audio.Media.DATA};
        
        //creating sort by for database
        final String sortOrder = MediaStore.Audio.AudioColumns.TITLE
                + " COLLATE LOCALIZED ASC";

        //stating pointer
        Cursor cursor = null;

        try {
            //the table for query
            Uri uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
            // query the db
            cursor = getBaseContext().getContentResolver().query(uri,
                    projection, selection, null, sortOrder);
            if (cursor != null) {
                
                //create array for incoming songs
                songs = new ArrayList<SongDetails>(cursor.getCount());
                
                //go to the first row
                cursor.moveToFirst();

                SongDetails details;

                while (!cursor.isAfterLast()) {
                    //collecting song information and store in array,
                    //moving to the next row
                    details = new SongDetails();
                    details.songTitle = cursor.getString(0);
                    details.songArtist = cursor.getString(1);
                    details.songData = cursor.getString(2);
                    songs.add(details);
                    cursor.moveToNext();
                    
                }
            }
        } catch (Exception ex) {

        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
    }



Simple Player

עד עכשיו היה החלק הטכני שבו אנחנו מקבלים את חומרי הגלם ועכשיו אפשר להתחיל לעבוד איתם בעזרת מחלקה מאוד פשוטה שעושה פעולות (Stop, Play, Pause, Forward, Backward, Seek) כמו כל נגן סטנדרטי , על מנת לעדכן את ה Gui נעזר ב Interface משותף כפי שניתן לראות בדוגמה:

public interface OnPlayerEventListener {
    void onPlayerComplete();
    void onPlayerStart(String Title,int songDuration,int songPosition);
}


המחלקה מקבלת את המופע של ה Activity שמפעיל אותה, מאתחלים אותה עם רשימת השרים ששלפנו מה Database ומחכים לפקודות מה Gui.

public class simplePlayer
{
    OnPlayerEventListener mListener;
    Activity mActivity;

    //give access to the gui
    public ArrayList<songDetails> songs = null;
    public boolean isPaused = false;
    public int currentPosition = 0;
    public int currentDuration = 0;

    //single instance
    public static MediaPlayer player;

   //getting gui player interface
   public  simplePlayer(Activity ma)
   {
       mActivity = ma;
       mListener = (OnPlayerEventListener) mActivity;
   }

    //initialize the player
    public void init(ArrayList<songDetails>_songs)
    {
        songs = _songs;
        currentPosition = 0;


        if(player == null)
        {
            player = new MediaPlayer();
            player.setAudioStreamType(AudioManager.STREAM_MUSIC);
            player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {

                    player.stop();
                    player.reset();

                    nextSong();
                    mListener.onPlayerSongComplete();

                }
            });
        }
    }

    //stop the current song
    public void stop()
    {
        if(player != null)
        {
            if(player.isPlaying())
                //stop music
                player.stop();

            //reset pointer
            player.reset();
        }
    }

    //pause the current song
    public void pause()
    {
        if(!isPaused && player != null)
        {
            player.pause();
            isPaused = true;
        }
    }

    //playing the current song
    public void play()
    {
        if(player != null)
        {
            if(!isPaused && !player.isPlaying())
            {
                if(songs != null)
                {
                    if(songs.size() > 0)
                    {
                        try {
                            //getting file path from data
                            Uri u = Uri.fromFile(new File(songs.get(currentPosition).songData));

                            //set player file
                            player.setDataSource(mActivity,u);
                            //loading the file
                            player.prepare();
                            //getting song total time in milliseconds
                            currentDuration = player.getDuration();
                          
                            //start playing music!
                            player.start();
                            mListener.onPlayerSongStart("Now Playing: "
                                    + songs.get(currentPosition).songArtist
                                    + " - "+ songs.get(currentPosition).songTitle
                                    ,currentDuration,currentPosition);
                        }
                        catch (Exception ex)
                        {
                            ex.printStackTrace();
                        }
                    }
                }
                else
                {
                    //continue playing, reset the flag
                    player.start();
                    isPaused = false;
                }
            }
        }
    }

    //playing the next song in the array
    public  void nextSong()
    {
        if(player != null)
        {
            if(isPaused)
                isPaused = false;

            if(player.isPlaying())
                player.stop();

            player.reset();

            if((currentPosition + 1) == songs.size())
                currentPosition = 0;
            else
                currentPosition  = currentPosition + 1;

            play();
        }
    }

    //playing the previous song in the array
    public void previousSong()
    {
        if(player != null)
        {
            if(isPaused)
                isPaused = false;

            if(player.isPlaying())
                player.stop();

            player.reset();

            if(currentPosition - 1 < 0)
                currentPosition = songs.size();
            else
                currentPosition = currentPosition -1;

            play();
        }
    }

    //getting new position for playing by the gui seek bar
    public void setSeekPosition(int msec)
    {
        if(player != null)
            player.seekTo(msec);
    }

    //getting the current duration of music
    public int getSeekPosition()
    {
        if(player != null)
            return  player.getDuration();
        else
            return -1;
    }
}

ה Activity ממש את ה Interface, ומחפש שירים על המכשיר ומכניס אותם למערך שנשלח למחלקה, ניתן ליצור כפתורים ולשלוט במחלקה בעזרת Gui:

public class MainActivity extends ActionBarActivity 
implements OnPlayerEventListener {

    simplePlayer player;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //getting all songs in the device
        getAllSongs();

        if (player == null) {
            //create new instance and send the listener
            player = new simplePlayer(this);
            //initialize the simplePlayer
            player.init(songs);
            //start playing the first song
            player.play();

            seekBar.setMax(player.currentDuration);
        }
    }

    @Override
    public void onPlayerSongComplete() {

    }

    @Override
    public void onPlayerSongStart(String Title, int songDuration, int songPosition) {
        this.setTitle(Title);
        seekBar.setMax(songDuration);
        seekBar.setProgress(0);
    }
}

סיכום:

דרך פשוטה מאוד שבעזרת ניתן לנגן מוזיקה במכשיר וזה רק חלק קטן מכלי המדיה המגוונים ש Android נותן, על הדרך ראינו כיצד לממש ממשק בין ה GUI למחלקה שיגרום לאירוע כאשר שיר נגמר ומתחיל.

אל תפריעו לשכנים...