效果图:
实现思路:
1.把raw的资源文件写入本地存储
package com.example.longshine.zname;
import android.content.Context;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by 16857 on 2019/4/17.
*/
public class FileStorageHelper {
private static final String SEPARATOR = File.separator;//路径分隔符
/**
* 复制res/raw中的文件到指定目录
*
* @param context 上下文
* @param id 资源ID
* @param fileName 文件名
* @param storagePath 目标文件夹的路径
*/
public static void copyFilesFromRaw(Context context, int id, String fileName, String storagePath) {
InputStream inputStream = context.getResources().openRawResource(id);
File file = new File(storagePath);
if (!file.exists()) {//如果文件夹不存在,则创建新的文件夹
file.mkdirs();
}
readInputStream(storagePath + SEPARATOR + fileName, inputStream);
}
/**
* 读取输入流中的数据写入输出流
*
* @param storagePath 目标文件路径
* @param inputStream 输入流
*/
public static void readInputStream(String storagePath, InputStream inputStream) {
File file = new File(storagePath);
try {
if (!file.exists()) {
// 1.建立通道对象
FileOutputStream fos = new FileOutputStream(file);
// 2.定义存储空间
byte[] buffer = new byte[inputStream.available()];
// 3.开始读文件
int lenght = 0;
while ((lenght = inputStream.read(buffer)) != -1) {// 循环从输入流读取buffer字节
// 将Buffer中的数据写到outputStream对象中
fos.write(buffer, 0, lenght);
}
fos.flush();// 刷新缓冲区
// 4.关闭流
fos.close();
inputStream.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.使用mediaplayer方法,在服务中实现播放音乐
package com.example.longshine.zname;
import android.Manifest;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import .Activity;
import .ActivityManager;
import .Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import .PackageManager;
import .MediaPlayer;
import android.os.Binder;
import android.os.Environment;
import android.os.IBinder;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.view.animation.LinearInterpolator;
import java.io.File;
import java.util.List;
/**
* Created by kx on 2016/11/3.
*/
public class MusicService extends Service {
public final IBinder binder = new MyBinder();
public class MyBinder extends Binder {
MusicService getService() {
return MusicService.this;
}
}
public static int isReturnTo = 0;
public static MediaPlayer mediaPlayer = new MediaPlayer();
public static ObjectAnimator animator;
public MusicService() {
initMediaPlayer();
}
public void initMediaPlayer() {
try {
mediaPlayer.setDataSource(FilePath.TESTAURL);
mediaPlayer.prepare();
mediaPlayer.setLooping(true); // 设置循环播放
} catch (Exception e) {
e.printStackTrace();
}
}
public void AnimatorAction() {
if (mediaPlayer.isPlaying()) {
animator.setDuration(5000);
animator.setInterpolator(new LinearInterpolator()); // 均速旋转
animator.setRepeatCount(ValueAnimator.INFINITE); // 无限循环
animator.setRepeatMode(ValueAnimator.INFINITE);
animator.start();
}
}
private int flag = 0;
public static String which = "";
public void playOrPause() {
flag++;
if (flag >= 1000) flag = 2;
which = "pause";
if(mediaPlayer.isPlaying()){
mediaPlayer.pause();
animator.pause();
} else {
mediaPlayer.start();
if ((flag == 1) || (isReturnTo == 1)) {
animator.setDuration(5000);
animator.setInterpolator(new LinearInterpolator()); // 均速旋转
animator.setRepeatCount(ValueAnimator.INFINITE); // 无限循环
animator.setRepeatMode(ValueAnimator.INFINITE);
animator.start();
} else {
animator.resume();
}
}
}
public void stop() {
which = "stop";
animator.pause();
if(mediaPlayer != null) {
mediaPlayer.pause();
mediaPlayer.stop();
try {
mediaPlayer.prepare();
mediaPlayer.seekTo(0);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void onDestroy() {
mediaPlayer.stop();
mediaPlayer.release();
super.onDestroy();
}
/**
* onBind 是 Service 的虚方法,因此我们不得不实现它。
* 返回 null,表示客服端不能建立到此服务的连接。
*/
@Override
public IBinder onBind(Intent intent) {
return binder;
}
}
3.一个全局的固定不变的路径
public class FilePath { public final static String TESTAURL = Environment.getExternalStorageDirectory().getAbsolutePath().toString()+"/bgmusic1.mp3"; }
4.清单文件去添加权限申请和注册服务
权限注册
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.GET_TASKS" />
服务注册
<service android:name="com.example.longshine.zname.MusicService"
5.简单的放一下布局文件吧
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http:///apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/relatives">
<ImageView
android:id="@+id/coverImage"
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_marginTop="20dp"
android:src="@mipmap/img"
android:scaleType="centerInside"
android:layout_centerHorizontal="true"/>
<TextView
android:id="@+id/stateText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/coverImage"
android:padding="15dp"
android:text="IDLE"
android:textSize="20dp"/>
<TableRow
android:id="@+id/row1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/stateText"
android:padding="15dp">
<TextView
android:id="@+id/playingTime"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="00:00"
android:textSize="20dp"/>
<SeekBar
android:id="@+id/seekBar"
android:layout_weight="4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"/>
<TextView
android:id="@+id/totalTime"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="00:00"
android:textSize="20dp"/>
</TableRow>
<TableRow
android:id="@+id/row2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:padding="15dp"
android:layout_below="@+id/row1"
android:layout_alignParentStart="true">
<Button
android:id="@+id/isPlayButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="22dp"
android:text="PLAY" />
<Button
android:id="@+id/stopButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="22dp"
android:text="STOP"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"/>
<Button
android:id="@+id/quitButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="22dp"
android:text="QUIT" />
</TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/row2"
android:layout_centerHorizontal="true"
android:textSize="18dp"
android:id="@+id/pathText"/>
<Button
android:id="@+id/copyButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="22dp"
android:text="歌曲初始化" />
</RelativeLayout>
6.最后,就是在界面做事件响应和调用了
package com.example.longshine.zname;
import android.Manifest;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import .Activity;
import .ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import .PackageManager;
import .MediaPlayer;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.app.ActivityCompat;
import .AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.LinearInterpolator;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private Button isPlay,copyButton;
private Button stop;
private Button quit;
private ImageView coverImage;
// private ObjectAnimator animator;
private int flag = 0;
private TextView totalTime;
private TextView playingTime;
private TextView stateText;
private SeekBar seekBar;
private TextView pathText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getOverflowMenu();
setContentView(R.layout.activity_main);
bindServiceConnection();
musicService = new MusicService();
coverImage = (ImageView) findViewById(.coverImage);
musicService.animator = ObjectAnimator.ofFloat(coverImage, "rotation", 0, 359);
isPlay = (Button) findViewById(.isPlayButton);
isPlay.setOnClickListener(new myOnClickListener());
stop = (Button) findViewById(.stopButton);
stop.setOnClickListener(new myOnClickListener());
quit = (Button) findViewById(.quitButton);
quit.setOnClickListener(new myOnClickListener());
seekBar = (SeekBar) findViewById(.seekBar);
seekBar.setProgress(musicService.mediaPlayer.getCurrentPosition());
seekBar.setMax(musicService.mediaPlayer.getDuration());
totalTime = (TextView) findViewById(.totalTime);
playingTime = (TextView) findViewById(.playingTime);
stateText = (TextView) findViewById(.stateText);
pathText = (TextView) findViewById(.pathText);
copyButton= (Button) findViewById(.copyButton);
copyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//raw开始复制文件到内存卡
FileStorageHelper.copyFilesFromRaw(MainActivity.this, R.raw.bgmusic1, "bgmusic1.mp3", Environment.getExternalStorageDirectory().getAbsolutePath().toString() + "/");
}
});
//pathText.setText(FilePath.);
}
private MusicService musicService;
private SimpleDateFormat time = new SimpleDateFormat("mm:ss");
private ServiceConnection sc = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
musicService = ((MusicService.MyBinder) iBinder).getService();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
musicService = null;
}
};
private void bindServiceConnection() {
Intent intent = new Intent(this, MusicService.class);
startService(intent);
bindService(intent, sc, this.BIND_AUTO_CREATE);
}
public Handler handler = new Handler();
public Runnable runnable = new Runnable() {
@Override
public void run() {
isPlay.setOnClickListener(new myOnClickListener());
stop.setOnClickListener(new myOnClickListener());
quit.setOnClickListener(new myOnClickListener());
if(musicService.mediaPlayer.isPlaying()) {
stateText.setText("Playing");
} else {
if (musicService.which.equals("stop")) {
stateText.setText("Stop");
} else if (musicService.which.equals("pause")){
stateText.setText("Pause");
}
}
playingTime.setText(time.format(musicService.mediaPlayer.getCurrentPosition()));
totalTime.setText(time.format(musicService.mediaPlayer.getDuration()));
seekBar.setProgress(musicService.mediaPlayer.getCurrentPosition());
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
musicService.mediaPlayer.seekTo(seekBar.getProgress());
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
handler.postDelayed(runnable, 100);
}
};
@Override
public void onPause(){
super.onPause();
if(isApplicationBroughtToBackground()) {
musicService.isReturnTo = 1;
Log.e("b","后台中");
}
}
@Override
public void onRestart() {
super.onRestart();
musicService.isReturnTo = 1;
}
@Override
protected void onResume() {
musicService.AnimatorAction();
verifyStoragePermissions(this);
if(musicService.mediaPlayer.isPlaying()) {
stateText.setText("Playing");
} else {
if (musicService.which.equals("stop")) {
stateText.setText("Stop");
} else if (musicService.which.equals("pause")){
stateText.setText("Pause");
}
}
seekBar.setProgress(musicService.mediaPlayer.getCurrentPosition());
seekBar.setMax(musicService.mediaPlayer.getDuration());
handler.post(runnable);
super.onResume();
Log.d("hint", "handler post runnable");
}
private class myOnClickListener implements View.OnClickListener {
@Override
public void onClick(View view) {
switch (view.getId()) {
case .isPlayButton:
changePlay();
musicService.playOrPause();
break;
case .stopButton:
musicService.stop();
changeStop();
break;
case .quitButton:
quit();
break;
default:
break;
}
}
}
private void changePlay() {
if(musicService.mediaPlayer.isPlaying()){
stateText.setText("Pause");
isPlay.setText("PLAY");
//animator.pause();
} else {
stateText.setText("Playing");
isPlay.setText("PAUSE");
}
}
private void changeStop() {
stateText.setText("Stop");
seekBar.setProgress(0);
//animator.pause();
}
private void quit() {
musicService.animator.end();
handler.removeCallbacks(runnable);
unbindService(sc);
try {
finish();
System.exit(0);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onStop() {
super.onStop();
}
@Override
public void onDestroy() {
unbindService(sc);
super.onDestroy();
}
private void getOverflowMenu() {
try {
ViewConfiguration config = ViewConfiguration.get(this);
Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
if (menuKeyField != null) {
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/*public static boolean isBackground(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.processName.equals(context.getPackageName())) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
Log.i("后台", appProcess.processName);
return true;
}else{
Log.i("前台", appProcess.processName);
return false;
}
}
}
return false;
}*/
private boolean isApplicationBroughtToBackground() {
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(getPackageName())) {
return true;
}
}
return false;
}
// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
/**
* Checks if the app has permission to write to device storage
*
* If the app does not has permission then the user will be prompted to grant permissions
*
* @param activity
*/
public static void verifyStoragePermissions(Activity activity) {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
}