Android本地音乐播放器
程序员文章站
2022-05-29 22:19:22
...
一,需要知识点:
1,Drawerlayout侧滑菜单实现。
2,ListView的使用及其点击事件的监听。
3,如何打开文件管理器选择特定文件,并获取被选文件的路径。
4,Service服务的使用。
5,如何使用新线程动态给UI线程发送消息更新Seekbar进度。
6,MediaPlayer的使用。
二,写代码时遇到的坑。
1,在新开的线程中是不能修改UI组件的,否则程序会崩溃,写的时候因为这个程序一直崩溃我也很绝望。
2,找如何打开系统浏览器找了半天。
布局文件(线性布局):
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout 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/drawerlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg3"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
>
<TextView
android:id="@+id/imageview"
android:layout_width="match_parent"
android:layout_height="300dp"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="当前正在播放:无歌曲"
android:textSize="25sp"
android:id="@+id/nowplayText"
android:lines="2"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal"
android:layout_marginTop="10dp"
>
<TextView
android:id="@+id/leftText"
android:text="00:00"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:layout_marginLeft="5dp"
/>
<SeekBar
android:id="@+id/seekbar"
android:layout_width="272dp"
android:layout_height="match_parent"
/>
<TextView
android:id="@+id/rightText"
android:text="99:99"
android:gravity="center"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:gravity="center"
>
<Button
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/open_btn"
android:text="打开"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/stop_btn"
android:text="停止"
/>
<ImageButton
android:id="@+id/imagebutton_exit"
android:layout_width="50dp"
android:layout_height="match_parent"
android:background="@drawable/exit_btn"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/pre_btn"
android:text="上一曲"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/start_btn"
android:text="播放"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/next_btn"
android:text="下一曲"
/>
<Button
android:id="@+id/menu_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="菜单" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="200dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:id="@+id/leftview"
>
<ListView
android:id="@+id/listview"
android:layout_width="200dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
android:background="@drawable/bg4"
>
</ListView>
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
MainActivity文件:
package com.example.my.musicplayer;
import android.Manifest;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.app.Notification;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.provider.MediaStore;
import android.support.annotation.RequiresApi;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.animation.Interpolator;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.sql.Time;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends AppCompatActivity implements View.OnClickListener,SeekBar.OnSeekBarChangeListener,AdapterView.OnItemClickListener {
private Button start_btn,pre_btn,next_btn,open_btn,stop_btn,menu_btn;
private TextView nowText,leftText,rightText,imageview;
public SeekBar seekBar;
private ListView listView=null;
private ArrayAdapter<String>adapter;
private MediaPlayer mediaPlayer;
private MusicService musicService;
private String path;
public Handler handler;
private ImageButton exit_btn;
private int second;
private int nowsecond;
private CFilelist musicfile=new CFilelist();
private int nowindex=0;
private LinearLayout left_view=null;
private DrawerLayout mDrawerLayout=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
menu_btn= (Button) findViewById(R.id.menu_btn);
menu_btn.setOnClickListener(this);
start_btn= (Button) findViewById(R.id.start_btn);
start_btn.setOnClickListener(this);
pre_btn= (Button) findViewById(R.id.pre_btn);
pre_btn.setOnClickListener(this);
next_btn= (Button) findViewById(R.id.next_btn);
next_btn.setOnClickListener(this);
open_btn= (Button) findViewById(R.id.open_btn);
open_btn.setOnClickListener(this);
stop_btn= (Button) findViewById(R.id.stop_btn);
stop_btn.setOnClickListener(this);
seekBar= (SeekBar) findViewById(R.id.seekbar);
seekBar.setOnSeekBarChangeListener(this);
nowText= (TextView) findViewById(R.id.nowplayText);
leftText= (TextView) findViewById(R.id.leftText);
rightText= (TextView) findViewById(R.id.rightText);
exit_btn= (ImageButton) findViewById(R.id.imagebutton_exit);
exit_btn.setOnClickListener(this);
listView= (ListView) findViewById(R.id.listview);
adapter=new ArrayAdapter<String>(this,R.layout.support_simple_spinner_dropdown_item,musicfile.listname);
listView.setAdapter(adapter);
listView.setOnItemClickListener(this);
imageview= (TextView) findViewById(R.id.imageview);
listView.getBackground().setAlpha(150);
left_view= (LinearLayout) findViewById(R.id.leftview);
mDrawerLayout= (DrawerLayout) findViewById(R.id.drawerlayout);
isGrantExternalRW(this);
//通过绑定方式启动Service
bindMusicService();
handler=new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 0x123) {
if(mediaPlayer.isPlaying()) {
seekBar.setMax(second);
seekBar.setProgress(nowsecond);
leftText.setText(change(nowsecond));
rightText.setText(change(second));
}
}
}
};
new Timer().schedule(new TimerTask() {
@Override
public void run() {
if(mediaPlayer!=null) {
second = musicService.mediaPlayer.getDuration();
nowsecond = musicService.mediaPlayer.getCurrentPosition();
//Toast.makeText(MainActivity.this,second+"",Toast.LENGTH_SHORT).show();
handler.sendEmptyMessage(0x123);
}
}
},0,1000);
}
private void bindMusicService()
{
Intent intent=new Intent(this,MusicService.class);
//启动服务
startService(intent);
//绑定服务
bindService(intent,serviceConnection,this.BIND_AUTO_CREATE);
}
private ServiceConnection serviceConnection=new ServiceConnection() {
//回调函数;1,连接服务时调用2,取消服务连接
//连接服务时调用
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//获取service服务
musicService=((MusicService.MyBinder)iBinder).getService();
//获取mediaplayer
mediaPlayer=musicService.mediaPlayer;
path=musicService.path;
//初始化进度条总时间
int second=musicService.mediaPlayer.getDuration();
second/=1000;
rightText.setText("0"+second/60+":"+second%60);
}
//取消服务连接时调用
@Override
public void onServiceDisconnected(ComponentName componentName) {
musicService=null;
}
};
//安卓6.0以上读取内存文件需要手动请求权限
public static boolean isGrantExternalRW(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && activity.checkSelfPermission(
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
activity.requestPermissions(new String[]{
//内存卡读写
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, 1);
return false;
}
return true;
}
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1) {
for (int i = 0; i < permissions.length; i++) {
String permission = permissions[i];
int grantResult = grantResults[i];
if (permission.equals(Manifest.permission.READ_EXTERNAL_STORAGE)) {
if (grantResult == PackageManager.PERMISSION_GRANTED) {
//授权成功后的逻辑
} else {
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
}
}
}
}
}
@Override
public void onClick(View view) {
switch (view.getId())
{
case R.id.start_btn: {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
//mediaPlayer.prepareAsync();
start_btn.setText("播放");
//objectAnimator.pause();
} else {
mediaPlayer.start();
start_btn.setText("暂停");
}
break;
}
case R.id.stop_btn:
{
if(mediaPlayer!=null) {
musicService.tag = false;
mediaPlayer.stop();
mediaPlayer.prepareAsync();
start_btn.setText("播放");
}
mediaPlayer.seekTo(0);
seekBar.setProgress(0);
break;
}
case R.id.imagebutton_exit:
{
unbindService(serviceConnection);
Intent intent=new Intent(this,MusicService.class);
stopService(intent);
try {
MainActivity.this.finish();
}catch (Exception e)
{
e.printStackTrace();
}
break;
}
case R.id.pre_btn:
{
if(musicfile.pathlist.size()==0)
{
Toast.makeText(this, "文件为空不能播放,请点击打开添加歌曲再进行播放", Toast.LENGTH_SHORT).show();
break;
}
nowindex--;
if(nowindex<0)
{
if(musicfile.pathlist.size()!=0)
nowindex=musicfile.pathlist.size()-1;
}
if(mediaPlayer!=null) {
mediaPlayer.stop();
mediaPlayer.reset();
seekBar.setProgress(0);
start_btn.setText("播放");
//Toast.makeText(this, "当前播放路径为:"+musicfile.pathlist.get(nowindex), Toast.LENGTH_SHORT).show();
try {
mediaPlayer.setDataSource(musicfile.pathlist.get(nowindex));
mediaPlayer.prepareAsync();
nowText.setText("当前正在播放:"+musicfile.listname.get(nowindex));
//mediaPlayer.start();
} catch (IOException e) {
e.printStackTrace();
}
}
break;
}
case R.id.next_btn:
{
if(musicfile.pathlist.size()==0)
{
Toast.makeText(this, "文件为空不能播放,请点击打开添加歌曲再进行播放", Toast.LENGTH_SHORT).show();
break;
}
nowindex++;
if(nowindex>=musicfile.pathlist.size())
{
if(musicfile.pathlist.size()!=0)
nowindex=0;
}
if(mediaPlayer!=null) {
mediaPlayer.stop();
mediaPlayer.reset();
seekBar.setProgress(0);
start_btn.setText("播放");
//Toast.makeText(this, "当前播放路径为:"+musicfile.pathlist.get(nowindex), Toast.LENGTH_SHORT).show();
try {
mediaPlayer.setDataSource(musicfile.pathlist.get(nowindex));
mediaPlayer.prepareAsync();
nowText.setText("当前正在播放:"+musicfile.listname.get(nowindex));
} catch (IOException e) {
e.printStackTrace();
}
}
break;
}
case R.id.open_btn:
{
//打开系统自带文件浏览器
Intent i=new Intent(Intent.ACTION_GET_CONTENT);
i.setType("audio/*");
i.addCategory(Intent.CATEGORY_OPENABLE);
this.startActivityForResult(i,1);
break;
}
case R.id.menu_btn:
{
if(!mDrawerLayout.isDrawerOpen(left_view))
{
mDrawerLayout.openDrawer(left_view);
}
break;
}
}
}
//重写返回键的功能
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//设置后台继续播放音乐
if(keyCode==KeyEvent.KEYCODE_BACK)
{
moveTaskToBack(false);
}
return super.onKeyDown(keyCode, event);
}
private String change(int xx)
{
xx/=1000;
String arg=new String();
int t=xx/60;
if(t<10){
arg+="0";
}
arg+=t;
t=xx%60;
arg+=":";
if(t<10){
arg+="0";
}
arg+=t;
return arg;
}
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
leftText.setText(change(seekBar.getProgress()));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
if(mediaPlayer!=null)
{
//如果音乐正在播放才更新播放进度
if(mediaPlayer.isPlaying()) {
mediaPlayer.seekTo(seekBar.getProgress());
}
else
{
seekBar.setProgress(0);
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode==1)
{
//将Url转换成真实路径
Uri uri = data.getData();
String[] proj = { MediaStore.Images.Media.DATA };
Cursor actualimagecursor = getContentResolver().query(uri,proj,null,null,null);
int actual_image_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
actualimagecursor.moveToFirst();
String img_path = actualimagecursor.getString(actual_image_column_index);
//Toast.makeText(this, img_path, Toast.LENGTH_LONG).show();
musicfile.pathlist.add(img_path);
//从文件末尾提取歌名
String[] st=img_path.split("/");
musicfile.listname.add(st[st.length-1]);
Toast.makeText(this, "歌曲添加成功,点击下一首即可播放", Toast.LENGTH_SHORT).show();
//更改ListView信息
adapter.notifyDataSetChanged();
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
mediaPlayer.stop();
mediaPlayer.reset();
try {
mediaPlayer.setDataSource(musicfile.pathlist.get(i));
mediaPlayer.prepareAsync();
nowText.setText("当前正在播放:"+musicfile.listname.get(i));
start_btn.setText("播放");
mDrawerLayout.closeDrawer(left_view);
} catch (IOException e) {
e.printStackTrace();
}
}
}
class CFilelist
{
public List<String>pathlist=new ArrayList<String>();
public List<String>listname=new ArrayList<String>();
}
package com.example.my.musicplayer;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
public class MusicService extends Service {
public MediaPlayer mediaPlayer;
public boolean tag=false;
public MyBinder binder=new MyBinder();
//内部储存卡路径
public String path= Environment.getExternalStorageDirectory().getPath();
public MusicService() {
mediaPlayer=new MediaPlayer();
try
{
mediaPlayer.setDataSource(path+"/music.mp3");
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return binder;
//throw new UnsupportedOperationException("Not yet implemented");
}
public class MyBinder extends Binder
{
MusicService getService()
{
return MusicService.this;
}
}
}
播放器功能:
可以添加本地歌曲进行播放,添加的歌曲再右边侧滑栏显示,点击即可播放。
实现效果:
上一篇: Android音乐播放器-热门榜单