ساختن کارخواه مرورگر رسانه

برای تکمیل طراحی کارخواه/کارساز، باید مؤلفه فعالیتی بسازید که حاوی کد میانای کاربر، MediaController منسوب، و MediaBrowser باشد.

‫MediaBrowser دو عملکرد مهم را انجام می‌دهد: به MediaBrowserService متصل می‌شود و پس‌از اتصال، MediaController را برای میانای کاربر شما ایجاد می‌کند.

توجه: پیاده‌سازی توصیه‌شده MediaBrowser MediaBrowserCompat است، که در کتابخانه پشتیبانی Media-Compat تعریف شده است. در سراسر این صفحه، اصطلاح «MediaBrowser» به نمونه‌ای از MediaBrowserCompat اشاره دارد.

متصل شدن به MediaBrowserService

وقتی فعالیت مشتری شما ایجاد می‌شود، به MediaBrowserService متصل می‌شود. کمی دست دادن و رقصیدن هم در کار است. فراخوانی‌های چرخه حیات فعالیت را به‌صورت زیر تغییر دهید:

  • ‫onCreate() یک MediaBrowserCompat می‌سازد. نام MediaBrowserService و MediaBrowserCompat.ConnectionCallback را که تعریف کرده‌اید وارد کنید.
  • ‫onStart() به MediaBrowserService متصل می‌شود. اینجا جایی است که جادوی MediaBrowserCompat.ConnectionCallback وارد می‌شود. اگر اتصال موفقیت‌آمیز باشد، callback‏()onConnect کنترل‌کننده رسانه را ایجاد می‌کند، آن را به جلسه رسانه پیوند می‌دهد، کنترل‌های میانای کاربر شما را به MediaController پیوند می‌دهد، و کنترل‌کننده را برای دریافت callback از جلسه رسانه ثبت می‌کند.
  • onResume() جاری‌سازی صوتی را تنظیم می‌کند تا برنامه‌تان به کنترل میزان صدا در دستگاه پاسخ دهد.
  • ‫onStop() MediaBrowser شما را قطع می‌کند و وقتی فعالیت شما متوقف می‌شود، MediaController.Callback را لغو ثبت‌نام می‌کند.

کاتلین

class MediaPlayerActivity : AppCompatActivity() {

    private lateinit var mediaBrowser: MediaBrowserCompat

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
        // Create MediaBrowserServiceCompat
        mediaBrowser = MediaBrowserCompat(
                this,
                ComponentName(this, MediaPlaybackService::class.java),
                connectionCallbacks,
                null // optional Bundle
        )
    }

    public override fun onStart() {
        super.onStart()
        mediaBrowser.connect()
    }

    public override fun onResume() {
        super.onResume()
        volumeControlStream = AudioManager.STREAM_MUSIC
    }

    public override fun onStop() {
        super.onStop()
        // (see "stay in sync with the MediaSession")
        MediaControllerCompat.getMediaController(this)?.unregisterCallback(controllerCallback)
        mediaBrowser.disconnect()
    }
}

جاوا

public class MediaPlayerActivity extends AppCompatActivity {
  private MediaBrowserCompat mediaBrowser;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // ...
    // Create MediaBrowserServiceCompat
    mediaBrowser = new MediaBrowserCompat(this,
      new ComponentName(this, MediaPlaybackService.class),
        connectionCallbacks,
        null); // optional Bundle
  }

  @Override
  public void onStart() {
    super.onStart();
    mediaBrowser.connect();
  }

  @Override
  public void onResume() {
    super.onResume();
    setVolumeControlStream(AudioManager.STREAM_MUSIC);
  }

  @Override
  public void onStop() {
    super.onStop();
    // (see "stay in sync with the MediaSession")
    if (MediaControllerCompat.getMediaController(MediaPlayerActivity.this) != null) {
      MediaControllerCompat.getMediaController(MediaPlayerActivity.this).unregisterCallback(controllerCallback);
    }
    mediaBrowser.disconnect();

  }
}

سفارشی‌سازی MediaBrowserCompat.ConnectionCallback

وقتی فعالیت شما MediaBrowserCompat را می‌سازد، باید نمونه‌ای از ConnectionCallback ایجاد کنید. روش onConnected() آن را اصلاح کنید تا کد جلسه رسانه را از MediaBrowserService بازیابی کند و از کد برای ایجاد MediaControllerCompat استفاده کند.

