Android 音乐播放器的开发教程:service的运用及音乐列表点击播放

按照前几篇博客的步骤,应该能看到自己手机里的音乐列表了,但是现在还只能看,不能点,还需要再给ListView添加点击事件的监听,接着启动一个Service来播放音乐,service是android四大组件之一,在官方的文档上是这样解释的:

A Service is an application component that can perform long-running operations in the background and does not provide a user interface. Another application component can start a service and it will continue to run in the background even if the user switches to another application. Additionally, a component can bind to a service to interact with it and even perform interprocess communication (IPC). For example, a service might handle network transactions, play music, perform file I/O, or interact with a content provider, all from the background.

也就是说,Service(服务)是一个没有用户界面的在后台运行执行耗时操作的应用组件。其他应用组件能够启动Service,并且当用户切换到 另外的应用场景,Service将持续在后台运行。另外,一个组件能够绑定到一个service与之交互(IPC机制),例如,一个service可能会 处理网络操作,播放音乐,操作文件I/O或者与内容提供者(content provider)交互,所有这些活动都是在后台进行。

我们先来给列表注册监听器,由于列表是显示在MyMusicFragment上面的,故注册监听器也应该在MyMusicFragment.java这个文件里面注册了,下面给出代码,红色部分为改动的地方:

package com.example.dada.myapplication;

import android.app.Activity;  
import android.net.Uri;  
import android.os.Bundle;  
import android.app.Fragment;  
import android.view.LayoutInflater;  
import android.view.View;  
import android.view.ViewGroup;  
import android.widget.AdapterView;  
import android.widget.ListView;

import java.util.List;

public class MyMusicFragment extends Fragment {

    private FindSongs finder; 
    //查找歌曲的类的实例  
    private Activity MyActivity;  
    private List mp3Infos;  
    private MusicListAdapter musicListAdapter;

    private OnFragmentInteractionListener mListener;

public static MyMusicFragment newInstance() {  
        MyMusicFragment fragment = new MyMusicFragment();  
        Bundle args = new Bundle();  
        fragment.setArguments(args);  
        return fragment;  
    }

    public MyMusicFragment() {  
        // Required empty public constructor  
    }

    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        MyActivity = getActivity();  
        finder = new FindSongs();  
        mp3Infos = finder.getMp3Infos(MyActivity.getContentResolver());  
        musicListAdapter = new MusicListAdapter(MyActivity.getApplicationContext(),mp3Infos);  
    }

    @Override  
    public View onCreateView(LayoutInflater inflater, ViewGroup container,  
                             Bundle savedInstanceState) {

        finder = new FindSongs();  
        View rootView = inflater.inflate(R.layout.fragment_my_music, container, false);

        /* 
        切换至我的音乐Fragment按钮监器 
        调用了在activity中已经重写了的方法onMyMusicFragmentInteraction 
         */  
        rootView.findViewById(R.id.top_layout_right_ImageView).  
                setOnClickListener(new View.OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                mListener.onMyMusicFragmentInteraction(AppConstant.PlayerMsg.BACK_TO_MAIN_FRAGMENT);  
            }  
        });

        /* 
        音乐列表的点击监听器 
        点击后调用的方法,是一个回调方法,用来告诉activity 
        列表里面的哪个项被点击了 
        让activity做出反应 
         */  
        ((ListView)rootView.findViewById(R.id.music_list)).  
                setOnItemClickListener(new AdapterView.OnItemClickListener() {  
                    @Override  
                    public void onItemClick(AdapterView parent, View view, int position, long id) {  
                        if (mp3Infos != null) {  
                            mListener.onMyMusicFragmentInteraction(AppConstant.PlayerMsg.LIST_CLICK, position);  
                        }  
                    }  
                });

        finder.setListAdpter(MyActivity.getApplicationContext(),  
                mp3Infos,(ListView)rootView.findViewById(R.id.music_list));

        return rootView;  
    }

    // TODO: Rename method, update argument and hook method into UI event  
    public void onButtonPressed() {  
        if (mListener != null) {  
        }  
    }

    @Override  
    public void onAttach(Activity activity) {  
        super.onAttach(activity);  
        try {  
            mListener = (OnFragmentInteractionListener) activity;  
        } catch (ClassCastException e) {  
            throw new ClassCastException(activity.toString()  
                    + " must implement OnFragmentInteractionListener");  
        }  
    }

    @Override  
    public void onDetach() {  
        super.onDetach();  
        mListener = null;  
    }

    public interface OnFragmentInteractionListener {  
        public void onMyMusicFragmentInteraction(int msg);  
        public void onMyMusicFragmentInteraction(int msg,int position);      //这个方法要在MainActivity中再次重写一遍
    }  
}

