• Android程序设计之音乐播放器实现


    Android毕设音乐播放器实现

    基于MediaPlayer技术实现在线音乐播放器,播放在线音乐,后端使用SpringBoot将音乐存放在Tomcat服务器。app通过网络请求获取音乐,从而实现在线音乐播放。该项目分为用户端和管理员端


    一、核心技术Service组件介绍

    Service它可以在后台执行长时间运行操作而没有用户界面的应用组件,不依赖任何用户界面,例如后台播放音乐,后台下载文件等。

    虽然服务是在后台运行的,但是Service和Activity都是运行在当前APP所在的main thread(UI主线程)中的,而耗时操作(如网络请求、拷贝数据、大文件)会阻塞主线程,给用户带来不好的体验。如果需要在服务中进行耗时操作,可以选择 IntentService,IntentService是Service的子类,用来处理异步请求。

    二、如何使用SerVice

    创建Service直接在Android Studio中右键选择Service创建即可。默认我们所创建的Service是继承Service的。同时我们为了实现后台音乐播放的功能,所以我们还要实MediaPlayer.OnCompletionListener的接口。

    同时还要在AndroidManifest.xml文件中对已经创建的Service进行注册,这一点Android Studio已经帮我们自动创建好了

    三、Service启动的两种方式

    (1)在Acitivity界面通过显式意图(或隐式意图)的方式来启动服务和关闭服务。

    Intent intentService = new Intent(MainActivity.this, AudioService.class);
     startService(intentService);
    
    • 1
    • 2

    (2)bindService()绑定服务

    当应用组件通过调用 bindService() 绑定到服务时,服务即处于“绑定”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。


    1. 用户端功能模块:登录,注册,音乐推荐,音乐分类,个人中心,音乐浏览记录,我的下载,上一曲,下一曲,音乐下载

    在这里插入图片描述
    在这里插入图片描述


    2.管理员模块:登录,注册,用户管理,音乐分类管理(添加分类,删除分类,编辑分类),音乐管理(修改歌名,移动音乐分类,删除音乐)

    在这里插入图片描述
    在这里插入图片描述


    3.部分核心代码实现

    欢迎页

    /**
     * 欢迎页
     */
    @SuppressLint("CustomSplashScreen")
    public class SplashActivity extends BaseActivity<ActivitySplashBinding> {
    
        @Override
        protected ActivitySplashBinding getViewBinding() {
            return ActivitySplashBinding.inflate(getLayoutInflater());
        }
    
        @Override
        protected void setListener() {
    
    
        }
    
        @Override
        protected void initData() {
            new Handler(Looper.myLooper()).postDelayed(new Runnable() {
                @Override
                public void run() {
                    startActivity(new Intent(mContext,LoginActivity.class));
                    finish();
                }
            },800);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    用户主页面

    /**
     * 用户主页面
     */
    public class MainActivity extends BaseActivity<ActivityMainBinding> {
        private String[] titles = {"音乐推荐", "音乐分类"};
        private List<Fragment> fragmentList = new ArrayList<>();
    
        @Override
        protected ActivityMainBinding getViewBinding() {
            return ActivityMainBinding.inflate(getLayoutInflater());
        }
    
        @Override
        protected void setListener() {
    
            mBinding.avatar.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    startActivityForResult(new Intent(MainActivity.this, MineActivity.class), 20002);
                }
            });
    
        }
    
    
        @Override
        protected void initData() {
            if (ApiConstants.getUserInfo() != null) {
                mBinding.username.setText(ApiConstants.getUserInfo().getUsername());
            }
            //造数据
            fragmentList.add(new HomeFragment());
            fragmentList.add(new TypeFragment());
    //        fragmentList.add(new RecordFragment());
    
            //如果处理成懒加载的话,其实很简单,只要是这个方法setOffscreenPageLimit不去设置,就可以了。
    //        mBinding.viewPager.setOffscreenPageLimit(fragmentList.size());
            mBinding.viewPager.setUserInputEnabled(false);
            mBinding.viewPager.setAdapter(new FragmentStateAdapter(this) {
                @NonNull
                @Override
                public Fragment createFragment(int position) {
                    return fragmentList.get(position);
                }
    
                @Override
                public int getItemCount() {
                    return fragmentList.size();
                }
            });
            mBinding.tabs.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
                @Override
                public void onTabSelected(TabLayout.Tab tab) {
                    mBinding.viewPager.setCurrentItem(tab.getPosition(), false);
                }
    
                @Override
                public void onTabUnselected(TabLayout.Tab tab) {
    
                }
    
                @Override
                public void onTabReselected(TabLayout.Tab tab) {
    
                }
            });
    
            TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(mBinding.tabs, mBinding.viewPager, new TabLayoutMediator.TabConfigurationStrategy() {
                @Override
                public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
                    tab.setText(titles[position]);
                }
            });
            //这句话很重要
            tabLayoutMediator.attach();
    
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (resultCode == 20002) {
                finish();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

    音乐播放界面

    /**
     * 音乐播放界面
     */
    public class PlayMusicActivity extends BaseActivity<ActivityPlayMusicBinding> implements OnPlayerEventListener {
        private static final String TAG = "============";
        private MusicInfo musicInfo;
        private int mLastProgress;
    
        @Override
        protected ActivityPlayMusicBinding getViewBinding() {
            return ActivityPlayMusicBinding.inflate(getLayoutInflater());
        }
    
        @Override
        protected void setListener() {
    
            Aria.download(this).register();
    
            mBinding.sbProgress.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean b) {
                    if (Math.abs(progress - mLastProgress) >= DateUtils.SECOND_IN_MILLIS) {
                        mBinding.tvCurrentTime.setText(formatTime("mm:ss", progress));
                        mLastProgress = progress;
                    }
                }
    
                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {
    
                }
    
                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {
                    if (AudioPlayer.get().isPlaying() || AudioPlayer.get().isPausing()) {
                        int progress = seekBar.getProgress();
                        AudioPlayer.get().seekTo(progress);
                    } else {
                        seekBar.setProgress(0);
                    }
                }
            });
    
            mBinding.ivMusicPlay.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    AudioPlayer.get().playPause();
                }
            });
    
            mBinding.ivMusicPrevious.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    AudioPlayer.get().prev();
                }
            });
    
            mBinding.ivMusicNext.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    AudioPlayer.get().next();
                }
            });
    
    
            //下载
            mBinding.download.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (XXPermissions.isGranted(mContext, Permission.Group.STORAGE)) {
                        download();
                    } else {
                        checkPermission();
                    }
    
                }
            });
    
        }
    
        @Override
        protected void initData() {
            initSystemBar();
            musicInfo = (MusicInfo) getIntent().getSerializableExtra("musicInfo");
            //监听
            AudioPlayer.get().addOnPlayEventListener(this);
            if (null != musicInfo) {
                AudioPlayer.get().addAndPlay(musicInfo);
                //添加到浏览记录
                addRecord(musicInfo);
    
                //获取单个任务实体
                DownloadEntity entity = Aria.download(this).getFirstDownloadEntity(musicInfo.getMusic_url());
                if (null != entity) {
                    mBinding.download.setClickable(false);
                    mBinding.download.setImageResource(R.mipmap.ic_download_complete);
                } else {
                    mBinding.download.setClickable(true);
                    mBinding.download.setImageResource(R.mipmap.iv_download);
                }
            }
        }
    
        /**
         * 沉浸式状态栏
         */
        private void initSystemBar() {
            ImmersionBar.with(this).init();
        }
    
        public String formatTime(String pattern, long milli) {
            int m = (int) (milli / DateUtils.MINUTE_IN_MILLIS);
            int s = (int) ((milli / DateUtils.SECOND_IN_MILLIS) % 60);
            String mm = String.format(Locale.getDefault(), "%02d", m);
            String ss = String.format(Locale.getDefault(), "%02d", s);
            return pattern.replace("mm", mm).replace("ss", ss);
        }
    
        @SuppressLint("SetTextI18n")
        private void onChangeImpl(MusicInfo music) {
            if (music == null) {
                return;
            }
            mBinding.sbProgress.setProgress((int) AudioPlayer.get().getAudioPosition());
            mBinding.sbProgress.setSecondaryProgress(0);
            mLastProgress = 0;
            mBinding.tvCurrentTime.setText("00:00");
            if (AudioPlayer.get().isPlaying() || AudioPlayer.get().isPreparing()) {
                mBinding.ivMusicPlay.setSelected(true);
            } else {
                mBinding.ivMusicPlay.setSelected(false);
            }
            mBinding.toolbar.setTitle(music.getMusic_title());
            mBinding.tvMusicTitle.setText(music.getMusic_title());
            mBinding.tvMusicSongType.setText(music.getMusic_type());
    
            startAnim();
        }
    
        @Override
        public void onChange(MusicInfo music) {
            onChangeImpl(music);
        }
    
        @Override
        public void onPlayerStart(long duration) {
            //一定要设置最大值
            mBinding.sbProgress.setMax((int) duration);
            mBinding.tvTotalTime.setText(formatTime("mm:ss", duration));
            mBinding.ivMusicPlay.setSelected(true);
            startAnim();
        }
    
        @Override
        public void onPlayerPause() {
            mBinding.ivMusicPlay.setSelected(false);
            stopAnim();
        }
    
        @Override
        public void onPublish(int progress) {
            mBinding.sbProgress.setProgress(progress);
        }
    
        @Override
        public void onBufferingUpdate(int percent) {
            mBinding.sbProgress.setSecondaryProgress(mBinding.sbProgress.getMax() * 100 / percent);
        }
    
    
        private Animation animation;
    
        private void startAnim() {
            animation = AnimationUtils.loadAnimation(this, R.anim.rotation_animation);
            LinearInterpolator lin = new LinearInterpolator();//设置动画匀速运动
            animation.setInterpolator(lin);
            mBinding.imgCd.startAnimation(animation);
        }
    
        private void stopAnim() {
            if (mBinding.imgCd.getAnimation() != null) {
                mBinding.imgCd.clearAnimation();
            }
        }
    
        private void addRecord(MusicInfo musicInfo) {
            OkGo.<String>get(ApiConstants.ADD_RECORD_MUSIC_URL)
                    .params("username", ApiConstants.getUserInfo().getUsername())
                    .params("music_title", musicInfo.getMusic_title())
                    .params("music_url", musicInfo.getMusic_url())
                    .params("music_type", musicInfo.getMusic_type())
                    .execute(new HttpStringCallback(null) {
                        @Override
                        protected void onSuccess(String msg, String response) {
    
                        }
    
                        @Override
                        protected void onError(String response) {
    
                        }
                    });
    
    
        }
    
        private void checkPermission() {
            XXPermissions.with(this)
                    // 申请单个权限
                    // 申请多个权限
                    .permission(Permission.Group.STORAGE)
                    // 设置权限请求拦截器(局部设置)
                    //.interceptor(new PermissionInterceptor())
                    // 设置不触发错误检测机制(局部设置)
                    //.unchecked()
                    .request(new OnPermissionCallback() {
    
                        @Override
                        public void onGranted(List<String> permissions, boolean all) {
                            if (!all) {
                                showToast("获取部分权限成功,但部分权限未正常授予");
                                return;
                            }
    
                            //这里做操作
    
    
                        }
    
                        @Override
                        public void onDenied(List<String> permissions, boolean never) {
                            if (never) {
                                showToast("被永久拒绝授权,请手动授予录音和日历权限");
                                // 如果是被永久拒绝就跳转到应用权限系统设置页面
                                XXPermissions.startPermissionActivity(mContext, permissions);
                            } else {
                                showToast("获取录音和日历权限失败");
                            }
                        }
                    });
        }
    
        @Download.onWait
        public void onWait(DownloadTask task) {
            Log.d(TAG, "onWait: ");
        }
    
        @Download.onPre
        public void onPre(DownloadTask task) {
            Log.d(TAG, "onPre: ");
        }
    
        @Download.onTaskStart
        public void onTaskStart(DownloadTask task) {
            Log.d(TAG, "onTaskStart: ");
            showToast("开始下载~~~~~");
        }
    
        @Download.onTaskRunning
        public void onTaskRunning(DownloadTask task) {
            Log.d(TAG, "onTaskRunning: ");
        }
    
        @Download.onTaskResume
        public void onTaskResume(DownloadTask task) {
            Log.d(TAG, "onTaskResume: ");
        }
    
        @Download.onTaskStop
        public void onTaskStop(DownloadTask task) {
            Log.d(TAG, "onTaskStop: ");
        }
    
        @Download.onTaskCancel
        public void onTaskCancel(DownloadTask task) {
            Log.d(TAG, "onTaskCancel: ");
        }
    
        @Download.onTaskFail
        public void onTaskFail(DownloadTask task, Exception e) {
            Log.d(TAG, "onTaskFail: ");
        }
    
        @Download.onTaskComplete
        public void onTaskComplete(DownloadTask task) {
            Log.d(TAG, "onTaskComplete: ");
            mBinding.download.setClickable(false);
            mBinding.download.setImageResource(R.mipmap.ic_download_complete);
            showToast("下载完成~~~~~");
    
        }
    
        private void download() {
            if (null != musicInfo) {
                Aria.download(PlayMusicActivity.this)
                        .load(musicInfo.getMusic_url()) // 下载地址
                        .setFilePath(getExternalCacheDir().getPath() + musicInfo.getMusic_title() + ".mp3") // 设置文件保存路径
                        .setExtendField(GsonUtils.toJson(musicInfo))
                        .create();
    
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304

    详情可私信哦~~~~~~

  • 相关阅读:
    Linux下的自动化构建工具之make/makefile的用法详解
    vue+nodejs+express+jwt如何生成并处理token
    C++实现快速排序的两种不同写法
    星宿UI V2.1 开源wordpress资源下载小程序源码,流量主激励视频广告
    最长连续不重复子序列 C++实现
    kafka生产者异步发送、同步发送、回调异步发送,是什么情况?
    简单汇编教程10 数组
    Hive的独立安装
    加快make编译速度的另一种方法
    技术分享 | OceanBase 在 Ubuntu 平台部署
  • 原文地址:https://blog.csdn.net/jky_yihuangxing/article/details/127898359