移动技术开发:音乐播放器

news2024/12/23 14:49:41

1 实验名称

       音乐播放器

2 实验目的

       掌握使用Service启动服务的方法,掌握BroadcastReceiver广播传递机制的实现,利用Activity、Service和BroadcastReceiver实现一个音乐播放器APP。

3 实验源代码

布局文件代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:background="@drawable/bg"
    tools:context=".MainActivity">

    <ImageButton
        android:id="@+id/stopImageBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/stop"
        />

    <ImageButton
        android:id="@+id/playImageBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/play"
        />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        >

        <TextView
            android:id="@+id/songNameTV"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#ffffff"
            android:textSize="24sp"
            android:text="歌曲名"
            android:layout_weight="2"
            />

        <TextView
            android:id="@+id/singerNameTV"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#ffffff"
            android:textSize="20sp"
            android:text="歌手名"
            android:layout_weight="1"
            />

    </LinearLayout>

</LinearLayout>

java代码:

(1)MainActivity

package com.example.musicplayertest;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

public class MainActivity extends AppCompatActivity {
    private ImageButton stopImageBtn = null;
    private ImageButton playImageBtn = null;
    private TextView songNameTV = null;
    private TextView singerNameTV = null;

    private ServiceReceiver serviceReceiver = null;
    private IntentFilter intentFilter= null;

    private boolean isPlaying = false;//定义一个反映MusicService播放状态的变量

    //定义存放歌曲名的数组
    private String []songNames = new String[]{"若思念便思念","就在江湖之上","山外"};

    //定义存放歌手名的数组
    private String []singerNames = new String[]{"周深","刘宇宁","张远"};


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

        stopImageBtn = findViewById(R.id.stopImageBtn);
        playImageBtn = findViewById(R.id.playImageBtn);
        songNameTV = findViewById(R.id.songNameTV);
        singerNameTV = findViewById(R.id.singerNameTV);

        init();

        playImageBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("cn.edu.nuc.mainactivity");
                //控制指令:1表示播放指令,2表示暂停指令,3表示停止指令
                if (isPlaying){//如果isPlaying为真,说明后台正在播放音乐
                    intent.putExtra("control",2);//封装暂停指令
                    playImageBtn.setImageResource(R.drawable.play);//更新为播放按钮图片
                    isPlaying = false;
                }else {//后台播放状态是暂停或停止状态
                    intent.putExtra("control",1);//封装播放指令
                    playImageBtn.setImageResource(R.drawable.pause);
                    isPlaying = true;
                }
                sendBroadcast(intent);//发送带有过滤条件和控制指令的广播
            }
        });

        stopImageBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("cn.edu.nuc.mainactivity");
                intent.putExtra("control",3);//封装停止指令
                playImageBtn.setImageResource(R.drawable.play);//更新为播放按钮图片
                isPlaying = false;
                sendBroadcast(intent);
            }
        });

    }

    private void init(){
        //启动MusicService
        Intent intent = new Intent(MainActivity.this, MusicService.class);
        startService(intent);//启动MusicService
        //创建广播接收器对象
        serviceReceiver = new ServiceReceiver();
        intentFilter = new IntentFilter("cn.edu.nuc.musicservice");
        //动态注册广播接收器
        registerReceiver(serviceReceiver,intentFilter);
    }

    //定义用于接受MusicService发送的广播接收器类
    private class ServiceReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            int status = intent.getIntExtra("status",-1);
            int current = intent.getIntExtra("current",-1);
            //根据后台播放状态更新播放按钮的图片
            switch (status){
                //定义当前音乐播放状态的变量,0x11表示停止状态,0x12表示正在播放状态,0x13表示暂停状态
                case 0x11:
                    playImageBtn.setImageResource(R.drawable.play);
                    break;
                case 0x12:
                    playImageBtn.setImageResource(R.drawable.pause);
                    break;
                case 0x13:
                    playImageBtn.setImageResource(R.drawable.play);
                    break;
                default:break;
            }

            //在播放器界面对应的文本框中更新当前正在播放的歌曲信息
            if (current>=0){
                songNameTV.setText(songNames[current]);
                singerNameTV.setText(singerNames[current]);
            }
        }
    }
}

