Mobile Development 13 min read

Seamless Video Playback Across Activities in NetEase Cloud Music: MediaPlayer Rebinding and Mini‑Window Solutions

NetEase Cloud Music’s 8.0 redesign enables seamless video playback across Activities by rebinding MediaPlayer instances to new TextureViews via AIDL, using a process‑pooled player architecture, while also offering simpler alternatives such as animated fake page switches, seek‑based reinitialization, and application‑context view reuse.

NetEase Cloud Music Tech Team
NetEase Cloud Music Tech Team
NetEase Cloud Music Tech Team
Seamless Video Playback Across Activities in NetEase Cloud Music: MediaPlayer Rebinding and Mini‑Window Solutions

In the NetEase Cloud Music 8.0 redesign, a new requirement emerged: when a video is playing, the user should be able to click a "mini‑window" button to collapse the video into a mini playback bar that continues playing across different Activities. The challenge is that the mini bar can appear on any Activity, so the video must transfer seamlessly from one Activity to another.

MediaPlayer Rebinding

Typical video playback uses the system VideoView , which extends SurfaceView and tightly binds a single MediaPlayer to a single surface. For the mini‑window scenario, a MediaPlayer must be able to bind to multiple TextureView instances. The presented framework solves this by placing all MediaPlayer instances in a dedicated Video process pool (active and idle pools). Idle MediaPlayers are reclaimed when the pool exceeds its limit. When a new page starts, its VideoView obtains an idle MediaPlayer from the pool via AIDL, and the MediaPlayer communicates with the TextureView through AIDL as well.

The architecture allows each Activity’s VideoView to replace its bound MediaPlayer without interrupting playback because the actual playback resides in the MediaPlayer, not in the view. When the MediaPlayer is unbound from a TextureView, playback continues; the new Activity simply re‑binds the same MediaPlayer to its own TextureView, instantly displaying the current frame.

Initial motivations for this design were:

Early instability of the in‑house MediaPlayer, requiring isolation in a separate process.

The need for pre‑loading capabilities beyond what a plain VideoView offers.

Reducing memory pressure on the main process.

Reusing player objects to avoid frequent creation.

The rebinding workflow stores a unique MediaPlayer ID (using hashCode() ) and the current resource ID in a global location. When a new Activity launches, its VideoView calls setDataSource , which looks up the existing MediaPlayer in the pool, sends the Surface via AIDL, and re‑binds it to the new TextureView. Because Surface implements Parcelable , it can be transferred across processes.

public class Surface implements Parcelable

Key steps for rebinding:

Provide the new page’s callbacks (e.g., onPrepare , onPause ) to the MediaPlayer.

Re‑bind the Surface; if the SurfaceTexture is not ready, perform the binding later in onSurfaceAvailable .

Drawbacks of this approach include empty surfaces during pause (which can be covered with a placeholder image), audio‑focus conflicts when the previous page still holds the focus, and the risk of player leaks if the MediaPlayer is not properly released.

“Fake” Page‑Switch Scheme

Another, simpler solution used early in NetEase Cloud Music is the “fake” page‑switch. It leverages the fact that a TextureView can be moved and animated like any other view. By placing the video playback fragment at the top of the view hierarchy and animating its position and scale, the transition appears as if the video moved to a new page. This works only within a single Activity.

public class VideoView extends SurfaceView implements MediaPlayerControl, SubtitleController.Anchor {

Seek‑Based Cross‑Activity Scheme

A third approach opens a new player in the target Activity, seeks to the previously saved playback position, and resumes. While this does not provide true seamless playback (activity launch adds latency), it requires minimal changes to existing logic. Important considerations include cache reuse (e.g., using AndroidVideoCache) and key‑frame limitations of the system MediaPlayer, which can be mitigated by using ExoPlayer.

View Cross‑Activity Reuse

Yet another method creates a reusable view using ApplicationContext and manages it via a singleton manager that implements ActivityLifecycleCallbacks . Sample Kotlin code demonstrates adding and removing a mini‑player bar during activity lifecycle events.

object Manager : ActivityLifecycleCallbacks {
    override fun onActivityStarted(activity: Activity) {
        ...
        removePlayerBarFromWindow(activity)
        addPlayerBarToWindow(activity)
    }

    override fun onActivityPaused(activity: Activity) {
        ...
        if (activity.isFinishing && getMiniPlayerBarParentContext() == activity) {
            removePlayerBarFromWindow(activity, true)
        }
    }
}

private fun getPlayerBar(activityBase: Activity): MiniPlayerBar {
    synchronized(this) {
        if (miniPlayerBar == null) {
            miniPlayerBar = MiniPlayerBar(activityBase.applicationContext)
        }
        ...
        return miniPlayerBar!!
    }
}

This approach avoids memory leaks by using the application context, but it was not adopted for the mini‑window feature because the existing pages required different playback views.

Conclusion

The article summarizes several strategies used by NetEase Cloud Music to achieve seamless video playback across Activities, ranging from a sophisticated MediaPlayer‑TextureView isolation with AIDL, to simple animation‑based “fake” page switches, to seek‑based re‑initialization, and finally to cross‑Activity view reuse. Developers should select the solution that best fits their current scenario, balancing complexity, performance, and maintainability.

AndroidActivityvideo playbackTextureViewAIDLMediaPlayerSeamless Playback
NetEase Cloud Music Tech Team
Written by

NetEase Cloud Music Tech Team

Official account of NetEase Cloud Music Tech Team

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.