通过服务+广播+通知实现的一个通知栏音乐控制器

之前的一段时间在学习服务和广播这两个知识点,然后在网上看到一些对于后台操作需要通过服务与广播的一些例子,便索性做一个小demo对这些知识点进行巩固;通过服务+广播+通知对后台音乐进行播放、暂停、停止这三样简单的控制。



创建demo后的第一步便是创建服务,创建一个名为MusicService的类,继承Service类;然后在MusicService里实现音乐文件的初始化,同时创建各种方法对音乐播放的控制,其中音乐控制相关方法与通知控制都设为静态,其他类可直接通过类进行调用,以下为代码,材料自找

public class MusicService extends Service {
    private static MediaPlayer mediaPlayer; //声明操作媒体的对象
    static int pos = 0; //记录播放的位置
    private static NotificationManager notificationManager;
    private String TAG = "media";
    private static Notification notification;
    
    class MyBinder extends Binder{
        public MusicService getService(){
            //绑定服务同时进行播放
            play();
            return MusicService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        showMusicNotification();
        //初始化播放对象
        if (mediaPlayer == null){
            mediaPlayer = mediaPlayer.create(MusicService.this,R.raw.lit);
            mediaPlayer.setLooping(false);
        }
        //监听播放结束,释放资源
        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                mediaPlayer.release();
            }
        });
    }

    //用于开始播放的方法
    public static void play(){
        if (mediaPlayer != null && !mediaPlayer.isPlaying()){
            try {
                if (pos != 0){
                    //根据指定位置进行播放
                    mediaPlayer.seekTo(pos);
                    mediaPlayer.start();
                }else {
                    //首次或从头播放,并显示通知
                    notificationManager.notify(200,notification);
                    mediaPlayer.stop();
                    mediaPlayer.prepare();
                    mediaPlayer.start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //暂停播放
    public static void pause(){
        if (mediaPlayer != null && mediaPlayer.isPlaying()){
            //获取播放位置
            pos = mediaPlayer.getCurrentPosition();
            mediaPlayer.pause();
        }
    }

    //停止播放
    public static void stop(){
        if (mediaPlayer != null){
            mediaPlayer.stop();
            pos = 0; //停止后播放位置置为0
        }

}


服务类需要在AndroidManifest.xml里进行注册

<service
            android:name=".MusicService"
            android:enabled="true"
            android:exported="true"/>

接着是创建通知,通过使用RemoteViews类创建自定义通知样式的对象,样式自己可通过创建布局进行自定义,而其中对布局控件的点击操作是通过发送广播进行操作

public void showMusicNotification(){
        Notification.Builder builder = new Notification.Builder(this);
        RemoteViews remoteViews = new RemoteViews(getPackageName(),R.layout.notification);
        remoteViews.setImageViewResource(R.id.image,R.drawable.timg);
        builder.setContent(remoteViews)
                .setWhen(System.currentTimeMillis())
                .setTicker("正在播放")
                .setPriority(Notification.PRIORITY_DEFAULT)
                .setAutoCancel(false)
                .setOngoing(true)
                .setSmallIcon(R.mipmap.ic_launcher);

        //通知栏控制器播放按钮广播操作
        Intent intentPlay = new Intent("play");//新建意图,设置action标记为“play”,用于接收广播时过滤意图信息
        PendingIntent playPendingIntent = PendingIntent.getBroadcast(this,0,intentPlay,0);
        remoteViews.setOnClickPendingIntent(R.id.play,playPendingIntent);//为play控件注册事件
        //通知栏控制器暂停按钮广播操作
        Intent intentPause = new Intent("pause");
        PendingIntent pausePendingIntent = PendingIntent.getBroadcast(this,0,intentPause,0);
        remoteViews.setOnClickPendingIntent(R.id.pause,pausePendingIntent);
        //通知栏控制器停止按钮广播操作
        Intent intentStop = new Intent("stop");
        PendingIntent stopPendingIntent = PendingIntent.getBroadcast(this,0,intentStop,0);
        remoteViews.setOnClickPendingIntent(R.id.stop,stopPendingIntent);
        ////通知栏控制器关闭通知按钮广播操作
        Intent intentDead = new Intent("clear");
        PendingIntent deadPendingIntent = PendingIntent.getBroadcast(this,0,intentDead,0);
        remoteViews.setOnClickPendingIntent(R.id.dead,deadPendingIntent);

        notification = builder.build();
        notification.flags = notification.FLAG_ONGOING_EVENT;
        notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    }


以下是我的通知栏的布局文件,图片可网上找

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="80dp">
    <ImageView
        android:id="@+id/image"
        android:src="@mipmap/ic_launcher"
        android:layout_width="80dp"
        android:layout_height="80dp" />
    <LinearLayout
        android:layout_centerInParent="true"
        android:layout_toRightOf="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ImageView
            android:layout_marginTop="10dp"
            android:layout_marginLeft="30dp"
            android:src="@mipmap/pause"
            android:id="@+id/pause"
            android:layout_width="40dp"
            android:layout_height="40dp" />
        <ImageView
            android:layout_marginTop="10dp"
            android:layout_marginLeft="40dp"
            android:src="@mipmap/play"
            android:id="@+id/play"
            android:layout_width="40dp"
            android:layout_height="40dp" />
        <ImageView
            android:layout_marginTop="10dp"
            android:layout_marginLeft="40dp"
            android:src="@mipmap/stop"
            android:id="@+id/stop"
            android:layout_width="40dp"
            android:layout_height="40dp" />
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="60dp">
            <ImageView
                android:id="@+id/dead"
                android:src="@mipmap/clear"
                android:layout_width="35dp"
                android:layout_height="35dp"
                android:layout_centerVertical="true"
                android:layout_centerHorizontal="true" />
        </RelativeLayout>
    </LinearLayout>
</RelativeLayout>

接下来是广播接收器,创建名为MusicReciver的类,继承BroadcastReceiver类,以下为代码文件

public class MusicReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        String ctrl_code = intent.getAction();
        if ("play".equals(ctrl_code)){
            //通知栏音乐播放操作
            MusicService.play();
        }else if ("pause".equals(ctrl_code)){
            //通知栏音乐暂停操作
            MusicService.pause();
        }else if ("stop".equals(ctrl_code)){
            //通知栏音乐停止操作
            MusicService.stop();
        }else if ("clear".equals(ctrl_code)){
            //通知栏关闭通知操作
            MusicService.clearNotification();
            MusicService.stop();
        }
    }
}

接收器需要在AndroidManifest.xml里进行注册,并且自定义的广播消息需要在注册的接收器内进行定义,否则程序会报错

<receiver android:name=".MusicReceiver"
            android:exported="true">
            <intent-filter>
                <action android:name="play"/>
                <action android:name="pause"/>
                <action android:name="stop"/>
                <action android:name="clear"/>
            </intent-filter>
        </receiver>

最后的是主activity的布局与类文件,主布局如下

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context="com.example.li.musictest.MainActivity"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:src="@drawable/timg"
        android:layout_marginTop="100dp"
        android:layout_centerHorizontal="true"
        android:layout_width="200dp"
        android:layout_height="200dp" />
    <LinearLayout
        android:layout_marginBottom="100dp"
        android:layout_alignParentBottom="true"
        android:layout_centerInParent="true"
        android:layout_toRightOf="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <ImageView
            android:src="@mipmap/pause"
            android:id="@+id/pause"
            android:layout_width="50dp"
            android:layout_height="50dp" />
        <ImageView
            android:layout_marginLeft="40dp"
            android:layout_marginRight="40dp"
            android:src="@mipmap/play"
            android:id="@+id/play"
            android:layout_width="50dp"
            android:layout_height="50dp" />
        <ImageView
            android:src="@mipmap/stop"
            android:id="@+id/stop"
            android:layout_width="50dp"
            android:layout_height="50dp" />
    </LinearLayout>

</RelativeLayout>

主类主要实现主布局的点击操作,其中有一内部类继承了ServiceConnection类,为与服务通讯的主要实现类,其余是我们平常的点击操作

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private Intent intent;
    private MusicService musicService;
    private MusicConnection myConnection = new MusicConnection();
    private String TAG = "media";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.play).setOnClickListener(this);
        findViewById(R.id.pause).setOnClickListener(this);
        findViewById(R.id.stop).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        //activity页面的相关点击操作
        switch (v.getId()){
            //播放
            case R.id.play:
                if (musicService == null) {
                    //首次播放绑定服务
                    intent = new Intent(MainActivity.this,MusicService.class);
                    bindService(intent,myConnection, Context.BIND_AUTO_CREATE);
                    startService(intent);
                }else {
                    musicService.play();
                }
                break;
            //暂停
            case R.id.pause:
                if (musicService != null){
                    musicService.pause();
                }
                break;
            //停止
            case R.id.stop:
                if (musicService != null){
                    musicService.stop();
                }
                break;
        }
    }



    private class MusicConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            MusicService.MyBinder myBinder = (MusicService.MyBinder) service;
            musicService = myBinder.getService();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            myConnection = null;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(myConnection);
        MusicService.clearNotification();
        Log.i(TAG, "onDestroy: ");
    }
}


第一次写博客,可能有很多不足的地方,代码也可能有错误的地方,希望多加指正

以下为运行图


                      


猜你喜欢

转载自blog.csdn.net/li527425/article/details/78241969