使用Android Studio开发一个简易的音乐播放器
阅读原文时间:2021年04月20日阅读:1

系统运行界面展示:

第一步要先把歌曲导进模拟器,导入模拟器的时候要先获取权限:

  • 首先,要获得虚拟设备Root权限。
  • 命令行工具,切换到『sdk目录』/platform-tools/ (或者将上述目录加入环境变量Path) 。
  • 运行 adb root
  • 然后,开启ADB集成
  • Tools->Android->勾选Enable ADB Integration
  • 向手机中推送音频文件:
  • Tools—Android—Android Device Monitor


1系统需求分析
1.1 登录模块
输入用户名和密码(初始用户名为admin,密码为123456),实现用户的登入和退出功能。
1.2 音乐列表
显示所有的歌手名和歌曲名,单击某首歌曲跳转到播放界面,长按实现删除歌曲的功能。
1.3 播放界面
显示正在播放歌曲的相关信息,如歌曲名,对应的歌手名,当前播放时间,歌曲总时间等,并且可拖动进度条实现快进、快退功能以及循环播放和单曲循环功能。

2系统总体设计
2.1系统整体结构

2.2数据存储设计
MediaStore类是android系统提供的一个多媒体数据库,android中多媒体信息都可以从这里提取。MediaStore包括了多媒体数据库的所有信息,包括音频,视频和图像,android把所有的多媒体数据库接口进行了封装,所有的数据库不用自己进行创建,直接调用利用ContentResolver去调用那些封装好的接口就可以进行数据库的操作了。比如,这次实验利用了ContentProvider(内容提供者)去调用安卓系统自带SQLite音频数据库,路径地址为MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,返回的结果为cursor结果集接口,此过程简单方便,适合此次设计的使用。

3系统详细设计
3.1 登录功能
用户输入账号和密码实现登录,并且在此界面实现获取系统权限的功能。
关键代码如下:

public class LoginActivity extends AppCompatActivity {
    ...
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        if (ContextCompat.checkSelfPermission(LoginActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(LoginActivity.this,
                    new String[]{
                            Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        }
       ...
   login = (Button) findViewById(R.id.login);
       login.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ...
                if (account.equals("admin") && password.equals("123456")) {
                    Intent intent = new Intent(LoginActivity.this, MusicListActivity.class);
                    startActivity(intent);
                } else {
                    Toast.makeText(LoginActivity.this, "用户名或密码错误,请重新输入!", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

    public void onRequestPermissionsResult(int requestCode, String[] permissions,
                                           int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0 && grantResults[0] != PackageManager.
                        PERMISSION_GRANTED) {
                    Toast.makeText(this, "拒绝权限将无法使用程序",
                            Toast.LENGTH_SHORT).show();
                    finish();
                }
                break;
            default:
                break;
        }
    }

}

3.2 音乐列表功能
用户可查看音乐列表,选择播放或删除某一首音乐,单击实现跳转播放,长按实现是否选择删除功能。
关键代码如下:

//查询媒体数据库
    Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null,
            null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
    //遍历数据库
    if (cursor.moveToFirst()) {
        while (!cursor.isAfterLast()) {
            //路径
            String uri = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
           ...     
File file = new File(uri);
            if (isMusic != 0 && file.exists()) {
                Music music = new Music(uri, musicName, artistName);
                musicList.add(music);
            }
        }
    }
   ...
    //短按实现跳转播放
    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view,
                                int position, long id) {
            Intent intent = new Intent(MusicListActivity.this, MusicPlayActivity.class);
            intent.putExtra("position", position);
            startActivity(intent);
        }
    });
    //长按选择是否删除歌曲
    listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
        @Override
        public boolean onItemLongClick(AdapterView<?> parent, View view,
                                       final int position, long id) {
            final Music music = musicList.get(position);
            AlertDialog.Builder dialog = new AlertDialog.Builder(MusicListActivity.this);
            dialog.setTitle("提示:");
            dialog.setMessage("是否删除这首歌曲?");
            dialog.setCancelable(false);
            dialog.setPositiveButton("删除", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    //删除音乐文件
                    File file = new File(music.getUri());
                    file.delete();
                    //删除媒体数据库记录
                    getContentResolver().delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                            MediaStore.Audio.Media.DATA + " LIKE ?", new String[]{music.getUri()});
                    musicList.remove(position);
                    adapter.notifyDataSetChanged();
                }
            });
            dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                }
            });
            dialog.show();
            return true;
        }
    });
}