上面的监听器注册完毕之后,就换到MainActivity.java中去对点击时间做出处理,启动一个service.我们需要先在MainActivity中写一个初始化service的方法,MainActivity代码如下,红色部分为修改的部分:

package com.example.dada.myapplication;

import android.app.FragmentManager;  
import android.app.FragmentTransaction;  
import android.content.Intent;  
import android.net.Uri;  
import android.support.v7.app.ActionBarActivity;  
import android.os.Bundle;  
import android.view.Menu;  
import android.view.MenuItem;  
import android.widget.ImageButton;  
import java.util.List;

public class MainActivity extends ActionBarActivity  
        implements MainFragment.OnFragmentInteractionListener,  
                   MyMusicFragment.OnFragmentInteractionListener{

    private boolean isPause;                                               //记录当前播放器的状态
    private FragmentManager fragmentManager;  
    private FragmentTransaction fragmentTransaction;  
    private MyMusicFragment myMusicFragment;  
    private MainFragment mainFragment;  
    private FindSongs finder;                                              //查找歌曲的类  
    public static List mp3Infos;                                  //歌曲列表  
    public static int music_position;                                      //音乐的位置

    private ImageButton play_button;                                       //播放按钮控件

    /* 
    这个方法是activity和fragment通信的一种方法 
    在MainFragment中调用这个方法,可以在activity中做出相应的反应 
     */  
    public void onMainFragmentInteraction(int msg){

        /* 
        对其中的参数msg做出判断,如果为CHANGE_TO_MY_MUSIC_FRAGMENT 
        则执行跳转 
         */  
        if(msg == AppConstant.PlayerMsg.CHANGE_TO_MY_MUSIC_FRAGMENT){

            /* 
            在这里并没有直接切换Fragment 
            而是调用了activity实现MyMusicFragment的那个接口 
            对后面的开发能带来一点便利之处 
             */  
            onMyMusicFragmentInteraction(AppConstant.PlayerMsg.CHANGE_TO_MY_MUSIC_FRAGMENT);  
        }  
    }

    public void onMyMusicFragmentInteraction(int msg){

        myMusicFragment = new MyMusicFragment();       //创建了MyMusicFragment的实例  
        FragmentManager fragmentManager = getFragmentManager();   //得到FragmentManager  
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); //得到fragmentTransaction

        if(msg == AppConstant.PlayerMsg.CHANGE_TO_MY_MUSIC_FRAGMENT){

            fragmentTransaction.replace(R.id.fragment_layout, myMusicFragment);

            fragmentTransaction.addToBackStack(null);        //这句话是将被替换的MainFragment加入到一个专门存放fragment的栈中,在回退的时候显示上一个Fragment  
            fragmentTransaction.commit();  
        }

        if(msg == AppConstant.PlayerMsg.BACK_TO_MAIN_FRAGMENT){  
            fragmentTransaction.replace(R.id.fragment_layout, mainFragment);  
            fragmentTransaction.addToBackStack(null);  
            fragmentTransaction.commit();  
        }  
    }

    public void onMyMusicFragmentInteraction(int msg,int position){  
        if(msg == AppConstant.PlayerMsg.LIST_CLICK){  
            if (mp3Infos != null) {  
                isPause = false;  
                initService(position);  
            }  
        }  
    }

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

        music_position = 0;  
        finder = new FindSongs();  
        mp3Infos = finder.getMp3Infos(getContentResolver());

        play_button = (ImageButton)findViewById(R.id.play_button);

        mainFragment = new MainFragment();           //创建了刚才定义的MainFragment实例  
        fragmentManager = getFragmentManager();      //得到FragmentManager  
        fragmentTransaction = fragmentManager.beginTransaction();   //得到fragmentTransaction,用于管理fragment的切换  
        fragmentTransaction.replace(R.id.fragment_layout, mainFragment).commit();  //将MainActivity里的布局模块fragment_layout替换为mainFragment  
    }

    @Override  
    public boolean onCreateOptionsMenu(Menu menu) {  
        // Inflate the menu; this adds items to the action bar if it is present.  
        getMenuInflater().inflate(R.menu.menu_main, menu);  
        return true;  
    }

    @Override  
    public boolean onOptionsItemSelected(MenuItem item) {  
        // Handle action bar item clicks here. The action bar will  
        // automatically handle clicks on the Home/Up button, so long  
        // as you specify a parent activity in AndroidManifest.xml.  
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement  
        if (id == R.id.action_settings) {  
            return true;  
        }

        return super.onOptionsItemSelected(item);  
    }

    private void initService(int position) {  
        music_position = position;  
        Mp3Info mp3Info = mp3Infos.get(position);

        /* 
        这里新建了一个Intent 
        里面存放各种即将传给Service的数据 
        要启动自定义PlayerService类 
        还需要在AndroidManifest中加入如下代码

         
        

         */  
        Intent intent = new Intent("com.example.communication.MSG_ACTION");  
        play_button.setImageResource(R.drawable.pause_photo);  
        intent.putExtra("url", mp3Info.getUrl());  
        intent.putExtra("title", mp3Info.getTitle());  
        intent.putExtra("artist", mp3Info.getArtist());  
        intent.putExtra("album", mp3Info.getAlbum());  
        intent.putExtra("album_id", mp3Info.getAlbum_id());  
        intent.putExtra("MSG", AppConstant.PlayerMsg.PLAY_MSG);  
        intent.setClass(MainActivity.this, PlayerService.class);  
        startService(intent);  
    }
}