(2)MusicService

package com.example.musicplayertest;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.media.MediaPlayer;
import android.os.IBinder;

import java.io.IOException;

public class MusicService extends Service {

    //定义一个媒体播放器
    private MediaPlayer mediaPlayer = null;

    //定义一个广播接收器
    private ActivityReceiver activityReceiver = null;
    //定义广播过滤器
    private IntentFilter intentFilter = null;

    //定义资源管理器
    private AssetManager assetManager = null;

    //将歌曲文件信息存放到数组中
    String []musics = new String[]{"life.mp3","road.mp3","star.mp3"};

    //定义一个存放当前正在播放的音乐的索引值变量
    int current = 0;
    //定义当前音乐播放状态的变量,0x11表示停止状态,0x12表示正在播放状态,0x13表示暂停状态
    int status = 0x11;

    public MusicService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        activityReceiver =new ActivityReceiver();//创建广播接收器对象
        intentFilter = new IntentFilter("cn.edu.nuc.mainactivity");
        registerReceiver(activityReceiver,intentFilter);//动态注册广播接收器
        mediaPlayer = new MediaPlayer();
        //给mediaPlayer添加播放完一首歌后的事件监听处理,实现自动播放下一首
        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                current++;
                if (current>=3){
                    current = 0;
                }
                Intent sendIntent = new Intent("cn.edu.nuc.musicservice");
                sendIntent.putExtra("current",current);
                sendBroadcast(sendIntent);
                prepareAndPlay(musics[current]);
            }
        });
        assetManager = getAssets();//创建资源管理器对象
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    //定义用于接受MainActivity发送的广播的广播接收器类
    private class ActivityReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            //从MainActivity发送过来的广播中解析出控制指令
            int control = intent.getIntExtra("control",-1);
            //控制指令:1表示播放指令,2表示暂停指令,3表示停止指令
            //定义当前音乐播放状态的变量,0x11表示停止状态,0x12表示正在播放状态,0x13表示暂停状态
            switch (control){
                case 1:
                    if (status == 0x11){
                        prepareAndPlay(musics[current]);
                        status = 0x12;
                    } else if (status == 0x12) {
                        mediaPlayer.pause();
                        status = 0x13;
                    } else if (status == 0x13) {
                        mediaPlayer.start();
                        status = 0x12;
                    }
                    break;
                case 2:
                    //暂停音乐播放
                    mediaPlayer.pause();
                    status = 0x13;
                    break;
                case 3:
                    //停止音乐播放
                    mediaPlayer.stop();
                    status = 0x11;
                    break;
                default:break;
            }

            //向MainActivity发送含有当前播放状态和歌曲索引值的广播
            Intent sendIntent = new Intent("cn.edu.nuc.musicservice");
            sendIntent.putExtra("status",status);
            sendIntent.putExtra("current",current);
            sendBroadcast(sendIntent);
        }
    }

    //定义初始化音乐播放的方法
    private void prepareAndPlay(String music){
        try {
            //创建音乐文件的一个资源文件描述符
            AssetFileDescriptor assetFileDescriptor = assetManager.openFd(music);
            mediaPlayer.reset();//重置媒体播放器
            mediaPlayer.setDataSource(assetFileDescriptor.getFileDescriptor(),
                    assetFileDescriptor.getStartOffset(),
                    assetFileDescriptor.getLength());//将要播放的音乐文件设置为媒体播放器的播放资源
            mediaPlayer.prepare();//准备声音
            mediaPlayer.start();//播放音乐
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

4 实验运行结果图

5 实验总结

       第一步,写布局文件。主要是两个图片按钮和两个文本框,图像按钮分别是暂停和播放;文本框分别是歌曲名和歌手名。

       写完布局文件开始写Java代码。设置控制指令,1表示播放指令,2表示暂停指令,3表示停止指令;再定义当前音乐播放状态的变量,0x11表示停止状态,0x12表示正在播放状态,0x13表示暂停状态;再分别定义存放歌曲名和歌手名的数组,将歌曲文件信息存放到数组中。

       分别定义一个媒体播放器、广播接收器、广播过滤器、资源管理器和一个存放当前正在播放的音乐的索引值变量。关于广播接收器,先创建广播接收器对象,动态注册广播接收器,给媒体播放器添加播放完一首歌后的事件监听处理,实现自动播放下一首。关于广播接收器,定义用于接收发送过来的广播的广播接收器类,从发送过来的广播中解析出指令,向其发送含有当前播放状态和歌曲索引值的广播。关于音乐播放,定义一个初始化音乐播放的方法,创建音乐文件的一个资源文件描述符,重置媒体播放器,将要播放的音乐文件设置位媒体播放器的播放资源,准备声音播放音乐。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2182148.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

yum无法使用解决办法

yum无法使用解决方法&#xff08;比较全&#xff0c;以后如果遇到别的问题还会添加&#xff09;yum无法使用解决方法&#xff08;比较全&#xff0c;以后如果遇到别的问题还会添加&#xff09; 如下&#xff0c;新装的linux虚拟机&#xff0c;yum安装wget报错 Cannot find a …

内存占用估算方法

优质博文&#xff1a;IT-BLOG-CN 通过掌握每种数据类型的大小&#xff0c;就可以更准确地预测对象和数据的内存消耗。 一、基础数据类型 Java基础数据类型结构&#xff0c;在64位系统开启指针压缩情况下的内存占用字节数&#xff1a; booleanbytecharshortintlongfloatdoub…

D23【 python 接口自动化学习】- python 基础之判断与循环

day23 match语句 学习日期&#xff1a;20240930 学习目标&#xff1a;判断与循环 --33 match语句&#xff1a;如何通过match关键字来处理程序的分支逻辑&#xff1f; 学习笔记&#xff1a; match语句的语法 基本写法 代码实现&#xff08;后续更新为自己写的代码&#xff…

软件测试学习笔记丨Mock的价值与实战

本文转自测试人社区&#xff0c;原文链接&#xff1a;https://ceshiren.com/t/topic/32331 一、Mock的价值与意义 1.1 简介 测试过程中&#xff0c;对于一些不容易构造或获取的对象&#xff0c;用一个虚拟的对象来替代它&#xff0c;达到相同的效果&#xff0c;这个虚拟的对象…

YOLOv11尝鲜测试五分钟极简配置

ultralytics团队在最近又推出了YOLOv11&#xff0c;不知道在有生之年能不能看到YOLOv100呢哈哈。 根据官方文档&#xff0c;在 Python>3.8并且PyTorch>1.8的环境下即可安装YOLOv11&#xff0c;因此之前YOLOv8的环境是可以直接用的。 安装YOLOv11&#xff1a; pip instal…

安宝特分享 | AR技术重塑工业:数字孪生与沉浸式培训的创新应用

在数字化转型的浪潮中&#xff0c;AR&#xff08;增强现实&#xff09;技术与工业的结合正在呈现新的趋势和应用延伸。特别是“数字孪生”概念的崛起&#xff0c;为AR技术在工业中提供了独特而创新的切入点。 本文将探索AR如何与数字孪生、沉浸式体验和实用案例相结合&#xf…

OpenHarmony(鸿蒙南向开发)——小型系统芯片移植指南(一)

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ 持续更新中…… 移植须知 本文详细介绍如何将OpenHarmony小型系统的linux和LiteOS…

Elasticsearch学习笔记(3)

RestAPI Elasticsearch&#xff08;ES&#xff09;官方提供了多种语言的客户端库&#xff0c;用于与Elasticsearch进行交互。这些客户端库的主要功能是帮助开发者更方便地构建和发送DSL&#xff08;Domain Specific Language&#xff09;查询语句&#xff0c;并通过HTTP请求与…

全面提升MySQL性能:从硬件到配置再到代码的最佳实践

MySQL 是全球最流行的开源关系型数据库管理系统之一&#xff0c;广泛应用于各种规模的应用程序中。随着应用规模的增长&#xff0c;数据库的性能优化成为提升系统整体性能的关键因素。本文将从多个角度探讨如何对MySQL进行性能优化&#xff0c;帮助开发者和DBA解决实际问题&…

JWT 令牌生成报错

一、问题描述 我在获取JWT令牌时&#xff0c;报了一个这样的错误 error&#xff1a;io.jsonwebtoken.security.WeakKeyException: The signing keys size is 64 bits which is not secure enough for the HS256 algorithm. 二、问题原因 原因是我这里指定的签名密钥也就是si…

java实现的无头单向非循环链表

java实现的无头单向非循环链表 ArrayList的缺陷链表链表的概念及结构无头单向非循环链表的实现链表OJ题 ArrayList的缺陷 由于ArrayList底层是一段连续空间&#xff0c;当在ArrayList任意位置插入或者删除元素时&#xff0c;就需要将后序元素整体往前或者往后搬移&#xff0c;…

使用C语言获取iostat中的await值的方法和方案

使用C语言获取iostat中的await值的方法和方案 1. 准备工作2. 调用iostat命令并获取输出3. 解析iostat输出4. 完整实现和错误处理5. 注意事项在Linux系统中,iostat命令是sysstat软件包的一部分,用于监控系统的CPU、网卡、tty设备、磁盘、CD-ROM等设备的活动情况和负载信息。其…

逻辑回归(下): Sigmoid 函数的发展历史

背景 闲来无事翻了一下之前买的一个机器学习课程及之前记录的网络笔记&#xff0c;发现遇到公式都是截图&#xff0c;甚至是在纸上用笔推导的。重新整理一遍之前逻辑回归函数的学习笔记&#xff0c;主要是为了玩一下 LaTex 语法&#xff0c;写公式挺有意思的。 整理之前三篇笔…

VMware 虚拟机 下载安装 Centos7 和Windows10 镜像源

准备工作 下载 VMware链接&#xff1a;稍后发布链接 Centos7完整版链接&#xff1a;https://www.123865.com/ps/EF7OTd-mdAnH Centos7mini版链接&#xff1a;https://www.123865.com/ps/EF7OTd-1dAnH Windows10链接&#xff1a;https://www.123865.com/ps/EF7OTd-4dAnH 演示环境…

win11任务栏颜色怎么修改?透明任务栏效果可以实现吗?5套方案!

win11任务栏颜色怎么修改&#xff1f; ■ 通过系统个性化设置、任务栏设置、金舟Translucent任务栏、Glass8、注册表等方式可以快速修改Windows11电脑任务栏颜色。 在重度使用电脑办公的过程中&#xff0c;大家除了对电脑壁纸有一点的设计感外&#xff0c;小编发现不少人对电…

【Qt】Qt安装(2024-10,QT6.7.3,Windows,Qt Creator 、Visual Studio、Pycharm 示例)

文章目录 一、Qt 简介二、安装开源版本2.1 Qt 官网 与 版本选择2.2 Qt 安装程序 三、使用示例3.1 Qt Creator3.11 示例程序3.12 新建C项目3.13 新建Python项目 3.2 Visual Studio 附录附录 1&#xff1a;Additional Libraries 说明附录2 &#xff1a;老版本安装附录3&#xff1…

基于大数据架构的就业岗位推荐系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

Redis入门第一步:认识Redis与快速安装配置

认识Redis与快速安装配置&#x1f343; Redis是什么&#x1f432; 1.Redis的背景&#x1f38d; Redis&#xff08;Remote Dictionary Server&#xff09;译为"远程字典服务"&#xff0c;它是一款基于内存实现的键值型 NoSQL 数据库&#xff0c; 通常也被称为数据结…

An End-to-End Local Attention Based Model for Table Recognition(ICDAR 2023)

An End-to-End Local Attention Based Model for Table Recognition(ICDAR 2023) 一.前述 作者认为基于Transformer的表格识别模型很难处理大表格的识别&#xff0c;原因是受限于它的全局注意力global attention机制。 基于以上&#xff0c;作者提出了一种局部注意力local a…

【HTML并不简单】笔记1-常用rel总结:nofollow、noopener、opener、noreferrer,relList

文章目录 rel"nofollow"rel"noopener"与rel"opener"rel"noreferrer"relList对象 《HTML并不简单&#xff1a;Web前端开发精进秘籍》张鑫旭&#xff0c;一些摘要&#xff1a; HTML&#xff0c;这门语言的知识体系非常庞杂&#xff0c;涉…