在Android Studio中如何实现综合实验MP3播放器(保姆级教程)

目录

一.本章要学习的内容

二.代码部分

(一)创建项目

(二)项目结构

(三)MainActivity

(四)MusicService

(五)activity_main.xml

(六)q.xml

(七)AndroidManifest.xml

三.运行部分

[(一)打开Device Manager](#(一)打开Device Manager)

(二)选择上次创建的虚拟机

(三)运行

(四)运行结果

一.本章要学习的内容

  1. 掌握 Android 程序的整体的设计;
  2. 融合Android的知识点;
  3. 理解Android工程的架构;
    MP 3 播放器

二.代码部分

(一)创建项目

(二)项目结构

++这里的raw包下面的china.mp3可以替换为任意的歌曲++

(三)MainActivity

复制代码
package com.example.demo8;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.animation.ObjectAnimator;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;

import org.w3c.dom.Text;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private ImageView iv_cover;
    private static SeekBar sb;
    private static TextView tv_progress, tv_total;
    private Button btn_play, btn_pause, btn_continue, btn_exit;
    private ObjectAnimator animator;

    private MusicService.MusicController musicController;//音乐服务控制器 Binder实例
    private MyserviceConn myserviceConn; //连接实例
    private Intent intent; //全局亿图
    private boolean isUnbind = false;  //记录是否被解绑

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

        initView();

    }
    private void initView(){
        iv_cover = findViewById(R.id.iv_cover);
        animator = ObjectAnimator.ofFloat(iv_cover,"rotation",0f,360.0f);
        animator.setDuration(10000); //旋转一周的时长
        animator.setInterpolator(new LinearInterpolator());  //匀速转动
        animator.setRepeatCount(-1);  //-1表示无限循环播放

        sb = findViewById(R.id.sb);
        sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            //滑动条变化的处理
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                if( i == seekBar.getMax()){  //滑动最大值,结束动画
                    animator.pause();
                }
            }
            //开始滑动时的处理
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }
            //停止滑动的处理
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                int progress = seekBar.getProgress();  //获取进度值
                //调用服务的seekTo方法改进音乐进度
                musicController.seekTo(progress);
            }
        });

        tv_progress = findViewById(R.id.tv_progress);
        tv_total = findViewById(R.id.tv_total);

        btn_play = findViewById(R.id.play);
        btn_pause = findViewById(R.id.pause);
        btn_continue = findViewById(R.id.continue2);
        btn_exit = findViewById(R.id.stop);

        intent = new Intent(MainActivity.this,MusicService.class);
        myserviceConn = new MyserviceConn();
        bindService(intent,myserviceConn,BIND_AUTO_CREATE);

        btn_play.setOnClickListener(this);
        btn_pause.setOnClickListener(this);
        btn_continue.setOnClickListener(this);
        btn_exit.setOnClickListener(this);
    }

    //自定义解绑方法
    private void myUnbind(boolean isUnbind){
        if(!isUnbind){
            isUnbind = true;
            musicController.pausePlay();  //暂停播放
            unbindService(myserviceConn); //解绑
            stopService(intent);
        }
    }

    //用于实现连接服务的自定义类
    class MyserviceConn implements ServiceConnection{

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            musicController = (MusicService.MusicController)iBinder;
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.play:
                musicController.play();
                animator.start();
                break;
            case R.id.pause:
                musicController.pausePlay();
                animator.pause();
                break;
            case R.id.continue2:
                musicController.continePlay();
                animator.start();
                break;
            case R.id.stop:
                myUnbind(isUnbind);
                finish();

                break;
        }
    }

    //创建消息处理的对象、
    public static Handler handler = new Handler(){
        //处理子线程传来的消息
        @Override
        public void handleMessage(@NonNull Message msg) {
            Bundle bundle = msg.getData(); //获取信息
            int duration = bundle.getInt("duration");
            int currentDuration = bundle.getInt("currentDuration");

            sb.setProgress(currentDuration);
            sb.setMax(duration);


            //显示总时长
            int minute = duration/1000/60;
            int second = duration/1000%60;
            String strMinute = "";
            String strSecond = "";
            if(minute<10){
                strMinute = "0"+minute;
            }else{
                strMinute = minute + "";
            }
            if(second<10){
                strSecond = "0"+second;
            }else{
                strSecond = second + "";
            }
            //显示总时长结束
            tv_total.setText(strMinute+":"+strSecond);


            //显示播放时长开始
            minute = currentDuration/1000/60;
            second = currentDuration/1000%60;
            if(minute<10){
                strMinute = "0"+minute;
            }else{
                strMinute = minute + "";
            }
            if(second<10){
                strSecond = "0"+second;
            }else{
                strSecond = second + "";
            }
            tv_progress.setText(strMinute+":"+strSecond);
            //播放时长结束

        }
    };

}

(四)MusicService

复制代码
package com.example.demo8;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;

