android studio中的流媒体音乐

android studio中的流媒体音乐,android,android-studio,android-asynctask,Android,Android Studio,Android Asynctask,我想流一个mp3文件,长度约为1小时。我想在后台播放这个文件。我看了很多教程视频。他们中的一些人使用服务,一些人使用asyntask。我也不知道我能在这两者中选择什么。哪个更好?如果您希望在用户退出应用程序后仍能播放音乐,则需要使用前台服务。所有音乐播放器都使用这种方法 如果你想让音乐结束,当用户存在一个复杂的活动时,只有在这种情况下才会考虑除了服务之外的任何东西。 异步任务不应用于此目的,因为它是小型后台任务的理想选择。播放音乐不属于这一类 您肯定希望使用服务,而不是异步任务。这样做的主要原因

我想流一个mp3文件,长度约为1小时。我想在后台播放这个文件。我看了很多教程视频。他们中的一些人使用服务,一些人使用asyntask。我也不知道我能在这两者中选择什么。哪个更好?

如果您希望在用户退出应用程序后仍能播放音乐,则需要使用前台服务。所有音乐播放器都使用这种方法

如果你想让音乐结束,当用户存在一个复杂的活动时,只有在这种情况下才会考虑除了服务之外的任何东西。


异步任务不应用于此目的,因为它是小型后台任务的理想选择。播放音乐不属于这一类

您肯定希望使用服务,而不是异步任务。这样做的主要原因是,如果你想让音乐在应用程序被挂起/放到后台的情况下运行,比如当用户移动到另一个应用程序时,只有一个服务会这样做。异步任务不会以这种方式在后台运行

为了包含一些关于后台服务的背景信息,他们使用来自应用程序上下文(如活动和前台服务)的事件来通知他们何时工作。这项工作通过服务的onStartCommand()函数处理。在Android文档中可以阅读更多关于服务的内容

这就是说,服务将允许在后台运行,但如果操作系统需要完成另一项任务,它仍然可以被抢占。因此,为了可靠地播放音乐,并在操作系统出于任何原因抢占服务后不久重新启动,您需要指定START_STICKY作为服务的onStartCommand()函数的返回值。但是,与Android的所有功能一样,与不兼容的版本相比,更喜欢兼容版本,即START_STICKY_兼容版本。START_STICKY/START_STICKY_兼容性适用于在播放命令的情况下返回。即,如果服务接收的事件正在播放

在任何情况下,从onStartCommand()返回START_STICKY或START_STICKY_兼容性都会使您获得一项永不消亡的服务,从而消耗运行该服务的手机的处理能力和电池寿命。这可能会导致处理器消耗和电池耗电。这就是为什么当用户试图暂停时,必须从onstart命令返回START\u NOT\u STICKY。即,如果服务接收的事件是暂停

以下是您可能希望服务的onStart命令的精简版本:

public int onStartCommand(Intent intent, int flags, int startId) {

    if (intent.getAction().equals(ACTION_PLAY)) {
        ...
        return START_STICKY_COMPATIBILITY;
    } else { // i.e. action is ACTION_PAUSE
        ...
        return START_NOT_STICKY;
    }
}
编辑:为了说明这一点以及这个答案的其余部分,为了简化这篇文章,我排除了等待mediaplayer准备的考虑因素。需要注意的是,该服务可能还需要处理等待mediaplayer准备单独的事件,或者在处理播放事件时处理。在启动服务之前,也可以从活动中处理,但这可能或多或少比较复杂。如果不讨论问题的这一方面,解释本答案中的其他问题/注意事项会容易得多,尽管制作一个功能性音乐播放器应用程序时必须考虑这一点

还需要设置设备锁定的时间,以便某些硬件外围设备不会关闭。考虑响应服务OnStistCube中的播放事件添加以下内容:
        // Setup Wake Mode Wake Lock so the music can play while device screen is locked
        mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.FULL_WAKE_LOCK);
        // Setup wifi lock so wifi can stay on while device is locked and trying to save power
        wifiLock = ((WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE))
                .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");
        wifiLock.acquire();
另一个问题是,理想情况下,如果服务正在运行,用户将能够终止该服务。如果他们关闭了应用程序,它不会像预期的那样关闭服务,音乐将继续播放。因此,用户应该能够通过带有暂停和播放音乐控件的通知来控制服务。这可以使用前台服务来完成。如果要添加前台服务层,可以在服务的onStartCommand()中添加对startForeground()的调用,以响应播放的广播事件。下面是添加了前台逻辑的精简onStartCommand():

public int onStartCommand(Intent intent, int flags, int startId) {

    if (intent.getAction().equals(ACTION_PLAY)) {
        ...
        Notification notification = setupNotification(); // where setupNotification is your own function
        startForeground(1, notification);
        return START_STICKY_COMPATIBILITY;
    } else { // i.e. action is ACTION_PAUSE
        ...
        stopForeground(false);

        // NotificationManagerCompat needed here for swipeable notification b/c service will be killed
        Notification notification = setupNotification();
        NotificationManagerCompat nmc = NotificationManagerCompat.from(this);
        nmc.notify(1, notification);
        return START_NOT_STICKY;
    }
}
函数的参数为id和通知对象。可以使用NotificationCompat.Builder创建通知,其代码如下所示(请注意,此处的一些变量需要为各自的应用程序进行子化):

注意上面代码中的未决意图。这些是使用PendingEvent类创建的。 例如,为通知上的播放按钮创建一个挂起的意图,如是(其中“this”是后台服务,假设您是从后台服务中创建此意图)

同样,当用户点击通知时,创建一个挂起的意图,以便它使用以下代码打开应用程序(同样,此处“this”是后台服务,假设您是从后台服务中创建此意图):

此外,在通知上创建挂起的刷卡操作意图,以如下方式终止后台服务(同样,“this”是后台服务,假设您是从后台服务中创建此意图):


希望这些内容足以让您继续,但我建议您在开始这个过程时不要使用复杂的前台活动层。当您看到应用程序中的音乐播放正常时,请添加它。

非常感谢。这真的帮了我很大的忙。非常感谢
Bitmap icon = BitmapFactory.decodeResource(getResources(),
        R.drawable.ic_launcher_round_large);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
        .setContentTitle(getString(R.string.app_name))
        .setContentText("Music is now playing") // change to paused on paused
        .setTicker("Music Playing")
        .setSmallIcon(R.drawable.status_bar_icon_xhdpi_48px)
        .setLargeIcon(Bitmap.createScaledBitmap(icon, 128, 128, false))
        .setContentIntent(pendingTapIntent)
        .setDeleteIntent(pendingSwipeIntent)
        .addAction(iconId, buttonText, pendingButtonIntent)
        .setWhen(System.currentTimeMillis());
 Intent playIntent = new Intent(this, MyService.class);
            playIntent.setAction(ACTION_PLAY);
            PendingIntent pendingPlayIntent = PendingIntent.getService(this, 0, playIntent, 0);
Intent notificationIntent = new Intent(this, StreamActivity.class);
        notificationIntent.setAction("ACTION_MAIN");
        notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Intent swipeIntent = new Intent(this, MyService.class);
swipeIntent.setAction(ACTION_END_SERVICE);
PendingIntent pendingSwipeIntent = PendingIntent.getService(this, 0, swipeIntent, 0);