android-音乐播放器实现及源码下载(四)

本系列博文,详细讲述一个音乐播放器的实现,以及从网络解析数据获取最新推荐歌曲以及歌曲下载的功能。

功能介绍如下:

1、获取本地歌曲列表,实现歌曲播放功能。

2、利用硬件加速感应器,摇动手机实现切换歌曲的功能

3、利用jsoup解析网页数据,从网络获取歌曲列表,同时实现歌曲和歌词下载到手机本地的功能。

4、通知栏提醒,实现仿QQ音乐播放器的通知栏功能.

涉及的技术有:

1、jsoup解析网络网页,从而获取需要的数据

2、android中访问网络,获取文件到本地的网络请求技术,以及下载文件到本地实现断点下载

3、线程池

4、图片缓存

5、service一直在后台运行

6、手机硬件加速器

7、notification通知栏设计

8、自定义广播

9、android系统文件管理

主要技术是这些,其中,利用jsoup解析网络网页,从而获取需要的数据,请参考我的博文: android中使用JSOUP如何解析网页数据详述

之前的三篇博文的链接:

android-音乐播放器实现及源码下载(一)讲述了activity基类实现和application类的实现,以及最终设计界面展示。

android-音乐播放器实现及源码下载(二)讲述了主界面的设计和实现

android-音乐播放器实现及源码下载(三)讲述了两个service服务的设计和实现

本篇博文讲述播放界面的设计和实现,以及做最后的总结。

这个是播放界面的截图,仿QQ音乐播放界面的实现,代码如下:

/**
 * 2015年8月15日 16:34:37
 *  博文地址:http://blog.csdn.net/u010156024
 */
public class PlayActivity extends BaseActivity implements OnClickListener {

    private LinearLayout mPlayContainer;
    private ImageView mPlayBackImageView; // back button
    private TextView mMusicTitle; // music title
    private ViewPager mViewPager; // cd or lrc
    private CDView mCdView; // cd
    private SeekBar mPlaySeekBar; // seekbar
    private ImageButton mStartPlayButton; // start or pause
    private TextView mSingerTextView; // singer
    private LrcView mLrcViewOnFirstPage; // single line lrc
    private LrcView mLrcViewOnSecondPage; // 7 lines lrc
    private PagerIndicator mPagerIndicator; // indicator

