【问题标题】:Streaming music in android studio在 android studio 中流式传输音乐
【发布时间】:2018-06-29 03:56:18
【问题描述】:

我想流式传输长度约为 1 小时的 mp3 文件。我想在后台播放文件。我看了很多教程视频。其中一些使用服务,一些使用异步任务。我也不知道我能在这些之间选择什么。哪个更好?

【问题讨论】:

    标签: android android-studio android-asynctask


    【解决方案1】:

    您肯定会想要使用服务,而不是 AsyncTask。这样做的主要原因是,如果您希望即使应用程序已暂停/进入后台也能运行音乐,例如当用户移动到另一个应用程序时,只有服务会这样做。 AsyncTasks 不会以这种方式在后台运行。

    为了包含有关后台服务的一些背景信息,它们使用来自应用上下文(例如活动和前台服务)的事件来通知它们何时开始工作。这项工作是通过服务的 onStartCommand() 函数处理的。有关服务的更多信息,请参阅 Android 文档 https://developer.android.com/guide/components/services

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

    在任何情况下从 onStartCommand() 返回 START_STICKY 或 START_STICKY_COMPATIBILITY 都会为您提供永不中断的服务,从而消耗运行它的手机的处理能力和电池寿命。这可能会导致处理器消耗和电池消耗。这就是为什么在用户尝试暂停时从 onStartCommand 返回 START_NOT_STICKY 很重要的原因。 IE。如果服务正在接收的事件是 PAUSE。

    这是您可能希望服务的 onStartCommand 看起来像这样的精简版本:

    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;
        }
    }
    

    编辑:警告这个和这个答案的其余部分 - 为了简化帖子,我排除了等待媒体播放器准备的考虑因素。需要注意的是,该服务可能还需要处理等待媒体播放器准备一个单独的事件,或者从 PLAY 事件的处理中。也可以在启动服务之前从活动内部处理,但这可能或多或少复杂。在不讨论问题的这一方面的情况下,解释此答案中的其余问题/考虑要容易得多,尽管必须考虑制作功能性音乐播放器应用程序。

    还需要设置设备何时锁定,以免某些硬件外围设备关闭。考虑添加以下内容以响应服务的 onStartCommand 中的 PLAY 事件来解决此问题:

            // 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()的调用,以响应PLAY的广播事件。这是添加了前台逻辑的精简 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;
        }
    }
    

    startForeground() 函数将一个 id 和一个 Notification 对象作为其参数。可以使用 NotificationCompat.Builder 创建通知,代码如下所示(注意这里的一些变量需要为您各自的应用程序替换):

    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());
    

    请注意上面代码中的待处理意图。这些是使用 PendingIntent 类创建的。 IE。像这样为通知上的播放按钮创建待处理的意图(其中“this”是后台服务,假设您是从后台服务中创建此意图)

     Intent playIntent = new Intent(this, MyService.class);
                playIntent.setAction(ACTION_PLAY);
                PendingIntent pendingPlayIntent = PendingIntent.getService(this, 0, playIntent, 0);
    

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

    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);
    

    此外,为通知上的滑动操作创建挂起的意图,以像这样终止后台服务(同样,“this”是后台服务,假设您是从后台服务中创建此意图):

    Intent swipeIntent = new Intent(this, MyService.class);
    swipeIntent.setAction(ACTION_END_SERVICE);
    PendingIntent pendingSwipeIntent = PendingIntent.getService(this, 0, swipeIntent, 0);
    

    希望这足以让您继续前进,但我建议在没有复杂的前台活动层的情况下开始此过程。然后在您看到应用内的音乐播放正常后添加它。

    【讨论】:

    • 非常感谢。这对我帮助很大。
    【解决方案2】:

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

    如果您希望音乐在用户存在特定活动时结束,那么只有在这种情况下才会考虑服务以外的任何内容。

    异步任务不应用于此目的,因为它非常适合小型后台任务。播放音乐不在此类别中。

    【讨论】:

    • 非常感谢
    猜你喜欢
    • 1970-01-01
    • 2017-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多