از روش راحتی MediaControllerCompat.setMediaController() برای ذخیره کردن پیوند به کنترل‌کننده استفاده کنید. این کار امکان مدیریت دکمه‌های رسانه را فراهم می‌کند. همچنین به شما امکان می‌دهد هنگام ساختن کنترل‌های انتقال، MediaControllerCompat.getMediaController() را برای بازیابی کنترل‌کننده فراخوانی کنید.

نمونه کد زیر نحوه اصلاح روش onConnected() را نشان می‌دهد.

کاتلین

private val connectionCallbacks = object : MediaBrowserCompat.ConnectionCallback() {
    override fun onConnected() {

        // Get the token for the MediaSession
        mediaBrowser.sessionToken.also { token ->

            // Create a MediaControllerCompat
            val mediaController = MediaControllerCompat(
                    this@MediaPlayerActivity, // Context
                    token
            )

            // Save the controller
            MediaControllerCompat.setMediaController(this@MediaPlayerActivity, mediaController)
        }

        // Finish building the UI
        buildTransportControls()
    }

    override fun onConnectionSuspended() {
        // The Service has crashed. Disable transport controls until it automatically reconnects
    }

    override fun onConnectionFailed() {
        // The Service has refused our connection
    }
}

جاوا

private final MediaBrowserCompat.ConnectionCallback connectionCallbacks =
  new MediaBrowserCompat.ConnectionCallback() {
    @Override
    public void onConnected() {

      // Get the token for the MediaSession
      MediaSessionCompat.Token token = mediaBrowser.getSessionToken();

      // Create a MediaControllerCompat
      MediaControllerCompat mediaController =
        new MediaControllerCompat(MediaPlayerActivity.this, // Context
        token);

      // Save the controller
      MediaControllerCompat.setMediaController(MediaPlayerActivity.this, mediaController);

      // Finish building the UI
      buildTransportControls();
    }

    @Override
    public void onConnectionSuspended() {
      // The Service has crashed. Disable transport controls until it automatically reconnects
    }

    @Override
    public void onConnectionFailed() {
      // The Service has refused our connection
    }
  };

رابط کاربری‌تان را به کنترل‌کننده رسانه متصل کنید

در کد نمونه ConnectionCallback بالا، شامل فراخوانی به buildTransportControls() برای تکمیل واسط کاربر شما است. باید onClickListeners را برای عناصر میانای کاربر که پخش‌کننده را کنترل می‌کنند تنظیم کنید. روش MediaControllerCompat.TransportControls مناسب را برای هرکدام انتخاب کنید.

کد شما چیزی شبیه به این خواهد بود، با یک onClickListener برای هر دکمه:

کاتلین

fun buildTransportControls() {
    val mediaController = MediaControllerCompat.getMediaController(this@MediaPlayerActivity)
    // Grab the view for the play/pause button
    playPause = findViewById<ImageView>(R.id.play_pause).apply {
        setOnClickListener {
            // Since this is a play/pause button, you'll need to test the current state
            // and choose the action accordingly

            val pbState = mediaController.playbackState.state
            if (pbState == PlaybackStateCompat.STATE_PLAYING) {
                mediaController.transportControls.pause()
            } else {
                mediaController.transportControls.play()
            }
        }
    }

    // Display the initial state
    val metadata = mediaController.metadata
    val pbState = mediaController.playbackState

    // Register a Callback to stay in sync
    mediaController.registerCallback(controllerCallback)
}

جاوا

void buildTransportControls()
{
  // Grab the view for the play/pause button
  playPause = (ImageView) findViewById(R.id.play_pause);

  // Attach a listener to the button
  playPause.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
      // Since this is a play/pause button, you'll need to test the current state
      // and choose the action accordingly

      int pbState = MediaControllerCompat.getMediaController(MediaPlayerActivity.this).getPlaybackState().getState();
      if (pbState == PlaybackStateCompat.STATE_PLAYING) {
        MediaControllerCompat.getMediaController(MediaPlayerActivity.this).getTransportControls().pause();
      } else {
        MediaControllerCompat.getMediaController(MediaPlayerActivity.this).getTransportControls().play();
      }
  });

  MediaControllerCompat mediaController = MediaControllerCompat.getMediaController(MediaPlayerActivity.this);

  // Display the initial state
  MediaMetadataCompat metadata = mediaController.getMetadata();
  PlaybackStateCompat pbState = mediaController.getPlaybackState();

  // Register a Callback to stay in sync
  mediaController.registerCallback(controllerCallback);
}
}