    // cd view and lrc view
    private ArrayList<View> mViewPagerContent = new ArrayList<View>(2);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.play_activity_layout);
        setupViews();
    }

    /**
     * 初始化view
     */
    private void setupViews() {
        mPlayContainer = (LinearLayout) findViewById(R.id.ll_play_container);
        mPlayBackImageView = (ImageView) findViewById(R.id.iv_play_back);
        mMusicTitle = (TextView) findViewById(R.id.tv_music_title);
        mViewPager = (ViewPager) findViewById(R.id.vp_play_container);
        mPlaySeekBar = (SeekBar) findViewById(R.id.sb_play_progress);
        mStartPlayButton = (ImageButton) findViewById(R.id.ib_play_start);
        mPagerIndicator = (PagerIndicator) findViewById(R.id.pi_play_indicator);

        // 动态设置seekbar的margin
        MarginLayoutParams p = (MarginLayoutParams) mPlaySeekBar
                .getLayoutParams();
        p.leftMargin = (int) (App.sScreenWidth * 0.1);
        p.rightMargin = (int) (App.sScreenWidth * 0.1);

        mPlaySeekBar.setOnSeekBarChangeListener(mSeekBarChangeListener);

        initViewPagerContent();
        // 设置viewpager的切换动画
        mViewPager.setPageTransformer(true, new PlayPageTransformer());
        mPagerIndicator.create(mViewPagerContent.size());
        mViewPager.setOnPageChangeListener(mPageChangeListener);
        mViewPager.setAdapter(mPagerAdapter);

        mPlayBackImageView.setOnClickListener(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        allowBindService();
    }

    @Override
    protected void onPause() {
        allowUnbindService();
        super.onPause();
    }

    private OnPageChangeListener mPageChangeListener =
            new OnPageChangeListener() {
        @Override
        public void onPageSelected(int position) {
            if (position == 0) {
                if (mPlayService.isPlaying())
                    mCdView.start();
            } else {
                mCdView.pause();
            }
            mPagerIndicator.current(position);
        }

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
        }

        @Override
        public void onPageScrollStateChanged(int arg0) {
        }
    };

    /**
     * 拖动进度条
     */
    private SeekBar.OnSeekBarChangeListener mSeekBarChangeListener =
            new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress,
                boolean fromUser) {

        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            int progress = seekBar.getProgress();
            mPlayService.seek(progress);
            mLrcViewOnFirstPage.onDrag(progress);
            mLrcViewOnSecondPage.onDrag(progress);
        }
    };

    private PagerAdapter mPagerAdapter = new PagerAdapter() {
        @Override
        public int getCount() {
            return mViewPagerContent.size();
        }

        @Override
        public boolean isViewFromObject(View view, Object obj) {
            return view == obj;
        }

        /**
         * 该方法是PagerAdapter的预加载方法,系统调用 当显示第一个界面时,
         * 第二个界面已经预加载,此时调用的就是该方法。
         */
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            container.addView(mViewPagerContent.get(position));
            return mViewPagerContent.get(position);
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            ((ViewPager) container).removeView((View) object);
        }
    };

    /**
     * 初始化viewpager的内容
     */
    private void initViewPagerContent() {
        View cd = View.inflate(this, R.layout.play_pager_item_1, null);
        mCdView = (CDView) cd.findViewById(R.id.play_cdview);
        mSingerTextView = (TextView) cd.findViewById(R.id.play_singer);
        mLrcViewOnFirstPage = (LrcView) cd.findViewById(R.id.play_first_lrc);

        View lrcView = View.inflate(this, R.layout.play_pager_item_2, null);
        mLrcViewOnSecondPage = (LrcView) lrcView
                .findViewById(R.id.play_first_lrc_2);

        mViewPagerContent.add(cd);
        mViewPagerContent.add(lrcView);
    }

    @SuppressWarnings("deprecation")
    private void setBackground(int position) {
        Music currentMusic = MusicUtils.sMusicList.get(position);
        Bitmap bgBitmap = MusicIconLoader.getInstance().load(
                currentMusic.getImage());
        if (bgBitmap == null) {
            bgBitmap = BitmapFactory.decodeResource(getResources(),
                    R.drawable.ic_launcher);
        }
        mPlayContainer.setBackgroundDrawable(
                new ShapeDrawable(new PlayBgShape(bgBitmap)));
    }

    /**
     * 上一曲
     *
     * @param view
     */
    public void pre(View view) {
        mPlayService.pre(); // 上一曲
    }

    /**
     * 播放 or 暂停
     *
     * @param view
     */
    public void play(View view) {
        if (mPlayService.isPlaying()) {
            mPlayService.pause(); // 暂停
            mCdView.pause();
            mStartPlayButton
                    .setImageResource(R.drawable.player_btn_play_normal);
        } else {
            onPlay(mPlayService.resume()); // 播放
        }
    }

    /**
     * 上一曲
     *
     * @param view
     */
    public void next(View view) {
        mPlayService.next(); // 上一曲
    }

    /**
     * 播放时调用 主要设置显示当前播放音乐的信息
     *
     * @param position
     */
    private void onPlay(int position) {
        Music music = MusicUtils.sMusicList.get(position);

        mMusicTitle.setText(music.getTitle());
        mSingerTextView.setText(music.getArtist());
        mPlaySeekBar.setMax(music.getLength());
        Bitmap bmp = MusicIconLoader.getInstance().load(music.getImage());
        if (bmp == null)
            bmp = BitmapFactory.decodeResource(getResources(),
                    R.drawable.ic_launcher);
        mCdView.setImage(ImageTools.scaleBitmap(bmp,
                (int) (App.sScreenWidth * 0.8)));

        if (mPlayService.isPlaying()) {
            mCdView.start();
            mStartPlayButton
                    .setImageResource(R.drawable.player_btn_pause_normal);
        } else {
            mCdView.pause();
            mStartPlayButton
                    .setImageResource(R.drawable.player_btn_play_normal);
        }
    }

    private void setLrc(int position) {
        Music music = MusicUtils.sMusicList.get(position);
        String lrcPath = MusicUtils.getLrcDir() + music.getTitle() + ".lrc";
        mLrcViewOnFirstPage.setLrcPath(lrcPath);
        mLrcViewOnSecondPage.setLrcPath(lrcPath);
    }

    @Override
    public void onPublish(int progress) {
        mPlaySeekBar.setProgress(progress);
        if (mLrcViewOnFirstPage.hasLrc())
            mLrcViewOnFirstPage.changeCurrent(progress);
        if (mLrcViewOnSecondPage.hasLrc())
            mLrcViewOnSecondPage.changeCurrent(progress);
    }

    @Override
    public void onChange(int position) {
        setBackground(position);
        onPlay(position);
        setLrc(position);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.iv_play_back:
            finish();
            break;
        default:
            break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}