上面的startService(intent)是启动service的一种方法,将intent传给新启动的PlayerService,接下来 就是自定义的一个PlayerService类,里面对传进来的intent进行各种判断和处理.新建一个java类,名为 PlayerService.java,代码如下:

package com.example.dada.myapplication;

import android.app.Notification;  
import android.app.NotificationManager;  
import android.app.PendingIntent;  
import android.app.Service;  
import android.content.BroadcastReceiver;  
import android.content.Context;  
import android.content.Intent;  
import android.content.IntentFilter;  
import android.media.MediaPlayer;  
import android.os.Handler;  
import android.os.IBinder;  
import android.os.Looper;  
import android.os.Message;  
import android.view.animation.AnimationUtils;  
import android.widget.RemoteViews;

import java.io.IOException;  
import java.util.ArrayList;  
import java.util.List;

public class PlayerService extends Service implements AppConstant {

    private int current_position;

    private String musicPath;  
    private String music_artist;  
    private String music_title;  
    private String notification_msg;

    @Override  
    public IBinder onBind(Intent intent) {  
        return null;  
    }

/*
onStartCommand()方法就是刚启动service时调用的一个方法  
里面第一个参数intent就是在activity中的那个intent  
因此里面包含着被点击的歌曲相关信息  
*/  
public int onStartCommand(Intent intent, int flags, int startId) {  
    public static MediaPlayer mediaPlayer = new MediaPlayer();                        //
    try {  
            int msg = intent.getIntExtra("MSG", 0);  
            musicPath = intent.getStringExtra("url");   //从intent中拿出歌曲的路径

            if (msg == AppConstant.PlayerMsg.PLAY_MSG) {  
                playMusic(0);  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return 0;  
    }

    private void playMusic(int position) {  
        try {  
            mediaPlayer.reset();  
            mediaPlayer.setDataSource(musicPath);  
            mediaPlayer.prepare();  
            mediaPlayer.setOnPreparedListener(new MyPreparedListener(position));

        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }

    private class MyPreparedListener implements MediaPlayer.OnPreparedListener {

        private int position;

        public MyPreparedListener(int position) {  
            this.position = position;  
        }

        public void onPrepared(MediaPlayer mp) {  
            if (position > 0)  
                mediaPlayer.seekTo(position);  
            mediaPlayer.start();  
        }  
    }

    private void stopMusic() {  
        if (mediaPlayer != null) {  
            mediaPlayer.pause();  
        }  
    }

    public void onDestory() {  
        if (mediaPlayer != null) {  
            mediaPlayer.stop();  
            mediaPlayer.release();  
        }  
    }

上面的函数命名也都很简单,相信大家能够看懂,如果有什么问题,直接给我留言把,我会解答的哈......

做到了这一步,现在的播放器就可以点击并且播放歌曲了,点什么唱什么有木有,但是还是觉得怪怪的对不对,因为还不能暂停和切歌,不要担心,下一篇的博客中,将继续介绍如何把按钮的监听事件给加上去,到时候播放器的功能就差不多咯.今天就说这么多了,88

你可能感兴趣的:(Android 音乐播放器的开发教程:service的运用及音乐列表点击播放)