import java.sql.Time;
import java.util.Timer;
import java.util.TimerTask;


public class MusicService extends Service {
    private MediaPlayer player;  //播放组件
    private Timer timer;    //计时器

    public MusicService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        player = new MediaPlayer();  //实例化
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        if(player==null) return;
        if(player.isLooping()){
            player.stop();
        }
        player.release();  //释放资源
        player = null;
    }



    //添加计时器 用于进度条
    public void addTime(){
        if(timer == null){
            timer = new Timer();
            TimerTask taksk = new TimerTask() {
                @Override
                public void run() {
                    if(player==null){
                        return;
                    }
                    //分别获取总长度和播放进度
                    int duration = player.getDuration();
                    int currentDuration = player.getCurrentPosition();

                    //创建Message对象
                    Message msg = MainActivity.handler.obtainMessage();
                    //将音乐的总时长,播放时长封装到消息对象中
                    Bundle bundle = new Bundle();
                    bundle.putInt("duration",duration);
                    bundle.putInt("currentDuration",currentDuration);
                    msg.setData(bundle);
                    //将消息添加到主线程
                    MainActivity.handler.sendMessage(msg);
                }
            };
            //开始计时任务后 5毫秒 执行第一次任务 以后500毫秒执行一次任务
            timer.schedule(taksk,5,500);
        }
    }

    //自定义一个Binder类
    class MusicController extends Binder{
        public void play(){
            try{
                player.reset(); //重置音乐播放器
                //加载多媒体文件
                player = MediaPlayer.create(getApplicationContext(),R.raw.china);
                player.start();
                addTime(); //添加计时器
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        public void pausePlay(){
            player.pause();  //暂停音乐播放
        }
        public void continePlay(){
            player.start();  //暂停音乐播放
        }
        public void seekTo(int progress){
            player.seekTo(progress);  //设置音乐的播放位置
        }
    }

}

(五)activity_main.xml

复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/ic_launcher_foreground"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/iv_cover"
        android:layout_width="240dp"
        android:layout_height="240dp"
        android:layout_marginTop="100dp"
        android:layout_gravity="center_horizontal"
        android:src="@drawable/ic_launcher_foreground"/>

    <SeekBar
        android:id="@+id/sb"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"/>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp">

        <TextView
            android:id="@+id/tv_progress"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="00:00"
            android:textSize="20sp"
            android:textColor="#fff"/>

        <TextView
            android:id="@+id/tv_total"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="04:50"
            android:textSize="20sp"
            android:layout_alignParentRight="true"
            android:textColor="#fff"/>
    </RelativeLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:orientation="horizontal">
        <Button
            android:id="@+id/play"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="播放音乐"
            android:textSize="16sp"
            android:layout_margin="5dp"
            android:background="@drawable/btn_bg_selector"
            android:layout_weight="1"/>
        <Button
            android:id="@+id/pause"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="暂停播放"
            android:textSize="16sp"
            android:layout_margin="5dp"
            android:background="@drawable/btn_bg_selector"
            android:layout_weight="1"/>
        <Button
            android:id="@+id/continue2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="继续播放"
            android:textSize="16sp"
            android:layout_margin="5dp"
            android:background="@drawable/btn_bg_selector"
            android:layout_weight="1"/>
        <Button
            android:id="@+id/stop"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="退出播放"
            android:textSize="16sp"
            android:layout_margin="5dp"
            android:background="@drawable/btn_bg_selector"
            android:layout_weight="1"/>
    </LinearLayout>
</LinearLayout>

(六)q.xml

复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

</LinearLayout>

(七)AndroidManifest.xml

复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.demo8">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Demo8">

        <activity android:name="com.example.demo8.MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name="com.example.demo8.MusicService"/>
    </application>

</manifest>

三.运行部分

(一)打开Device Manager

(二)选择上次创建的虚拟机

(三)运行

(四)运行结果

相关推荐
CYRUS_STUDIO18 小时前
利用 Linux 信号机制(SIGTRAP)实现 Android 下的反调试
android·安全·逆向
CYRUS_STUDIO18 小时前
Android 反调试攻防实战:多重检测手段解析与内核级绕过方案
android·操作系统·逆向
黄林晴1 天前
如何判断手机是否是纯血鸿蒙系统
android
火柴就是我1 天前
flutter 之真手势冲突处理
android·flutter
法的空间1 天前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
循环不息优化不止1 天前
深入解析安卓 Handle 机制
android
恋猫de小郭1 天前
Android 将强制应用使用主题图标,你怎么看?
android·前端·flutter
jctech1 天前
这才是2025年的插件化!ComboLite 2.0:为Compose开发者带来极致“爽”感
android·开源
用户2018792831671 天前
为何Handler的postDelayed不适合精准定时任务?
android
叽哥1 天前
Kotlin学习第 8 课:Kotlin 进阶特性:简化代码与提升效率
android·java·kotlin