整个代码比较简单,需要特别说明的是,播放界面并没有和MediaPlayer类耦合,而是和PlayService耦合,对于歌曲的播放,暂停,下一曲、上一曲等操作都和PlayService进行交互,这样做好处非常明显,整个项目中所有对播放歌曲的操作都通过PlayService进行,同时,通过PlayService可以更新通知栏信息。

**

总结

**

一、

项目中,用到了比较多的回调接口,回调接口确实非常好用,解决之间的耦合关系。

service类通过回调接口OnMusicEventListener中的方法,调用activity类中的

public void onPublish(int percent);
public void onChange(int position);

两个方法来实现UI的更新。

而Activity类中通过基类BaseActivity中的以下代码

private ServiceConnection mPlayServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceDisconnected(ComponentName name) {
            L.l(TAG, "play--->onServiceDisconnected");
            mPlayService = null;
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mPlayService = ((PlayService.PlayBinder) service).getService();
            mPlayService.setOnMusicEventListener(mMusicEventListener);
            onChange(mPlayService.getPlayingPosition());
        }
    };

    private ServiceConnection mDownloadServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceDisconnected(ComponentName name) {
            L.l(TAG, "download--->onServiceDisconnected");
            mDownloadService = null;
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mDownloadService = ((DownloadService.DownloadBinder) service).getService();
        }
    };

    /**
     * 音乐播放服务回调接口的实现类
     */
    private PlayService.OnMusicEventListener mMusicEventListener =
            new PlayService.OnMusicEventListener() {
        @Override
        public void onPublish(int progress) {
            BaseActivity.this.onPublish(progress);
        }

        @Override
        public void onChange(int position) {
            BaseActivity.this.onChange(position);
        }
    };

完成与两个service服务的绑定,实现与service服务的交互。

以上是两个非常关键的方法实现两者之间的交互,应该说是非常好的处理两者之间的信息传递。

其中在获取网络歌曲列表的过程中,也是用到了回调接口的方法进行数据传递,SongsRecommendation类中的

/**
     * 回调接口 获取数据之后,通过该接口设置数据传递
     */
    public interface OnRecommendationListener {
        public void onRecommend(ArrayList<SearchResult> results);
    }

这个接口就是进行结果传递的回调接口。所以大家在看代码的过程中,务必了解并看懂回调接口到底是如何进行的。

二、

项目中使用了比较多的线程池问题,大家务必了解线程池的用法。其实线程池用法非常简单。

private ExecutorService mThreadPool;
mThreadPool = Executors.newSingleThreadExecutor();
mThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                ArrayList<SearchResult> result = getMusicList();
                if (result == null) {
                    mHandler.sendEmptyMessage(Constants.FAILED);
                    return;
                }
                mHandler.obtainMessage(Constants.SUCCESS, result)
                        .sendToTarget();
            }
        });

以上便是线程池的基本用法了。easy!!

三、

jsoup是本项目中的重点内容,请参考我的博文:android中使用JSOUP如何解析网页数据详述

四、

本项目中的两个service服务也是关键内容,关于service服务一直在后台运行的内容,请参考我的博文:实现音乐播放器后台Service服务一直存在的解决思路

以上四点是项目中比较重要的部分,博文写的比较仓促,难免有什么不好的地方,如果大家有什么疑问或问题,欢迎给我留言,我一定尽快回复大家!^_^【握手】

音乐播放器源码下载

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-03 07:26:12

android-音乐播放器实现及源码下载(四)的相关文章

android-音乐播放器实现及源码下载(二)

本系列博文,详细讲述一个音乐播放器的实现,以及从网络解析数据获取最新推荐歌曲以及歌曲下载的功能. 功能介绍如下: 1.获取本地歌曲列表,实现歌曲播放功能. 2.利用硬件加速感应器,摇动手机实现切换歌曲的功能 3.利用jsoup解析网页数据,从网络获取歌曲列表,同时实现歌曲和歌词下载到手机本地的功能. 4.通知栏提醒,实现仿QQ音乐播放器的通知栏功能. 涉及的技术有: 1.jsoup解析网络网页,从而获取需要的数据 2.android中访问网络,获取文件到本地的网络请求技术,以及下载文件到本地实现