روش‌های TransportControls تماس‌های برگشتی را به جلسه رسانه سرویس شما ارسال می‌کنند. مطمئن شوید که برای هر کنترل، روش MediaSessionCompat.Callback متناظر را تعریف کرده‌اید.

با جلسه رسانه همگام بمانید

رابط کاربری باید وضعیت فعلی جلسه رسانه را، همان‌طور که PlaybackState و Metadata آن شرح می‌دهد، نمایش دهد. وقتی کنترل‌های انتقال را ایجاد می‌کنید، می‌توانید وضعیت فعلی جلسه را دریافت کنید، آن را در میانای کاربر خود نمایش دهید، و کنترل‌های انتقال را براساس وضعیت و کنش‌های دردسترس آن فعال و غیرفعال کنید.

برای دریافت فراخوانی‌های برگشتی از جلسه رسانه هربار که وضعیت یا فراداده آن تغییر می‌کند، یک MediaControllerCompat.Callback با این دو روش تعریف کنید:

کاتلین

private var controllerCallback = object : MediaControllerCompat.Callback() {

    override fun onMetadataChanged(metadata: MediaMetadataCompat?) {}

    override fun onPlaybackStateChanged(state: PlaybackStateCompat?) {}
}

جاوا

MediaControllerCompat.Callback controllerCallback =
  new MediaControllerCompat.Callback() {
    @Override
    public void onMetadataChanged(MediaMetadataCompat metadata) {}

    @Override
    public void onPlaybackStateChanged(PlaybackStateCompat state) {}
  };

هنگام ساختن کنترل‌های انتقال، فراخوانی برگشتی را ثبت کنید (به روش buildTransportControls() مراجعه کنید) و وقتی فعالیت متوقف شد، آن را لغو ثبت کنید (در روش چرخه حیات onStop() فعالیت).

قطع اتصال هنگام ازبین رفتن جلسه رسانه

اگر جلسه رسانه نامعتبر شود، onSessionDestroyed() فراخوانی برگشتی صادر می‌شود. وقتی این اتفاق می‌افتد، جلسه نمی‌تواند دوباره در طول عمر MediaBrowserService فعال شود. اگرچه عملکردهای مربوط به MediaBrowser ممکن است همچنان کار کنند، اما کاربر نمی‌تواند بازپخش را از یک جلسه رسانه تخریب‌شده مشاهده یا کنترل کند، که احتمالاً ارزش برنامه شما را کاهش می‌دهد.

بنابراین، وقتی جلسه ازبین می‌رود، باید با فراخوانی disconnect()، اتصال از MediaBrowserService را قطع کنید. این کار تضمین می‌کند که سرویس مرورگر هیچ کلاینت مقیدی ندارد و می‌تواند توسط سیستم‌عامل ازبین برود. اگر لازم است بعداً دوباره به MediaBrowserService متصل شوید (برای مثال، اگر برنامه شما می‌خواهد اتصال پایداری با برنامه رسانه حفظ کند)، نمونه جدیدی از MediaBrowser ایجاد کنید و از نمونه قدیمی دوباره استفاده نکنید.

تکه‌کد زیر پیاده‌سازی callback را نشان می‌دهد که هنگام ازبین رفتن جلسه رسانه، اتصال را از سرویس مرورگر قطع می‌کند:

کاتلین

private var controllerCallback = object : MediaControllerCompat.Callback() {
    override fun onSessionDestroyed() {
      mediaBrowser.disconnect()
      // maybe schedule a reconnection using a new MediaBrowser instance
    }
}

جاوا

MediaControllerCompat.Callback controllerCallback =
  new MediaControllerCompat.Callback() {
    @Override
    public void onSessionDestroyed() {
      mediaBrowser.disconnect();
      // maybe schedule a reconnection using a new MediaBrowser instance
    }
  };