3.3 播放界面功能
用户可选择不同的播放模式,如顺序播放或单曲循环,并且可选择播放上一首或下一首乐曲,以及可实现拖拉进度条调整音乐播放进度的功能。
关键代码如下:

public Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case UPDATE_TEXT:
                    musicName.setText(songName);
                    artist.setText(artistName);
                    musicTime.setText(time.format(mediaPlayer.getCurrentPosition()));
                    musicTotal.setText(time.format(mediaPlayer.getDuration()));
                    seekBar.setMax(mediaPlayer.getDuration());
                    seekBar.setProgress(mediaPlayer.getCurrentPosition());
                    break;
                default:
                    break;
            }
        }
    };

      protected void onCreate(Bundle savedInstanceState) {
        ...
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            // 拖动条停止拖动的时候调用
            public void onStopTrackingTouch(SeekBar seekBar) {
                int progress = seekBar.getProgress();
                mediaPlayer.seekTo(progress);
            }
            ...
           );

        new Thread(new Runnable() {
            @Override
            public void run() {
                if (flag) {
                    Message message = new Message();
                    message.what = UPDATE_TEXT;
                    handler.sendMessage(message);
                    handler.postDelayed(this, 1000);
                }
            }
        }).start();
      }

    private void initMediaPlayer() {
        try {
            Music music = musicList.get(position);//得到当前播放音乐的路径
            artistName = music.getArtistName();//获得歌手名
            songName = music.getMusicName();//获得歌名
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);// 指定参数为音频文件
            mediaPlayer.setDataSource(music.getUri());//为多媒体对象设置播放路径
            mediaPlayer.prepare();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.prev://上一首
                position = position == 0 ? musicList.size() - 1 : position - 1;
                mediaPlayer.reset();
                initMediaPlayer();
                play.setText("■");
                musicName.setText(songName);
                artist.setText(artistName);
                mediaPlayer.start();
                break;
            case R.id.play://开始
                if (!mediaPlayer.isPlaying()) {
                    play.setText("■");
                    musicName.setText(songName);
                    artist.setText(artistName);
                    mediaPlayer.start();
                } else {//暂停
                    play.setText("▶");
                    mediaPlayer.pause();
                }
                break;
            case R.id.next://下一首
                position = position == musicList.size() - 1 ? 0 : position + 1;
                mediaPlayer.reset();
                initMediaPlayer();
                play.setText("■");
                musicName.setText(songName);
                artist.setText(artistName);
                mediaPlayer.start();
                break;
            default:
                break;
        }
    }

    //顺序播放或单曲循环
    public void automaticPlay() {

        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            public void onCompletion(MediaPlayer arg0) {
                if (valid) {
                    position = position == musicList.size() - 1 ? 0 : position + 1;
                    mediaPlayer.reset();
                    initMediaPlayer();
                    play.setText("■");
                    musicName.setText(songName);
                    mediaPlayer.start();
                    //Log.d("valid", "true");
                } else {
                    mediaPlayer.reset();
                    initMediaPlayer();
                    mediaPlayer.start();
                    Log.d("valid", "false");
                }
            }
        });
    }

    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.sequential_play:
                valid = true;
                Toast.makeText(this, "顺序播放", Toast.LENGTH_SHORT).show();
                break;
            case R.id.single_play:
                valid = false;
                Toast.makeText(this, "单曲循环", Toast.LENGTH_SHORT).show();
                break;
            default:
        }
        return true;
    }
}

4结论与心得体会
通过对各个模块的调试,基本都实现了该系统的功能。