android-音乐播放器实现及源码下载(三)

本系列博文,详细讲述一个音乐播放器的实现,以及从网络解析数据获取最新推荐歌曲以及歌曲下载的功能. 功能介绍如下: 1.获取本地歌曲列表,实现歌曲播放功能. 2.利用硬件加速感应器,摇动手机实现切换歌曲的功能 3.利用jsoup解析网页数据,从网络获取歌曲列表,同时实现歌曲和歌词下载到手机本地的功能. 4.通知栏提醒,实现仿QQ音乐播放器的通知栏功能. 涉及的技术有: 1.jsoup解析网络网页,从而获取需要的数据 2.android中访问网络,获取文件到本地的网络请求技术,以及下载文件到本地实现

android-音乐播放器实现及源码下载(一)

从本文开始,详细讲述一个音乐播放器的实现,以及从网络解析数据获取最新推荐歌曲以及歌曲下载的功能. 功能介绍如下: 1.获取本地歌曲列表,实现歌曲播放功能. 2.利用硬件加速感应器,摇动手机实现切换歌曲的功能 3.利用jsoup解析网页数据,从网络获取歌曲列表,同时实现歌曲和歌词下载到手机本地的功能. 4.通知栏提醒,实现仿QQ音乐播放器的通知栏功能. 涉及的技术有: 1.jsoup解析网络网页,从而获取需要的数据 2.android中访问网络,获取文件到本地的网络请求技术,以及下载文件到本地实现

酷毙了!python用37行代码打造属于自己的音乐播放器,附源码

想不想手动打造一款专属于你的播放器,同时练练Python编程? 如果想,那就立即行动吧! 所需库pygametkintermutagen 至于它们的使用,可以浏览一下文档,如果你想做更功能强大的播放器,那必须好好看看哦! 设计思路作为版本0,我们并不想做太复杂的项目.只需实现以下几个功能: 将某个目录下的mp3文件名在listbox中显示 显示当前播放的歌曲名 播放上一首歌曲 播放下一首歌曲 停止播放 获取目录下的mp3文件直接上代码! def directorychooser():direct

自编Win8风格Android音乐播放器应用源码(单机版)

用闲暇的两天时间,研究编写了一个类Win8风格的android音乐播放器,实现了大部分基本功能.下面看具体描述: 基本实现功能:注意事项:Android系统版本须在2.2以上,保证手机安装有SD卡(部分图标来至qq音乐和百度音乐)界面组成:欢迎界面:淡入,随机图片 由于代码不少,所以在这里贴出来也不太现实,嗯,那就上链结吧,请各位到源码天堂网站上下载吧: http://code.662p.com/view/4733.html 主界面:4个tab标签页,4宫格: --  歌曲列表界面:从sd卡中扫

android音乐播放器源码

最近研究android音乐播放器,弄了一个,还可以,可以实现播放.暂停.拖动进度等功能. 源码地址:http://download.csdn.net/detail/a358763471/8728855

Android音乐播放器源码(歌词.均衡器.收藏.qq5.0菜单.通知)

Android音乐播放器(歌词.均衡器.收藏.qq5.0菜单.通知) 一款Android音乐播放器源码,基本功能都实现了 qq5.0菜单(歌词.均衡器.收藏.qq5.0菜单.通知) 只有向右滑动出现,菜单键和指定按钮都还没有添加. 下载地址:http://www.devstore.cn/code/info/1144.html 运行截图:     热门源码下载: 高仿京东商城 Android快速开发不可或缺的11个工具类 Android快速开发框架LoonAndroid Android应用源码比较

android音乐播放器开发 SweetMusicPlayer 智能负载直插式歌词

在一份书面的使用MediaPlayer播放音乐, http://blog.csdn.net/huweigoodboy/article/details/39862773.假设没有本地歌词怎么办?如今来将一下载入在线歌词.好了,还是用那张图. 在实现这个功能的时候,lz尝试过baidu api,歌词迷api,后来选用了歌词迷api.尽管还是资源不全.并且还有非常多错误. 特别头疼的是有时候歌词竟然不分行.解析起来简直难受. 歌词迷api歌词查询地址:http://geci.me/api/lyric/

android音乐播放器开发教程

android音乐播放器开发教程 android音乐播放器开发教程,布布扣,bubuko.com