在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_STUDIO22 分钟前
Android 源码如何导入 Android Studio?踩坑与解决方案详解
android·android studio·源码阅读
EQ-雪梨蛋花汤1 小时前
【Unity&AS】Unity & Android Studio 联合开发快速入门:环境配置、AAR 集成与双向调用教程
unity·游戏引擎·android studio
前端赵哈哈1 小时前
初学者入门:Android 实现 Tab 点击切换(TabLayout + ViewPager2)
android·java·android studio
一条上岸小咸鱼5 小时前
Kotlin 控制流(二):返回和跳转
android·kotlin
Jasonakeke5 小时前
【重学 MySQL】九十二、 MySQL8 密码强度评估与配置指南
android·数据库·mysql
Mertrix_ITCH5 小时前
在 Android Studio 中修改 APK 启动图标(2025826)
android·ide·android studio
荏苒追寻5 小时前
Android OpenGL基础1——常用概念及方法解释
android
人生游戏牛马NPC1号5 小时前
学习 Android (十七) 学习 OpenCV (二)
android·opencv·学习
恋猫de小郭6 小时前
谷歌开启 Android 开发者身份验证,明年可能开始禁止“未经验证”应用的侧载,要求所有开发者向谷歌表明身份
android·前端·flutter
用户096 小时前
Gradle声明式构建总结
android