为了让案例代码简单易懂,本案例虽然是以播放音乐功能进行演示,但是为了减少代码量,让演示功能可以更直观地理解,本案例只选取一首固定的mp3进行操作演示,但播放mp3使用了安卓内置的MediaPlayer类,该类可以胜任音频和视频的播放,如果想详细了解,请查阅该类的技术文档。
先添加音乐服务类MusicService 继承 Service
因为是简单的播放功能 所以用MediaPlayer
public class MusicService extends Service {
private MediaPlayer mediaPlayer;
public MusicService() {//此构造方法必须写 要不然会报错
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}//可以自己定义 IBinder 用来调用方法 通信
@Override
public void onCreate() {
super.onCreate();
this.mediaPlayer = MediaPlayer.create(this,R.raw.xinghe);//创建
this.mediaPlayer.start();//播放
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {//开启服务
Log.d("TAG", "onStartCommand: " + intent.getAction());
if (intent.getAction()!=null&&intent.getAction().equals("STOP")){
this.mediaPlayer.pause();
}
if (intent.getAction()!=null&&intent.getAction().equals("EXIT")){
System.exit(0);
}
if (intent.getAction()!=null&&intent.getAction().equals("START")) {
this.mediaPlayer.start();
}
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
this.mediaPlayer.stop();
}
}
然后要在 manifest中添加 (不添加服务类无法使用)
<service android:name=".MusicService">
<intent-filter>
<action android:name="com.example.mymusic.MusicPlayer"></action>
</intent-filter>
</service>
然后为通知栏新建一个布局文件(不能太复杂 尽量简洁 要不然通知栏显示不出来)
然后新建一个MusicFragment继承Fragment
把刚刚新建的 layout和MusicFragment绑定
public class MusicFragment extends Fragment {
private View view;
private Intent svc_intent;
public boolean isplay = false;
private Context context;
private ServiceConnection sc = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
public boolean isIsplay() {
return isplay;
}
public void setIsplay(boolean isplay) {
this.isplay = isplay;
}
public MusicFragment(Context context){
svc_intent = new Intent(context,MusicService.class);
svc_intent.setPackage("com.example.mymusic");
this.context = context;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.notification,container,false);
TextView textViewMusicName = view.findViewById(R.id.textViewMusicName);
final ImageView btnPlay = view.findViewById(R.id.imageViewPlay);
ImageView btnMusic = view.findViewById(R.id.imageViewMusic);
ImageView btnClose = view.findViewById(R.id.imageViewClose);
btnMusic.setVisibility(View.GONE);
btnClose.setVisibility(View.GONE);
textViewMusicName.setText("刘佳怡 - 所念皆星河(纯钢琴)(翻自 CMJ) .mp3");
btnPlay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (isplay){
isplay =false;
svc_intent.setAction("STOP");
btnPlay.setImageResource(R.drawable.ic_play_circle_outline_black_24dp);
context.startService(svc_intent);
}
else {
svc_intent.setAction("START");
btnPlay.setImageResource(R.drawable.ic_pause_circle_outline_black_24dp);
getActivity().bindService(svc_intent,sc, Service.BIND_AUTO_CREATE);
context.startService(svc_intent);
isplay = true;
}
}
});
view.findViewById(R.id.imageViewStop).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getActivity().unbindService(sc);
}
});
return view;
}
}
然后布局Mainlayout
container是用来盛放musicfragment的
MainActivity中的
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
notifManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notifManager.cancelAll();//清除所有通知
Intent intent = new Intent(this,MusicService.class);
//stopService(intent);//停止音乐服务
CreatChannle();//创建频道
createNotification();//创建通知栏
musicFragment = new MusicFragment(this);
getSupportFragmentManager().beginTransaction().replace(R.id.container, musicFragment).commit();
}
@Override
public void onBackPressed() {
onStop();
}//重写返回按键
@Override
protected void onStop() {
super.onStop();
confirmExitRuning();//弹确认退出对话框
}
只有高版本才需要创建(API大于26)
//创建广播评到设置重要性
private void CreatChannle(){
if (notifManager == null)
notifManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
//将通知重要性设为低,这样就不会有通知的声音(部分模拟器仍然会发声)
int importance = NotificationManager.IMPORTANCE_LOW;
mChannel = notifManager.getNotificationChannel(Channel_ID);
if (mChannel==null){
mChannel = new NotificationChannel(Channel_ID,ChannelName,importance);
mChannel.setDescription(Channel_Description);
notifManager.createNotificationChannel(mChannel);
}
}
}
该函数设置通知栏的视图内容,包括布局和布局内四个按钮的点击事件处理
private RemoteViews getRemoteView(){
RemoteViews remoteViews = new RemoteViews(getPackageName(),R.layout.notification);
remoteViews.setTextViewText(R.id.textViewMusicName,noteMessage);
remoteViews.setImageViewResource(R.id.imageViewMusic,R.drawable.ic_music_note_black_24dp);
remoteViews.setImageViewResource(R.id.imageViewClose,R.drawable.ic_close_black_24dp);
remoteViews.setImageViewResource(R.id.imageViewStop,R.drawable.ic_stop_black_24dp);
remoteViews.setImageViewResource(R.id.imageViewPlay,R.drawable.ic_play_circle_outline_black_24dp);
//播放按钮打开服务
Intent intent =new Intent(MainActivity.this,MusicService.class);
intent.setAction("START");
PendingIntent pendingIntent = PendingIntent.getService(this,0,intent,0);
remoteViews.setOnClickPendingIntent(R.id.imageViewPlay,pendingIntent);
//停止按钮打开服务(设置停止标签)
Intent intentStop =new Intent(MainActivity.this,MusicService.class);
intentStop.setAction("STOP");
PendingIntent pendingIntentStop = PendingIntent.getService(this,0,intentStop,0);
remoteViews.setOnClickPendingIntent(R.id.imageViewStop,pendingIntentStop);
//关闭广播和服务
Intent intent_close = new Intent(this,CloseNotificationReceiver.class);
PendingIntent pendingIntent_close = PendingIntent.getBroadcast(this,0,intent_close,0);
remoteViews.setOnClickPendingIntent(R.id.imageViewClose,pendingIntent_close);
//打开app
Intent intent_open = new Intent(getApplicationContext(),MainActivity.class);
PendingIntent pendingIntent_open = PendingIntent.getActivity(getApplicationContext(),0,intent_open,PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.imageViewMusic,pendingIntent_open);
return remoteViews;
}
用于关闭通知和服务的静态内部广播类
必须在mainframe中添加
<receiver
android:name=".MainActivity$CloseNotificationReceiver"
android:enabled="true"
android:exported="true"/>
然后是类
public static class CloseNotificationReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("TAG", "onReceive: ");
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancelAll();
Intent musicSvc = new Intent(context,MusicService.class);
context.stopService(musicSvc);
System.exit(0);
}
}
创建通知栏 要分三种情况 API<19 19<API<26 API>26
public void createNotification(){
Intent intent = new Intent(MainActivity.this,MusicService.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getService(MainActivity.this,0,intent,0);
noteMessage ="刘佳怡 - 所念皆星河(纯钢琴)(翻自 CMJ) .mp3";
if (Build.VERSION.SDK_INT<Build.VERSION_CODES.JELLY_BEAN){
//使用 NotificationCompat 而不是Notification,因为Notification需要API16才能使用
//NotificationCompat 存在于V4 Support Library
NotificationCompat.Builder compat_builder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(note_Title)
.setContentText(noteMessage)
.setAutoCancel(false)
.setOngoing(true)
.setWhen(System.currentTimeMillis())
.setContentIntent(pendingIntent);
if (compat_builder != null){
//设置通知栏的视图内容
compat_builder.setContent(getRemoteView());
if (notifManager == null){
notifManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}
notifManager.notify(NOTE_ID,compat_builder.build());
}
}else if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.JELLY_BEAN&&Build.VERSION.SDK_INT<Build.VERSION_CODES.O){
Notification.Builder notificationBuilder = new Notification.Builder(MainActivity.this);
notificationBuilder.setSmallIcon(R.drawable.ic_music_note_black_24dp);
notificationBuilder.setContentTitle(note_Title);
notificationBuilder.setContentText(noteMessage);
notificationBuilder.setAutoCancel(false);
notificationBuilder.setOngoing(true);
notificationBuilder.setWhen(System.currentTimeMillis());
notificationBuilder.setContentIntent(pendingIntent);
if (notificationBuilder != null){
//设置通知栏的视图内容
notificationBuilder.setContent(getRemoteView());
if (notifManager == null){
notifManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}
notifManager.notify(NOTE_ID,notificationBuilder.build());
}
}
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
Notification.Builder notificationBuilder =null;
notificationBuilder=
new Notification.Builder(getApplicationContext(),Channel_ID)
.setSmallIcon(R.drawable.ic_music_note_black_24dp)
.setContentTitle(note_Title)
.setContentText(noteMessage)
.setAutoCancel(false)
.setOngoing(true)
.setWhen(System.currentTimeMillis())
.setContentIntent(pendingIntent);
if (notificationBuilder != null){
//设置通知栏的视图内容
notificationBuilder.setContent(getRemoteView());
if (notifManager == null){
notifManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}
if (notifManager != null){
notifManager.notify(NOTE_ID,notificationBuilder.build());
}
}
}
}
//确认对话框
private void confirmExitRuning() {
new AlertDialog.Builder(MainActivity.this)
.setIcon(R.drawable.ic_warning_black_24dp)
.setTitle("退出提示")
.setMessage("要在后台运行吗?")
.setPositiveButton("后台运行", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
createNotification();
goToDesktop(MainActivity.this);
// System.exit(0);
}
})
.setNegativeButton("直接退出!", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(getApplicationContext(),MusicService.class);
stopService(intent);
System.exit(0);
}
}).create().show();
}
返回到桌面
public static void goToDesktop(Context context) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(intent);
}
然后九世最终效果了