إنشاء برنامج متصفح للوسائط

لإكمال تصميم العميل/الخادم، يجب إنشاء مكون نشاط يحتوي على رمز واجهة المستخدم وMediaController وMediaBrowser المرتبط بهما.

يؤدي MediaBrowser وظيفتين مهمتين: يتصل بـ MediaBrowserService، وعند توصيله يقوم بإنشاء MediaController لواجهة المستخدم.

ملاحظة: التنفيذ المقترح لبرنامج MediaBrowser هو MediaBrowserCompat، والذي يتم تحديده في مكتبة دعم Media-Compat في هذه الصفحة، يظهر المصطلح "MediaBrowser" يشير إلى مثيل MediaBrowserCompat.

الاتصال بخدمة MediaBrowserService

عندما يتم إنشاء نشاط العميل، يتم ربطه بـ MediaBrowserService. هناك القليل من المصافحة والرقص. عدِّل عمليات الاستدعاء الخاصة بدورة حياة النشاط على النحو التالي:

  • ينشئ onCreate() MediaBrowserCompat. أدخِل اسم MediaBrowserService وMediaBrowserCompat.ConnectionCallback اللذَين حدَّدتهما.
  • يتصل onStart() بـ MediaBrowserService. هنا يأتي دور MediaBrowserCompat.ConnectionCallback. إذا كان الاتصال ناجحًا، ينشئ استدعاء onConnect() وحدة التحكم في الوسائط، ويربطها بجلسة الوسائط، ويربط عناصر تحكم واجهة المستخدم بوحدة التحكم MediaController، ويسجل وحدة التحكم لتلقي استدعاءات من جلسة الوسائط.
  • يعمل onResume() على ضبط البث الصوتي ليتمكّن تطبيقك من الاستجابة لعناصر التحكّم في مستوى الصوت على الجهاز.
  • يؤدي onStop() إلى إلغاء ربط MediaBrowser وإلغاء تسجيل MediaController.Callback عندما يتوقف نشاطك.

Kotlin

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

Java

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

Kotlin

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

Java

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 لكل زر:

Kotlin

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

Java

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 لكل عنصر تحكّم.

البقاء متزامنًا مع جلسة الوسائط

يجب أن تعرض واجهة المستخدم الحالة الحالية لجلسة الوسائط، كما هو موضّح في حالة التشغيل والبيانات الوصفية. عند إنشاء عناصر التحكّم في النقل، يمكنك ضبط الحالة الحالية للجلسة وعرضها في واجهة المستخدِم وتفعيل عناصر التحكّم في النقل وإيقافها استنادًا إلى الحالة والإجراءات المتاحة بها.

لتلقّي استدعاءات من جلسة تشغيل الوسائط في كل مرة تتغير فيها حالتها أو بياناتها الوصفية، حدِّد MediaControllerCompat.Callback، باستخدام هاتين الطريقتين:

Kotlin

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

    override fun onMetadataChanged(metadata: MediaMetadataCompat?) {}

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

Java

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

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

يمكنك تسجيل طلب المعاودة عند إنشاء عناصر التحكّم في النقل (راجِع طريقة buildTransportControls()) وإلغاء التسجيل عند توقف النشاط (وفقًا لطريقة onStop() في النشاط للنشاط).

قطع الاتصال عند إتلاف جلسة الوسائط

إذا أصبحت جلسة الوسائط غير صالحة، فإن onSessionDestroyed() يتم إصدار معاودة الاتصال. وعند حدوث ذلك، لا يمكن أن تصبح الجلسة فعالة مجددًا في مدة بقاء MediaBrowserService. على الرغم من أنّ الدوال المرتبط بـ MediaBrowser قد يستمر في العمل، ولن يتمكن المستخدم من العرض أو التحكم تشغيل من جلسة وسائط تالفة، الأمر الذي من المرجح أن يقلل من قيمة تطبيقك.

ولذلك، عندما يتم إتلاف الجلسة، يجب إلغاء الربط من MediaBrowserService عن طريق الاتصال disconnect() يضمن هذا عدم وجود برامج مرتبطة بخدمة المتصفح يمكن أن تدمرها . إذا كنت بحاجة إلى إعادة الاتصال بـ "MediaBrowserService" في وقت لاحق (على سبيل المثال، إذا إذا كان تطبيقك يريد الحفاظ على اتصال دائم بتطبيق الوسائط)، أنشئ مثيل جديد لـ MediaBrowser بدلاً من إعادة استخدام المثيل القديم.

يوضح مقتطف الرمز التالي عملية تنفيذ لمعاودة الاتصال قطع الاتصال من خدمة المتصفح عند إتلاف جلسة الوسائط:

Kotlin

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

Java

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