从音乐播放器谈Service

本文介绍如何使用Android Service实现后台音乐播放功能。Service分为startedService和boundService两种形式,通过startService和bindService方法启动。文章详细展示了音乐播放Service的生命周期、启动方式,并提供了具体的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Service作为Android四大组件之一,在每一个应用程序中都扮演着非常重要的角色。它主要用于在后台处理一些耗时的逻辑,或者去执行某些需要长期运行的任务。必要的时候我们甚至可以在程序退出的情况下,让Service在后台继续保持运行状态。
这里写图片描述

1. startedService

  • 被开启的service通过其他组件调用 startService()被创建。
  • 这种service可以无限地运行下去,必须调用stopSelf()方法或者其他组件调用stopService()方法来停止它。
  • 当service被停止时,系统会销毁它。

2.boundService

  • 被绑定的service是当其他组件(一个客户)调用bindService()来创建的。
  • 客户可以通过一个IBinder接口和service进行通信。
  • 客户可以通过 unbindService()方法来关闭这种连接。
     
     

注意:

  一个service可以同时和多个客户绑定,当多个客户都解除绑定之后,系统会销毁service。


  • 1.Service与Activity之间可以相互调用(bindService,拿到一个binder实例任意调用)
  • 2.如果采用bindService Service实例生命周期与Activity绑定到一起了,如果Activity销毁,Service也会销毁,那么不能做到后台播放
  • startService(Service实例与启动者的生命周期无关,除非调用stopService方法而消亡)
  • bindService(Service实例与启动者的生命周期关联,用户手动调用unbindService或者Activity消亡会跟着消亡)

  • 两种方式各有千秋,结合起来可以实现灵活控制

生命周期

  • service整体的生命时间是从onCreate()被调用开始,到onDestroy()方法返回为止。和activity一样,service在onCreate()中进行它的初始化工作,在onDestroy()中释放残留的资源。

  • 比如,一个音乐播放service可以在onCreate()中创建播放音乐的线程,在onDestory()中停止这个线程。

  • onCreate() 和 onDestroy()会被所有的service调用,不论service是通过startService()还是bindService()建立。

BindService:

  • 当绑定service和所有客户端解除绑定之后,Android系统将会销毁它,(除非它同时被onStartCommand()方法开启)。
  • 因此,如果你的service是一个纯粹的绑定service,那么你不需要管理它的生命周期。然而,如果你选择实现onStartCommand()回调方法,那么你必须显式地停止service,因为service此时被看做是开启的。这种情况下,service会一直运行到它自己调用stopSelf()或另一个组件调用stopService(),不论它是否和客户端绑定。 另外,如果你的service被开启并且接受绑定,那么当系统调用你的onUnbind()方法时,如果你想要在下次客户端绑定的时候接受一个onRebind()的调用(而不是调用onBind()),你可以选择在onUnbind()中返回true。onRebind()的返回值为void,但是客户端仍然在它的 onServiceConnected()回调方法中得到 IBinder 对象。

这里写图片描述

简单的音乐播放器代码:
public class MainActivity extends Activity {
private Button mPlayBtn;
private Button mStopBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPlayBtn = (Button) findViewById(R.id.play_pause);
mPlayBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// Started
Intent intent = new Intent();
intent.putExtra(“command”, “play”);
intent.setClass(MainActivity.this, MusicService.class);
startService(intent);
}
});
mStopBtn = (Button) findViewById(R.id.stop_play);
mStopBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// Stop
stopService(new Intent(MainActivity.this, MusicService.class));
}
});
findViewById(R.id.next).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//切换下一首歌曲
Intent intent = new Intent();
intent.putExtra(“command”, “next”);
intent.setClass(MainActivity.this, MusicService.class);
startService(intent);
}
});
}
}

Service代码:

package com.example.lesson18_service_start;

import java.util.ArrayList;
import java.util.List;

import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.RemoteViews;

public class MusicService extends Service {

MediaPlayer mediaPlayer;

List<Integer> songList = new ArrayList<>();
List<String> songNameList = new ArrayList<>();
int playIndex;// 当前播放歌曲的下标

@Override
public void onCreate() {// Service实例被创建
    super.onCreate();
    Log.i("at22", "onCreate");
    // 歌曲的资源集合
    songList.add(R.raw.abc);
    songList.add(R.raw.areyouok);
    songList.add(R.raw.zxmzf);
    // 歌曲的名字
    songNameList.add("abc");
    songNameList.add("areyouok");
    songNameList.add("zxmzf");

    mediaPlayer = MediaPlayer.create(this, songList.get(playIndex));

    // 第一次播放的时候更新通知栏的歌曲名字
    updateNotification();

}
/**
 * 更新通知栏
 */
private void updateNotification() {
    //创建能兼容v7以上的通知栏构建者对象
    NotificationCompat.Builder builder = new NotificationCompat.Builder(
            this);
    // 通知栏三个必须的属性需要设置
    builder.setSmallIcon(R.drawable.ic_launcher);
    // builder.setContentText("abc");//自定义通知视图可以不写
    // builder.setContentTitle("abc title");//自定义通知视图可以不写
    //创建通知栏中自定义视图的类
    RemoteViews views = new RemoteViews(getPackageName(),
            R.layout.notification_layout);
    //获取当前的歌曲名字
    String songName = songNameList.get(playIndex);
    // 更新RemoteView中的文本内容
    views.setTextViewText(R.id.song, songName);

    Intent intent = new Intent();//下一首的歌曲
    intent.putExtra("command", "next");
    intent.setClass(this, MusicService.class);
    PendingIntent pendingIntent = PendingIntent.getService(this, 1, intent,
            PendingIntent.FLAG_UPDATE_CURRENT);
    // 给RemoteView中的某个视图这是点击处理
    views.setOnClickPendingIntent(R.id.next, pendingIntent);//第一个参数是下一首button视图的id
    // 将自定义视图设置到通知栏中去
    builder.setContent(views);
    //启动一个通知与当前的服务“命运”关联
    startForeground(111, builder.build());
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    String command = intent.getStringExtra("command");

    if ("play".equals(command)) {
        playOrPause();
    } else if ("next".equals(command)) {
        playNext();
    }
    Log.i("at22", "onStartCommand" + command);
    return super.onStartCommand(intent, flags, startId);
}

private void playNext() {
    if (mediaPlayer != null) {// 释放播放器
        mediaPlayer.stop();
        mediaPlayer.release();
    }
    playIndex++;
    if (playIndex >= songList.size()) {// 切换下一首歌曲
        playIndex = 0;
    }

    int songRawId = songList.get(playIndex);// 歌曲的资源id
    mediaPlayer = MediaPlayer.create(this, songRawId);
    mediaPlayer.start();
    // 有歌曲名变化时通知栏更新
    updateNotification();
}

private void playOrPause() {
    if (mediaPlayer != null && mediaPlayer.isPlaying()) {//如果正在播放就暂停
        mediaPlayer.pause();//暂停
    } else {
        mediaPlayer.start();//播放
    }
}

@Override
public void onDestroy() {// Service实例被销毁
    super.onDestroy();
    Log.i("at22", "onDestroy");
}

@Override
public IBinder onBind(Intent intent) {
    // TODO Auto-generated method stub
    return null;
}

}
注意。由于Service是四大组建:一定要在清单文件中声明:

  • android:name=”.MusicService”

这里写图片描述

音乐播放器源代码:代码链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值